Konva – A workaround for inaccurate Path measuring

Long story short, Konvas path measuring for Path.getLength() and Path.getPointAtLength() methods are broken. The math involved is very complex and its not surprising that there are bugs. But also there’s a simple and higher performance workaround so on balance its not so bad Lets take a look….

Paths can be complex – whether they are route lines on a map, or whatever, they can be constructed of a scary amount of move-to, line-to, Beziers, arcs, etc. Konva supports a subset of SVG path commands and does a good job of drawing them.

Generically, the getPointAtLength() function is intended to be used with the getLength() function. Path.getLength() will give you the total length of the path. You can then chop this up into shorter lengths to get the point on the canvas where each of those lengths end.

For example, if you are drawing movie theatre seating for a reservation app – you need to draw a bunch of seat shapes on a gentle curve. Let’s say on the front row you have to place 10 seats. If you draw the curve as a path you could then get the points at 10 equi-distant positions along the path using

let total = path.getLength();

for (let i = 0; i < 10, i++){

console.log('Seat position ' + i + ' = ' + path.getPointAtLength(i * total / 10))

}

So, Path.getLength() and getPointAtLength() are useful when working with paths – so what’s the workaround to get correct values ?

SVG to the rescue

Browsers have a built-in SVG feature set. Path is a staple of SVG. So we can get the SVG engine to do the math and give us a more accurate getPointAtLength() result.

Here’s a function you can cut & paste to do that job.

function getPosAtLengthPercent(pathData, percent){
  
  // Create an <SVG:path> element to get the path length
  // and the various points at a given distance
  const pathEle = document.createElementNS("http://www.w3.org/2000/svg", "path");

  pathEle.setAttribute("d", pathData);
  const totalLength = pathEle.getTotalLength();
  const distance = totalLength * percent / 100 
  return pathEle.getPointAtLength(distance)
 
}

It should be clear but just in case, what this function does is to create an SVG element, but crucially this is NOT added to the DOM. We set the path data into the SVG path, then get the total path length. Using the input percent parameter, we then compute the distance along the path that this percentage represents, and finally get the position at that point and return it.

Summary

We’ve learned that Konva’s built-in path measuring math is inaccurate, and seen a simple and high-performance workaround.

Thanks for reading.

VW March 2023.

Photo credit Matt Duncan

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: