简体   繁体   中英

d3 javascript, get distance between two points in an svg path

I have a set of points through which I have drawn a path.

let path=svg.append("path").attr("id","path")
        .data([points])
        .attr("d", d3.line()
        .curve(d3.curveCatmullRom));

I now want to get the distance of the path between the points so that I can break it into segments. I have tried incrementing the distance and checking if the points (rounded off to 5) match with that of the initial set of points and thereby getting the distance whenever there is a match. I then save the points until there as a list.

Here, xyArray has the list of points to which I append d and the list seg as well.

function distanceBetween2Points(path, xyArray) {
    let distance = 0;
    xyArray.forEach(function(d,i)
    {
        let flag=1;
        seg=[];

        while(flag)
            {let pt=path.getPointAtLength(distance);
            if(round5(pt.x)==round5(d.x) && round5(pt.y)==round5(d.y))
                {console.log("d",i);
                d.d=distance;
                d.seg=seg;
                flag=0;
                break;}
            seg.push([pt.x,pt.y]);
            distance++;}
        return 0;
    });
}

It sometimes works (even though not accurately) but sometimes does not, depending on the data. Is there a better way to get the distance?

This is a demo using vanilla javascript not d3 but I hope you'll find it useful.

The function getLengthForPoint(p,thePath) is calculating the distance on the path for a given point p. I'm setting a variable let precision = 100; . Depending on the length of the path you may want to change this value to something else.

Also keep in mind that a path can pass through the same point multiple times. This can be tricky and can give you an error.

Also as you may know you will get the approximated distance to a point. In this example the point p1 = {x:93.5,y:60} . The point at the calculated length has this coords: {x:93.94386291503906,y: 59.063079833984375}

 // some points on the path let p1 = {x:93.5,y:60} let p2 = {x:165,y:106} //the total length of the path let pathLength = thePath.getTotalLength(); let precision = 100; let division = pathLength / precision; function getLengthForPoint(p,thePath){ let theRecord = pathLength; let theSegment; for (let i = 0; i < precision; i++) { // get a point on the path for thia distance let _p = thePath.getPointAtLength(i * division); // get the distance between the new point _p and the point p let theDistance = dist(_p, p); if (theDistance < theRecord) { // if the distance is smaller than the record set the new record theRecord = theDistance; theSegment = i; } } return(theSegment * division); } let theDistanceOnThePath = getLengthForPoint(p1,thePath); //if you calculate the coords of a point at the calculated distance you'll see that is very near the point console.log(thePath.getPointAtLength(theDistanceOnThePath)); let theDistanceBetween2PointsOnThePath = getLengthForPoint(p2,thePath) - getLengthForPoint(p1,thePath); // a helper function to measure the distance between 2 points function dist(p1, p2) { let dx = p2.x - p1.x; let dy = p2.y - p1.y; return Math.sqrt(dx * dx + dy * dy); }
 svg{border:solid}
 <svg viewBox="0 10 340 120"> <path id="thePath" fill="none" stroke="black" d="M10, 24Q10,24,40,67Q70,110,93.5,60Q117,10,123.5,76Q130,142,165,106Q200,70,235,106.5Q270,143, 320,24"></path> <circle cx="93.5" cy="60" r="2" fill="red"/> <circle cx="165" cy="106" r="2" fill="red"/> </svg>

To get the distance between 2 points on the path you can do:

let theDistanceBetween2PointsOnThePath = getLengthForPoint(p2,thePath) - getLengthForPoint(p1,thePath);

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