Search code examples
javascriptperformancegoogle-chromesvg

I have a problem with Chrome's version of SVGGeometryElement.isPointInFill() (works in Firefox)


https://jsfiddle.net/awebnoyz/

I need to check for a few thousand paths per second if a point lies within the area. path.isPointInFill(point) does the trick in Firefox, while Chrome returns false.

I just want to do the check without drawing anything, but chrome only seems to work when the elements are actually added to the document. With appending a path, it takes roughly 100x the time.

Any suggestions?

const sPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
sPath.setAttribute('d', "M0 0 L10 0 L10 10 L0 10 Z");
const sPoint = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGPoint();
sPoint.x = 5;
sPoint.y = 5;

console.log("virtual:" + sPath.isPointInFill(sPoint));
//chrome:false, firefox:true


//now with actually adding an svg and the path to the document, both return true
svg = document.documentElement.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"))
svg.appendChild(sPath);
console.log("appended:" + sPath.isPointInFill(sPoint));
svg.removeChild(sPath);

I am currently out of ideas and using a ray cast instead, which "only" takes 10x time :)


Solution

  • Chrome does support setting the d attribute through CSS, so it makes sense that they don't support this method on elements that are not in the DOM and thus on which all the CSS rules can't be computed.

    For what you wish, you can use the Path2D(svgString) constructor along with the canvas 2D isPointInPath() method:

    const ctx = document.createElement("canvas").getContext("2d");
    const path = new Path2D("M0 0 L10 0 L10 10 L0 10 Z");
    const pt = { x: 5, y: 5 }
    console.log(ctx.isPointInPath(path, pt.x, pt.y));