Custom Elements: Extend SVG - Real coordinates on mouse events

In my Editor-App I use SVG for making PLC logic drawings + HMI and need the real user coordinates (not screen clientX/clientY) when placing and moving shapes around my SVG drawing.
The user coordinates in SVG space is normally not part of the mouse events.

This might be a dumb question, but would it be possible to extend the ‘svg’ tag to include real SVG coordinates
with the mouse events ? (by using Custom Elements)
So that in Elm you could simply do something like:

svg [ onMouseOverWithCoordinates MyMsg ] [ ]

Today I use ports, works fine. But maybe a Custom Element might be nicer to work with.
If an extended svg tag like this was included/used by elm/svg, it would definitely be nicer :slight_smile:

Today’s port solution is something like this:

let svg = main.getElementsByTagName('svg')[0]
point = svg.createSVGPoint()
        point.x = evt.clientX
        point.y = evt.clientY
        position = point.matrixTransform(svg.getScreenCTM().inverse())
        app.ports.svgMouseCoordinates.send({
            x: position.x,
            y: position.y
        })
1 Like

You don’t need Custom Elements for this. You can use a Mutation Observer and look for elements with certain characteristics and bind events to those elements that extracts the information you need and publish it as a custom event that you would then capture in Elm.

4 Likes

Out of curiosity (and would probably help others provide solutions) could you make a small Ellie (https://ellie-app.com/) with an example svg containing one or two PLC drawings? You can easily decode the position of mouse events (client, offset), so if your SVG does not have too deeply nested transformations, there might be simple solutions.

Thanks, I did not know that I could fire Custom events and listen to them in Elm.

Using the same logic as for the port, but now listening for Events.on “mousemoveWithCoordinates” in Elm:

        let svg = document.getElementsByTagName('svg')[0]
        if (svg) {
            let point, position
            svg.addEventListener('mousemove', (e) => {
                point = svg.createSVGPoint()
                point.x = e.clientX
                point.y = e.clientY
                position = point.matrixTransform(svg.getScreenCTM().inverse())

                let event = new CustomEvent("mousemoveWithCoordinates", { detail: position })
                svg.dispatchEvent(event)
            })
        }
2 Likes

Hi, thanks for reply.
Any drawing will require multiple files to render.
You suggest calculating px to user coordinates based on SVG element size and viewBox ?
I will try this, maybe it can be solved without any JavaScript at all.
I have 0 nested SVG elements, so might be a very simple solution. :grinning:

I have an application where I’m currently using ports to get the local coordinates within an svg element also. Using @pdamoc’s suggestion of a Mutation Observer (which I didn’t know existed until now), I made an example on Ellie of how to fire a custom event on svg elements that will return the local coordinates. Clicking around in the box will get the local coordinates and move the circle marker.

4 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.