add mouse event to svg , detect grid hover

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



add mouse event to svg <pattern>, detect grid hover



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.


<pattern>



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>



Fiddle to play with





If you use one rect element for each of the smaller square, then you can attach just one mouse over listener to the group element and find out which is being hovered via event.target. But I am not sure if you like this as you said you are likely to need thousands of squares.
– Wang Sheng
Aug 11 at 1:39


rect


event.target




2 Answers
2



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/





Yes, using a mouse position is not a complicated problem for the scope of this question. However, this is an interactive svg. I've already written the controls to let a user zoom and pan around the svg. The reason why I was hoping to not use mouse coordinates is because when a user pans / zooms the writing location for the new rect is not in the correct place.
– John Ruddell
Aug 13 at 17:37





The common way to implement zoom and pan is by manipulating the viewBox. If you are doing it that way, then my code should work fine.
– Paul LeBeau
Aug 13 at 17:58


viewBox



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>


<pattern>


<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


<svg>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS