how to know if any x or y point is on svg path
Asked Answered
C

2

4

i have a svg path and i want to know if my mouse is on svg path or not, if it is i want to change the cursor to mouse to pointer.

This could have been easily done by adding mouse hover property on path and also with Recognize point(x,y) is inside svg path or outside with this solution.

but there is a twist, I have another transparent layer over it, because of which I cannot have those two solutions.

right now I am making top layer display none and it works fine. but because of this my mouse pointer and the action I do such as moving a certain element on mouse move is slow,

hence i want to find out if there is any other better way without making display equal to none.

please find the fiddle example, I want to change the cursor to pointer when its on mypath element and also want myline should be moving as i move mouse over the layer, i can do display to none on layer for time being, but i noticed on firefox, line movement is not that smooth,

https://jsfiddle.net/shyam_bhiogade/9a7zuou2/6/

<svg width="400" height="400">
  <g>
    <path id="mypath" d="M10 200 L200 90 L200 200" fill="transparent" stroke="black" stroke-width="5" />
    <rect class="interactiveArea" width="500" height="500" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0);opacity:0.2" />
    <line id="myline" x1="20" y1="0" x2="20" y2="400" stroke-width="2" stroke="black" />
  </g>
</svg>
Crossman answered 8/6, 2017 at 5:35 Comment(7)
make the transparent layer pointer-events: noneCountryside
that will not work..because i need mouse move event on the transparent layer.on mouse move, i move an elment along the mouse, also if mouse is on underlying path, i want to change the cursor to pointerCrossman
create a minimal reproducible example and add it to the question.Countryside
Created the exampleCrossman
SVGGeometryElement.isPointInStroke() is only implemented in Chrome so far. Firefox, haven't found anything on Edge.Sunroom
i need the same but it should support all the browser. do you find the implementation for it anywhereCrossman
found the solution.Crossman
C
3

I have used the solution given at https://bl.ocks.org/mbostock/8027637 , it returns the distance of x and y point from the path, if the distance is less than 1px or width of the stroke, I consider that x and y point is on the path.

   function closestPoint(pathNode, point) {
  var pathLength = pathNode.getTotalLength(),
      precision = 8,
      best,
      bestLength,
      bestDistance = Infinity;

  // linear scan for coarse approximation
  for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
    if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
      best = scan, bestLength = scanLength, bestDistance = scanDistance;
    }
  }

  // binary search for precise estimate
  precision /= 2;
  while (precision > 0.5) {
    var before,
        after,
        beforeLength,
        afterLength,
        beforeDistance,
        afterDistance;
    if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
      best = before, bestLength = beforeLength, bestDistance = beforeDistance;
    } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
      best = after, bestLength = afterLength, bestDistance = afterDistance;
    } else {
      precision /= 2;
    }
  }

  best = [best.x, best.y];
  best.distance = Math.sqrt(bestDistance);
  return best;

  function distance2(p) {
    var dx = p.x - point[0],
        dy = p.y - point[1];
    return dx * dx + dy * dy;
  }
}
Crossman answered 14/6, 2017 at 20:40 Comment(0)
K
3

The SVGGeometryElement.isPointInFill() method determines whether a given point is within the fill shape of an element. Normal hit testing rules apply; the value of the pointer-events property on the element determines whether a point is considered to be within the fill. The point argument is interpreted as a point in the local coordinate system of the element.

var myPath = document.getElementById("mypath");
var txt = document.getElementById("txt");
var svg = document.getElementsByTagName("svg")[0];

svg.addEventListener("mousemove", function(event) {
  var mouseX = event.clientX;
  var mouseY = event.clientY;  
  
  var point = svg.createSVGPoint();
  point.x = event.clientX;
  point.y = event.clientY;  
  point=point.matrixTransform(svg.getScreenCTM().inverse());
  
  var inShape=myPath.isPointInFill( point ); 
  txt.innerText=inShape+" x:"+point.x+" y:"+point.y;
});
<svg width="300" height="200" style="border:1px solid black">
  <g>
    <path id="mypath" d="M118 62C118 62 118 62 119 62 135 62 152 62 168 62 168 62 168 63 168 63 168 69 168 74 169 79 172 80 174 80 177 81 191 85 200 94 204 109 206 114 205 120 204 126 199 139 190 148 176 152 169 153 162 153 156 151 142 147 133 138 129 124 129 122 129 121 128 120 128 120 128 120 127 120 122 120 117 120 112 119 112 100 112 81 113 62 113 62 113 62 113 62 115 62 116 62 118 62" fill="red" stroke="black" stroke-width="2" />
  </g>
</svg>
<p>Move Mouse Over Shape <span id="txt" style="font-weight:bold"></span> </p>
Kassandrakassaraba answered 10/7, 2023 at 16:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.