How do I track the position of a moving svg element in relationship to a fixed svg element?

StackOverflow https://stackoverflow.com/questions/23522654

  •  17-07-2023
  •  | 
  •  

سؤال

I am working on a project that moves elements of an svg file up and down across a horizontal line. I want to track the position of the moving element in relation to the fixed line. Both elements are within the same svg. I tried using

getBoundingClientRect().top

However, this does not provide a good solution as the coordinates produced by the getBoundingClientRect() function change based on the size, position, and zoom, of the viewport. It is not the same for every device in every situation. I need to be able to know when a specific path is a certain distance above or below a fixed line. I'm using setAttribute('transform','translate()) on the containing group to move a group of objects in my project. I need to know the position of an individual object within my group in relation to a fixed line not in my group.

<svg version="1.1" id="ex1-3rds-quarter-s" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
 y="0px" width="323.333px" height="55.333px" viewBox="0 0 323.333 55.333" enable-background="new 0 0 323.333 55.333"
 xml:space="preserve">
  <g id="ledgerlines">
    <line id="MidCLine1" fill="none" stroke="#000000" stroke-width="0.75" stroke-miterlimit="10" x1="48.09" y1="41.694" x2="57.924" y2="41.694"/>
  </g>
  <g id="note1">
    <path class="root" d="M54.113,38.945c1.116,0,2.172,0.578,2.172,1.813c0,1.435-1.116,2.411-2.052,2.969c-0.717,0.418-1.514,0.717-2.331,0.717
            c-1.116,0-2.172-0.578-2.172-1.813c0-1.435,1.116-2.411,2.052-2.969C52.499,39.244,53.296,38.945,54.113,38.945z"/>
    <path d="M54.113,33.963c1.116,0,2.172,0.578,2.172,1.813c0,1.435-1.116,2.411-2.052,2.969c-0.717,0.418-1.514,0.717-2.331,0.717
            c-1.116,0-2.172-0.578-2.172-1.813c0-1.435,1.116-2.411,2.052-2.969C52.499,34.262,53.296,33.963,54.113,33.963z"/>
  </g>
</svg>

Is there a way to track the position of the path without using the getBoundingClientRect() function?

Thanks, --christopher

هل كانت مفيدة؟

المحلول

Try placing your path in an svg 'wrapper/empty' element. Then use getBBox() for the wrapper. This will provide x,y values used to set/read the path's translations.

EDIT: I have included an example below that can move rects between reference lines. This works even when the rect has been previously transformed. This uses a single SVG Wrapper. Note: If you are only going to transform your element a single time, then you do not have to use the matrix transform on the bbx, bby values. they can be used directly.

<!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
        <title>SVG Wrapper</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        </head>
        <body style='font-family:arial'>
            <center>
            <h4>SVG Wrapper</h4>
            <div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
           Translate rects to line via SVG Wrapper. Can translate between lines
            </div>
            <div id="svgDiv" style='background-color:gainsboro;width:400px;height:400px;'>
<svg id="mySVG" width="400" height="400">
<line id=refLine1 stroke='blue' stroke-width='2' x1=20 y1=40 x2=380 y2=40 />
<line id=refLine2 stroke='maroon' stroke-width='2' x1=20 y1=100 x2=380 y2=100 />
<g id=rectG>
<rect id=redRect fill=red x=60 y=200 width=100 height=50 />
<rect id=greenRect fill=lime x=260 y=320 width=100 height=50 />
</g>
<svg id=Wrapper />
</svg>
            </div>
<center>
<button onClick=moveToLine(refLine1,redRect)>Move Red Rect to <span style=color:blue>Line 1</span></button>
<button onClick=moveToLine(refLine1,greenRect)>Move Green Rect to <span style=color:blue>Line 1</span></button>
<br />
<button onClick=moveToLine(refLine2,redRect)>Move Red Rect to <span style=color:maroon>Line 2</span></button>
<button onClick=moveToLine(refLine2,greenRect)>Move Green Rect to <span style=color:maroon>Line 2</span></button>
</center>
            <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>
            <div id='browserDiv' style='padding:5px;position:absolute;top:5px;left:5px;background-color:gainsboro;'>OK in:IE11/CH32/FF28<br /></div>
<script id=myScript>
function moveToLine(refLine,rect)
{
    //---move rect to this location at line---
    var targetY=refLine.y1.baseVal.value
    var targetX=rect.x.baseVal.value
    Wrapper.appendChild(rect)
    var bb=Wrapper.getBBox()
    //---return rect to its <g>---
    rectG.appendChild(rect)
    var bbx=bb.x
    var bby=bb.y

    //---bind wrapper x,y to rect's current transform--
    var pnt = mySVG.createSVGPoint();
    pnt.x = bbx;
    pnt.y = bby;
    var sCTM = rect.getCTM();
    PNT = pnt.matrixTransform(sCTM.inverse());
    //---translate rect's x,y to target---
    var transX=targetX-PNT.x
    var transY=targetY-PNT.y

    rect.setAttribute("transform","translate("+transX+" "+transY+")")

    svgSourceValue.value=svgDiv.innerHTML
}

</script>
            <script>
            document.addEventListener("onload",init(),false)
            function init()
            {
                svgSourceValue.value=svgDiv.innerHTML
                jsValue.value=myScript.text
            }
            </script>
        </body>
    </html>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top