I have a NiceGUI page with an SVG image consisting of two elements (a circle and a square). I need to check which element of this image was clicked when the SVG image is clicked, so that I can handle it.
I want the event "circle clicked" to be triggered when the circle is clicked, and the event "square clicked" to be triggered when the square is clicked. I am trying to implement this through a handler, but I don't know what to write in the handler function. I am attaching the code.
My method 1:
from nicegui import ui
def my_handler(event_args):
print("Button clicked!")
with ui.row():
svg_element = ui.html('''
<svg width="200" height="200" style="border: 1px solid black;">
<circle cx="50" cy="50" r="40" fill="red" class="clickable-circle"/>
<rect x="100" y="10" width="80" height="80" fill="blue" class="clickable-square"/>
</svg>
''')
svg_element.on('click', js_handler='(click) => { console.log(event.target.clickable-circle); }')
ui.run(port = 8082)
My method 2:
from nicegui import ui
def my_handler(event_args):
element = event_args.sender
# ???????
with ui.row():
svg_element = ui.html('''
<svg width="200" height="200" style="border: 1px solid black;">
<circle cx="50" cy="50" r="40" fill="red" class="clickable-circle"/>
<rect x="100" y="10" width="80" height="80" fill="blue" class="clickable-square"/>
</svg>
''')
svg_element.on('click', handler=my_handler)
ui.run(port=8082)
Thank you all for your help.
If you want to use JavaScript
then you have to use the same name event
in
(event) => { console.log(event.target) }
I think you could use it to emit custom event with information what object was clicked
emitEvent(`clicked_${event.tagerg.tagName}`)
and it should send event clicked_circle
or clicked_rect
(and maybe even clicked_svg
) to Python and it can use it to execute function with ui.on()
instead of element_svg.on()
ui.on('clicked_circle', handler=my_handler_for_circle)
ui.on('clicked_rect', handler=my_handler_for_rect)
You may also use it with parameters
ui.on('clicked_circle', handler=lambda event:my_handler(event, "circle"))
ui.on('clicked_rect', handler=lambda event:my_handler(event, "rect"))
Maybe you could even use emitEvent
to send some extra information but this would need to check it on internet because I never used it before.
UPDATE:
emitEvent
may sends also args
(for example name of clicked tag) and it allows to create only one event which will send different value(s) in args
emitEvent("clicked_svg", {target: event.target.tagName});
and it will need only one ui.on()
ui.on('clicked_svg', handler=on_click_svg)
and it will need only one function
def on_click_svg(event):
print("--- clicked svg ---")
print('event:', event)
print('event.args["target"]:', event.args['target'])
if event.args['target'] == 'circle':
print('>>> clicked circle <<<')
if event.args['target'] == 'rect':
print('>>> clicked rect <<<')
Full working code used for tests.
from nicegui import ui
def my_handler(event, target):
print('--- my_handler ---')
print('event:', event)
print('event.args["target"]:', event.args['target'])
print('target:', target)
def on_click_svg(event):
print("--- clicked svg ---")
print('event:', event)
print('event.args["target"]:', event.args['target'])
if event.args['target'] == 'circle':
print('>>> clicked circle <<<')
if event.args['target'] == 'rect':
print('>>> clicked rect <<<')
with ui.row():
svg_element = ui.html('''
<svg width="200" height="200" style="border: 1px solid black;">
<circle cx="50" cy="50" r="40" fill="red" class="clickable-circle"/>
<rect x="100" y="10" width="80" height="80" fill="blue" class="clickable-square"/>
</svg>
''')
ui.on('clicked_circle', handler=lambda event:my_handler(event, 'circle'))
ui.on('clicked_rect', handler=lambda event:my_handler(event, 'rect'))
ui.on('clicked_svg', handler=on_click_svg)
svg_element.on('click', js_handler='''(event) => {
console.log(event.target.tagName);
emitEvent(`clicked_${event.target.tagName}`, {target: event.target.tagName});
emitEvent("clicked_svg", {target: event.target.tagName});
}''')
ui.run(port = 8082)