简体   繁体   中英

SVG getTotalLength() won't return the right size for non-scaling-stroke - get SVG scale

I'm using javascript to get a path length and apply half of it to the stroke-DashArray . My problem is that I use vector-effect="non-scaling-stroke" so that no mather the scale, it allways keeps a stroke-width:2px; The non-scaling seems to affect every part of the stroke properties including the DashArray so I need to get the scale of the svg to then scale path.getTotalLength(); .

Is there a way to get the SVG computed scale using javascript to use as multiplier of the path lenght?

I made a codepen.io to demonstrate the issue. Just resize the view port to see the stroke change.

Would just like to draw more attention to Sam's comment/answer above, which worked for me!

path.getBoundingClientRect().width/path.getBBox().width will return a scale number.

You can then multiply the scale by the length of the path with path.getTotalLength() * scale;

I think that you must divide the viewbox size / SVG width

 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <button onclick="dashAni(myPath, 50, 3500)">start</button> <svg id="mySVG" width="200" height="200" viewBox="0 0 500 500"> <path vector-effect="non-scaling-stroke" id="myPath" d="M 50,250 c 0 -100 150 -100 200 0 c 50 100 200 100 200 0 c -0 -100 -150 -100 -200 0 c -50 100 -200 100 -200 0 z" stroke="#eee" stroke-width="5" fill="none" /> </svg> <script> var dashAni = function(path, length, duration){ var dashPath = path.cloneNode(true); mySVG.appendChild(dashPath); var pathLen=path.getTotalLength()/2.5; var aktPos=0 var sumSteps = duration / (1000/60) // 60 pics per second var step=0; var pathAnim; dashPath.setAttribute('stroke-dasharray', length + ' ' + (pathLen - length)); dashPath.setAttribute('stroke', "red"); dashPath.setAttribute('stroke-dashoffset', aktPos); var anim=function(){ aktPos = pathLen/sumSteps*step*-1; //aktLen = easeInOutQuad(step/sumSteps)*len; dashPath.setAttribute('stroke-dasharray', length + ' ' + pathLen); dashPath.setAttribute('stroke-dashoffset', aktPos); if (step <= (sumSteps)){ step++; pathAnim = setTimeout(anim, 1000/60) //1000/60 pics/second } else { mySVG.removeChild(dashPath); clearTimeout(pathAnim); } } anim(); } </script> </body> </html>

For anyone struggling with this now, the scaling solution suggested above wasn't working for me, which I think is because I'm not sizing my svg proportionally (it is set to fill the browser window). I discovered a straightforward solution for my use case with boundingClientRect and the pythagorean theorem though:

let boundingClient=el.getBoundingClientRect();
let pathLength=Math.sqrt(boundingClient.width**2 + boundingClient.height**2);

This gets it pretty spot-on for me, and it just needs to be recalculated whenever the window resizes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM