-
-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pointer events to interactive image #2745
Conversation
To kind of give more background as to why I'd like this (perhaps even as just an example or to keep this as a dead PR if need be) is because I thought it'd be interesting (and thus useful) if we could determine when the mouse enters an svg. Seeing if the mouse coordinates are over an SVG is almost trivial, however determining if the mouse enters / leaves is less so trivial, even less so when you have hundreds of these SVG shapes. This system allows you to do something super simple to access that, as can be determined in this video. Watch as my mouse moves over the shape it can determine if the mouse enters / leaves, if the click is down or up, etc. In case you were wondering, aside from the code provided in this commit, below is all the code necessary to run this example. I'd appreciate it if you would consider it. 😄 from nicegui import ui
class Image:
def __init__(self, image_url):
self.image_url = image_url
self.content = """
<circle transform="scale(1, 1) rotate(0,0,0) translate(0, 0) skewX(1) skewY(1)" cx="100" cy="50" r="50" fill="black" fill-opacity="1" stroke="black" stroke="black" stroke-width="1" pointer-events="all"/>
"""
self.image = ui.interactive_image(image_url, on_pointer = self.emit_events)
self.image.style("border: 1px solid black;")
self.image.content = self.content
def emit_events(self, event):
if event.type == "mousemove":
print("Mouse Move")
elif event.type == "mousedown":
print("Mouse Down")
elif event.type == "mouseup":
print("Mouse Up")
elif event.type == "mouseleave":
print("Mouse Leave")
elif event.type == "mouseenter":
print("Mouse Enter")
image = Image("result.svg")
ui.run() |
Thanks for the pull request @frankvp11. I like the general idea but wonder if the events are not better added in the same style as in #2716... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @frankvp11,
Thanks for the pull request. If I understand correctly, you basically want to receive events from the <svg>
element instead of the <img>
element.
In its current form, I see two major flaws in the implementation:
- The code is very repetitive.
- It doesn't allow the users to specify which event they are interested in. It simply sends all events to the server, causing quite some traffic, even if SVG events are not needed at all.
I agree with @rodja that the approach from #2716 should work nicely. This way the user should be able to register SVG events like this:
ui.interactive_image(...).on('svg:mouseenter', ...)
I'm trying to make it so that this is possible, however I am having trouble determining how we can access the SVG events in this way. |
Great! I added the event listener registration, but somehow the server doesn't receive the event: ui.interactive_image(content='''
<circle cx="125" cy="80" r="50" fill="black" pointer-events="all" />
<circle cx="250" cy="80" r="50" fill="black" pointer-events="all" />
''', size=(800, 600), cross=True).classes('w-64 bg-blue-50').on('svg:pointerenter', lambda e: print(e)) The |
I figured that out. You were sending it as something similar to this: |
Are there any more changes required ? |
Actually I've noticed on bug in testing this. Edit: I think there might be a better way to get what I'm after. I was looking around and noticed that if you do this in Javascript, you can actually access the events of the raw SVG element itself, which makes me wonder if I can create a mixin for the SVG's Edit 2: |
Thanks for looking into it, @frankvp11. Let me know when it's a good time for a final review. 🙂 |
Alright. I'm bringing / have brought this to the discord so if you wanted to follow it, as it'd allow me to expand more on my thinking and ideas for this / current issues https://discord.com/channels/1089836369431498784/1220463393060950016/1220730161058680862 |
In terms of functionality, this PR should be complete. It allows the user to access the SVG events, which was the intention from the start. I think it would be good to start the final review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @frankvp11, while working on the demo for the documentation, I noticed that the image coordinates are incorrect. It seems like the coordinates change depending on the browser's zoom level. And there's an obvious typo using event.x
for x and y. Can you, please, have another look?
I noticed the typo earlier this morning, I haven't had a chance to getting around to fixing that yet. I didn't however notice that the coordinates are/were wrong. I believe using just the offsetX and offsetY should work, but I'll double check and get back to you with a new commit soon 👍 |
If you test the version before the commit where I "removed debug statements", you should see that it appears to be working properly. In that version, it would place a red circle in the image_x and image_y position that you clicked in. Upon testing it regularly (by reading the notify box) it appears to be working on max and min zoom. |
Are there any more steps necessary for merging this PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just added the element_id
to the event arguments so that you can identify which SVG element has been interacted with.
Apart from that I only wonder how we could keep the crosshair visible while hovering nested SVG elements. I guess it disappears because the image registers a "leave" event which is handled in onCrossEvents
. On the other hand this could as well be a feature: It combines image interactions with a crosshair and SVG interactions without. Let's leave it like this and - if necessary - improve on it later.
The reason that I am submitting this pull request is that because I found a need to have access to the events that arise from what I recently learned are pointers.
Basically, with the on_mouse you can access the position that the user clicked on. However, given my project https://github.com/frankvp11/ModelMaker, I have been trying to access what* they are clicking on when they click. I have yet to test it with my project, but from what I can tell, it doesn't break the functionality of on_mouse, and would certainly be a nice feature for those of us (albeit very few) working with the SVG side of things with the interactive images.
This can also be considered as an example for how the user can simply use SVG's inside the interactive image, since from a discord discussion we determined it wasn't too clear.
If there are any improvements needed, please let me know.
If you don't like the idea, or have perhaps a better way of implementing this (or getting my project to work lol) it'd be much appreciated.
When testing this, go to this route: documentation/interactive_image#svg_content and place your mouse over one of the two black circles. I apologize in advance for the immense amount of spamming that pops up - this is due to the amount of events that arise. I couldn't exactly think of a better way to deal with this while still showing off the feature.