Reputation: 25842
I have a bit of a complicated question. I'm trying to render a grid via svg and then add event listeners to the grid. Currently I'm rendering the grid via a <pattern>
element. I'm open to other avenues for rendering the grid, but it needs to be scalable / performant, as this grid could easily be 10's of thousands of squares. Think of it like a floorplan or a blueprint.
What I want: I'd like to be able to attach an event listener to every square of the grid.
What I've done: I looked up the svg docs, tried a bunch of different things (like onclick handlers, svg attributes like pointer-events... etc) but with no luck. I can probably make it work with mouse client coordinates, however I'd like to avoid using this method if possible as this svg will have zoom and pan functionality.. which can make transforming coordinates a pain.
Base svg code (simplified for this question):
<svg viewBox="0 0 100 100">
<g className="view-control">
<defs>
<pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" strokeWidth="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
</g>
</svg>
Upvotes: 2
Views: 1555
Reputation: 29784
If you make the grid a <pattern>
then you will not be able to register any mouse events on the pattern. The patterns hitbox will cover the whole <rect>
I recommend calculating the coordinates of the squares yourself based on the size of the <svg>
, the viewBox and the spacing of the grid. Attach any mouse events to the SVG element
Upvotes: 1
Reputation: 101800
I'm not sure what your objection to "mouse client coordinates" is, but it is very simple to do, and meets your requirement.
Add a click handler to the grid rectangle. I've used a click handler for this demo. But if you want to base it on hover, you could use the mousemove event instead.
<rect width="200%" height="200%" fill="url(#grid)" onClick={(e) => handleClick(e)}/>
function handleClick(e) {
var pos = getSVGPosition(e);
createRectAt(pos);
}
The function to convert the mouse coords to svg coords looks like this:
function getSVGPosition(e) {
var svg = e.nativeEvent.target.ownerSVGElement;
var pt = svg.createSVGPoint();
pt.x = e.nativeEvent.clientX;
pt.y = e.nativeEvent.clientY;
pt = pt.matrixTransform(svg.getScreenCTM().inverse());
return {svg: svg, x: pt.x, y: pt.y};
}
And then for the purposes of the demo, I create a square at the relevant grid position
function createRectAt(pos) {
var rect = document.createElementNS(pos.svg.namespaceURI, "rect");
rect.setAttribute("x", Math.floor(pos.x / 10) * 10);
rect.setAttribute("y", Math.floor(pos.y / 10) * 10);
rect.setAttribute("width", 10);
rect.setAttribute("height", 10);
rect.setAttribute("fill", "green");
pos.svg.appendChild(rect);
}
https://jsfiddle.net/tp530748/31/
Upvotes: 3