svg - math—convert world transform to local transform -
i getting kind of headache… using jsbox2d.js 2d game, based on svg graphics. »connect« b2d-body svg element, works debug draw, not graphics in scene.
setup:
there svg, including arbitrary nested structure of groups , shapes. each 1 have transformations, each element resides in own coordinate space.
aside there box2d simulation , bodies represent element in svg.
i apply b2body's transform svg-element represents, animation looks correctly. working debug draw, using code:
// links array [[b2body, svgelement],…] (var = 0; < links.length; i++) { var t = links[i][0].gettransform(); //tiny helper function taking values , //setting element // transform(element, a,b,c,d,e,f) //|a c e| //|b d f| svghelper.transform(links[i][1], t.q.c, t.q.s, -t.q.s, t.q.c, t.p.x, t.p.y); }
the main difference is, elements used debug draw generated on fly, without transformations, using world coordinates of vertices of b2dshapes.
but graphics scene taken svg graphic created inkscape and, f.i. using groups arm or head of charackter.
how can apply transform of body right on elements? guess need change basis of transform matrix, somehow can't make work.
i have tried this:
var t = body.gettransform(), mtr = svg,createsvgmatrix( t.q.c, t.q.s, -t.q.s, t.q.c, t.p.x, t.p.y), toelement = element.gettransformtoelement(element.ownersvgdocument), toelement_inv = toelement.invert(); mtr = mtr.multiply(toelement); mtr = toelement_inv.multiply(mtr); //applying result
but resulted in wrong result , errors inverting matrix.
thanks in ahead!
i have example below may helpful, , not add headache;) addresses placing elements in different viewports
<!doctype html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>find x,y in transforms & viewports</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"> </head> <body style='padding:10px;font-family:arial'> <center> <h4>find x,y in transforms & viewports</h4> <div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'> elements transformed , reside different viewports. example uses <b>getscreenctm</b> , <b>inverse</b> access x,y values. </div> <table> <tr><td align=left> <b>click on element target.<br /> place black circle<br />so matches target's transformations</b><br /> scenerio:<br /> 1.) svg image inline, contained in div.<br /> 2.) blue rect element contained in <g>.<br /> 3.) <g> element has been transformed.<br /> 4.) maroon rect resides in different viewport.<br /> 5.) orange circle has been transformed.<br /> 6.) move cursor on elements x,y values<br /> 6.) click on element place black circle in viewport or target's transform.<br /> </td> <td align=left> <div id="svgdiv" style='background-color:lightgreen;width:400px;height:400px;'> <svg id="mysvg" width="400" height="400" onmousemove="svgcursor(evt)" onclick="placeblackcircle(evt)" > <circle pointer-events="none" id="blackcircle" r="10" fill="black" /> <circle onmousemove=getxy(evt) onmouseout=clearxy() id="redcircle" cx="120" cy="180" r="40" fill="red" stroke="black" stroke-width="2" /> <circle onmousemove=getxy(evt) onmouseout=clearxy() id="orangecircle" cx="200" cy="200" r="40" fill="orange" stroke="black" stroke-width="2" /> <svg viewbox="0 100 800 800"> <rect onmousemove=getxy(evt) onmouseout=clearxy() id="maroonrect" x="220" y="250" width="60" height="60" fill="maroon" stroke="black" stroke-width="2" /> </svg> <g id="myg" > <rect onmousemove=getxy(evt) onmouseout=clearxy() id="bluerect" x="220" y="250" width="60" height="60" fill="blue" stroke="black" stroke-width="2" /> </g> </svg> </div> </td> <td align=left> <table style='font-family:lucida console'> <tr><td colspan=4><b>html page values:</b></td></tr> <tr style='font-size:110%'> <td align=right>mouse x:</td><td><input style='font-size:120%' type=text id=htmlmousexvalue size=1 /></td> <td><input style='font-size:120%' type=text id=htmlmouseyvalue size=1 /></td><td align=left>:mouse y</td> </tr> <tr><td colspan=4><b>svg image values:</b></td></tr> <tr style='font-size:110%'> <td align=right>svg x:</td> <td><input style='font-size:120%' type=text id=svgxvalue size=1 /></td> <td><input style='font-size:120%' type=text id=svgyvalue size=1 /></td><td align=left>:svg y</td> </tr> <tr><td colspan=4><b>target:<input id=elemidvalue size=10 /></b></td></tr> <tr style='font-size:110%'> <td align=right>client x:</td> <td><input style='font-size:120%' type=text id=clientxvalue size=1 /></td> <td><input style='font-size:120%' type=text id=clientyvalue size=1 /></td><td align=left>:client y</td> </tr> <tr style='font-size:110%'> <td align=right>screen x:</td> <td><input style='font-size:120%' type=text id=screenxvalue size=1 /></td> <td><input style='font-size:120%' type=text id=screenyvalue size=1 /></td><td align=left>:screen y</td> </tr> </table> </td> </tr></table> <br />svg source:<br /> <textarea id=svgsourcevalue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea> <br />javascript:<br /> <textarea id=jsvalue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea> </center> <script id=myscript> //---mouse move--- function getxy(evt) { var target=evt.target elemidvalue.value=target.id var pnt = target.ownersvgelement.createsvgpoint(); pnt.x = evt.clientx; pnt.y = evt.clienty; clientxvalue.value=pnt.x clientyvalue.value=pnt.y //---element's x,y screen transformed/inversevalues--- var sctm = target.getscreenctm(); var pnt = pnt.matrixtransform(sctm.inverse()); screenxvalue.value=pnt.x screenyvalue.value=pnt.y } function placeblackcircle(evt) { var target=evt.target; //---initialize point in respective viewport-- if(target.nearestviewportelement) //--must click on element not svg root-- { var pnt = target.nearestviewportelement.createsvgpoint(); //---client area click point--- pnt.x = evt.clientx; pnt.y = evt.clienty; var sctm = target.getscreenctm(); //---return viewport's pnt.x, pnt.y--- pnt = pnt.matrixtransform(sctm.inverse()); //----place blackdot on top in viewport , locate it--- target.nearestviewportelement.appendchild(blackcircle) blackcircle.setattribute("cx",pnt.x) blackcircle.setattribute("cy",pnt.y) if(target.parentnode.nodename=="g") { target.parentnode.appendchild(blackcircle) } if(target.getattribute("transform")) { var transform=target.getattribute("transform") blackcircle.setattribute("transform",transform) } else blackcircle.removeattribute("transform") } } function clearxy() { elemidvalue.value="" clientxvalue.value="" clientyvalue.value="" screenxvalue.value="" screenyvalue.value="" } //---onload--- function inittransforms() { //---place transforms on elements--- //--- transform orange circle--- var transformrequestobj=mysvg.createsvgtransform() var animtransformlist=orangecircle.transform var transformlist=animtransformlist.baseval //---translate--- transformrequestobj.settranslate(180,-260) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //----scale--- transformrequestobj.setscale(.5,.9) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //----skewy--- transformrequestobj.setskewy(52) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //--init transform on myg--- var transformrequestobj=mysvg.createsvgtransform() var animtransformlist=myg.transform var transformlist=animtransformlist.baseval //---translate--- transformrequestobj.settranslate(-50,-80) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //----skewx--- transformrequestobj.setskewx(15) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //----skewy--- transformrequestobj.setskewy(20) transformlist.appenditem(transformrequestobj) transformlist.consolidate() //---rotate--- transformrequestobj.setrotate(30,200,200) transformlist.appenditem(transformrequestobj) transformlist.consolidate() } document.onmousemove = htmcursor //---'event' html event object--- function htmcursor(event) { var event = event || window.event; mymousex=event.clientx; mymousey=event.clienty; mymousex = mymousex + document.documentelement.scrollleft; mymousey = mymousey + document.documentelement.scrolltop; htmlmousexvalue.value=mymousex htmlmouseyvalue.value=mymousey } //---'evt' svg event object-- function svgcursor(evt) { var rect = svgdiv.getboundingclientrect(); svgxvalue.value=evt.clientx-rect.left svgyvalue.value=evt.clienty-rect.top } </script> <script> document.addeventlistener("onload",init(),false) function init() { inittransforms() svgsourcevalue.value=svgdiv.innerhtml jsvalue.value=myscript.text } </script> </body> </html>
Comments
Post a Comment