Question

Say I have the following SVG:

<g id="g1" transform="translate(100, 250) rotate(90)" >
    <path id="path1" d="M 100,100 c...

Is there a way to get the actual coordinates of the d attribute? Ideally I want some function such as untransform below:

var transform =  $("g1").getAttribute("transform");
var d = $("path1").getAttribute("d");
var dUntransformed = untransform(d, transform);
$("g1").removeAttribute("transform");
$("path1").setAttribute("d", dUntransformed);

The idea is that if I ran this script the resulting image would be identical to the previous image.

The reason I want to do this is because I have an animation that follows this path. However because of the transform the animation is off. And if I add the transform to the animateMotion object the animation is still off. So my thought is to remove the path and put it back exactly where it is. So that I can get the animation to work. (The AnimateMotion is similar to this demo: https://mdn.mozillademos.org/files/3261/animateMotion.svg)

Was it helpful?

Solution

Here is an example to return screen points after tranformations : polygon, path, polyline. The path example does not work or arcs. Also, in some cases relative points may not return. This uses getCTM and matrixTransform. It may be possible to create an array to 'remember' the points at various time lines.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Return Screen Points After Tranformations</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:0px;font-family:arial'>
<center>
<h4>Return Screen Points After Tranformations : polygon, path, polyline</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:10px;'>
In many cases it is meaningful to return certain svg elements(polygon, polyline, and path) to their screen x,y values following transformations. This is accomplished using <b>getCTM</b>, and <b>matrixTransform</b>
Note: Use  vector-effect="non-scaling-stroke" for elements with stroke(*not available in IE).
</div>
<div id="svgDiv" style="background-color:lightgreen;width:500px;height:500px;">
<svg id="mySVG" width="500" height="500">
    <path id="myPath" vector-effect="non-scaling-stroke"  transform="scale(.8)translate(120 50)skewY(15)rotate(-15)" fill="yellow" stroke="black" stroke-width="2"
    d="M50,50 Q-30,100 50,150 100,230 150,150 230,100 150,50 100,-30 50,50"/>
    <polyline vector-effect="non-scaling-stroke"  id="myPolyline" transform="scale(.3)translate(700 620)"  fill="red" stroke="black" stroke-width="3" points="122 60 150 450 500 400" />
    <polygon vector-effect="non-scaling-stroke"  id="myPolygon"  transform="scale(3)translate(122 132)" fill="purple"  stroke="white" stroke-width="3"points="15,0 10.6066,-10.6066 9.18486e-016,-15 -10.6066,-10.6066 -15,-1.83697e-015 -10.6066,10.6066 -2.75545e-015,15 10.6066,10.6066" />
</svg>
</div>
<button onClick=change2Screen()>change to screen values</button>
 <br />SVG Source:<br />
<textarea id=mySVGValue style='font-size:120%;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>
<div id='browserDiv' style='padding:3px;position:absolute;top:5px;left:5px;background-color:gainsboro;'></div>
<script id=myScript>

//--button---
function change2Screen()
{
    screenPolyline(myPolyline)
    screenPolygon(myPolygon)
    screenPath(myPath)
    mySVGValue.value=svgDiv.innerHTML
}
function screenPolyline(myPoly)
{
    var sCTM = myPoly.getCTM()
    var svgRoot = myPoly.ownerSVGElement
    var pointsList = myPoly.points;
    var n = pointsList.numberOfItems;
    for(var m=0;m<n;m++)
    {
        var mySVGPoint = svgRoot.createSVGPoint();
        mySVGPoint.x = pointsList.getItem(m).x
        mySVGPoint.y = pointsList.getItem(m).y
        mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
        pointsList.getItem(m).x=mySVGPointTrans.x
        pointsList.getItem(m).y=mySVGPointTrans.y
    }
    //---force removal of transform--
    myPoly.setAttribute("transform","")
    myPoly.removeAttribute("transform")
}
//---except arc/relative paths---
function screenPath(path)
{
    var sCTM = path.getCTM()
    var svgRoot = path.ownerSVGElement

    var segList=path.pathSegList
    var segs=segList.numberOfItems
    //---change segObj values
    for(var k=0;k<segs;k++)
    {
        var segObj=segList.getItem(k)

        if(segObj.x && segObj.y )
        {
            var mySVGPoint = svgRoot.createSVGPoint();
            mySVGPoint.x = segObj.x
            mySVGPoint.y = segObj.y
            mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
            segObj.x=mySVGPointTrans.x
            segObj.y=mySVGPointTrans.y
        }

        if(segObj.x1 && segObj.y1)
        {
            var mySVGPoint1 = svgRoot.createSVGPoint();
            mySVGPoint1.x = segObj.x1
            mySVGPoint1.y = segObj.y1
            mySVGPointTrans1 = mySVGPoint1.matrixTransform(sCTM)
            segObj.x1=mySVGPointTrans1.x
            segObj.y1=mySVGPointTrans1.y
        }
        if(segObj.x2 && segObj.y2)
        {
            var mySVGPoint2 = svgRoot.createSVGPoint();
            mySVGPoint2.x = segObj.x2
            mySVGPoint2.y = segObj.y2
            mySVGPointTrans2 = mySVGPoint2.matrixTransform(sCTM)
            segObj.x2=mySVGPointTrans2.x
            segObj.y2=mySVGPointTrans2.y
        }
    }
    //---force removal of transform--
    path.setAttribute("transform","")
    path.removeAttribute("transform")
}

//---changes all transformed points to screen points---
function screenPolygon(myPoly)
{
    var sCTM = myPoly.getCTM()
    var svgRoot = myPoly.ownerSVGElement

    var pointsList = myPoly.points;
    var n = pointsList.numberOfItems;
    for(var m=0;m<n;m++)
    {
        var mySVGPoint = svgRoot.createSVGPoint();
        mySVGPoint.x = pointsList.getItem(m).x
        mySVGPoint.y = pointsList.getItem(m).y
        mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
        pointsList.getItem(m).x=mySVGPointTrans.x
        pointsList.getItem(m).y=mySVGPointTrans.y
    }
    //---force removal of transform--
    myPoly.setAttribute("transform","")
}
</script>
<script>
document.addEventListener("onload",init(),false)

function init()
{
  mySVGValue.value=svgDiv.innerHTML
  jsValue.value=myScript.text
}
</script>
</body>

</html>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top