Infer user click position in img using LiveView

Hello,
I’m struggling to code a LiveView that will return the exact position user clicks into an img HTML element.
My issue is about getting the element DOM naturalwidth and naturalheight.
Even though I set the img width to say 600px, for some reasons I don’t know, in some pages the image is actually displayed as 681px width.
So, when I retrieve the user click offsetX position (from the on-click event), it varies from 0 to 681 range and not from 0 to 600 range as expected.
That throws my computation off since I base it on 600, not 681 !
I think I could solve the issue by querying the clicked element about its naturalwidth, but I don’t know how to do that. I bet Javascript hook is the right path, but can’t work my head around it.
Any tips are welcome.

My current app.js liveSocket code is

let liveSocket = new LiveSocket("/live", Socket, {
    hooks: Hooks, params: { _csrf_token: csrfToken }, metadata: {
        click: (e, _el) => {
            return {
                offsetX: e.offsetX, offsetY: e.offsetY, clientX: e.clientX,
                clientY: e.clientY, pageX: e.pageX, pageY: e.pageY
            }
        }
    }
})

Thank you
Jean-yves :slight_smile:

_el has clientWidth and clientHeight properties that may be what you’re looking for.

    click: (e, el) => {
      return {
        offsetX: e.offsetX,
        offsetY: e.offsetY,
        clientWidth: el.clientWidth,
        clientHeight: el.clientHeight
      }
    }
2 Likes

Hi, it worked perfectly, thank you !
If I try to understand from your answer I get this : e is about the event and el about the HTML element.
Is this standard to the HTML/Javascript world to have those two data element linked to the click event ? (I could not find relevant Javascript documentation about that).
Anyway, thanks to you I can pursue and will be able to use all events and elements related properties in the future.
A big thank you from France.
Jean-yves :sunglasses:

1 Like

You’re welcome!

And yes, e represents the click event while el represents the element.

The target property of the event object is always a reference to the element the event occurred upon.
source: Introduction to events - Learn web development | MDN

It can be a bit bewildering on the Javascript side, but at a high level events have targets that are often elements. And at a lower level, visually it is something like:

click event => MouseEvent => UIEvent => Event => Event.target <= EventTarget <= Node <= Element

Hello again,
Now I need to get the clientWidth and height of an img before the user clicks it.
I have created a hook

export default {
    mounted() {
        this.pushEvent("img_size", { width: this.el.clientWidth, height: this.el.clientHeight })
    }
}

and attached it to my img element in LiveView
It works great, but I wonder If there is a smarter way to do that with LiveView or Surface-ui ?
Maybe with phx-mounted, but I can’t figure the syntax when using surface-ui.
Plain LiveView syntax would be

<div phx-mounted={this.pushEvent("img_size", { width: this.el.clientWidth, height: this.el.clientHeight })}>

but that does not compile in surface ~F sigil.

It looks like Surface UI uses a different syntax, but it’s unclear if it’ll support DOM patching bindings/directives like phx-mounted, phx-update, phx-remove.

Using the :on-[event] directive

The :on-[event] directive can configure a server event binding by automatically generating the phx-[event] and phx-target attributes in the HTML tag, defining the component itself as the default handler (target). This is the preferred way to use phx events in Surface as it can properly handle properties of type :event.

Available directives are: :on-click, :on-capture-click, :on-blur, :on-focus, :on-change, :on-submit, :on-keydown, :on-keyup, :on-window-focus, :on-window-blur, :on-window-keydown and :on-window-keyup.

source: Using the :on-[event] directive | Surface UI docs