In justpy, I would like to load an image and record which pixel a clicked on. So I need the position of the pixel of an image with an offset, not position of the mouse on screen.
JustPy click and click_out event do not give any coordinates at all, even in debug mode.
{'event_type': 'click__out', 'id': 2, 'class_name': 'Img', 'html_tag': 'img', 'vue_type': 'html_component', 'page_id': 0, 'websocket_id': 0, 'session_id': 'e0311ccc163e47df884e3cb109d046b9', 'msg_type': 'event', 'page': WebPage(page_id: 0, number of components: 2, reload interval: None), 'websocket': <starlette.websockets.WebSocket object at 0x75ae283282d0>, 'target': Img(id: 2, html_tag: img, vue_type: html_component, name: No name, number of components: 0)}
Any idea how to get the position of the pixel? Or the offset of the image on the users screen?
I read the examples on the webpage and tried different events, but failed.
import justpy as jp
def my_click1(self, msg):
self.text = 'I was clicked'
#self.log.text=msg
print(msg.event_type)
print(msg['event_type'])
print(msg)
def img_click(self, msg):
print("Image Click")
print(msg.event_type)
print(msg['event_type'])
print(msg)
print(self)
def img_clickout(self, msg):
print("Clickout")
print(msg.event_type)
print(msg['event_type'])
print(msg)
print(self)
def event_demo1():
wp = jp.WebPage()
wp.debug = True
d = jp.Div(text='Not clicked yet', a=wp, classes='w-48 text-xl m-2 p-1 bg-blue-500 text-white')
img = jp.Img(src='https://www.python.org/static/community_logos/python-powered-h-140x182.png', a=wp)
d.on('click', my_click1)
img.on('click', img_click)
img.on('click__out', img_clickout)
return wp
jp.justpy(event_demo1)
Using img.additional_properties = ['pageX', 'pageY', 'screenX', 'screenY']
you can get mouse position on page (pageX
, pageY
)
To get image position I use
jp.run_task(wp.run_javascript(js_code, request_id='image_data'))
to execute JavaScript
code
js_code = f'''
var image = document.querySelector('[name="{self.name}"]'); // put self.name
var rect = image.getBoundingClientRect();
//console.log(rect.top, rect.right, rect.bottom, rect.left);
({{image: rect, mouse:{{ pageX:{msg.pageX}, pageY:{msg.pageY}, screenX: {msg.screenX}, screenY: {msg.screenY} }} }}); // it has to be in ( )
'''
I use f-string
to put some extra values in code - so it can run with different images.
I use name
from Img(.. , name=...)
to find image in browser and I use getBoundingClientRect()
to get its size and position.
Next I send back all information - even mouse position because it can't get it in current function but in function assigned to wp.on('result_ready', result_ready)
.
Because function result_ready
can be used to get result from different events so I use result_id
in run_javascript(..., request_id=...)
to recognize this event.
Doc:
Full working code.
import justpy as jp
def result_ready(self, msg):
#print('result_ready: self:', self)
#print('result_ready: msg:', msg)
#print('result_ready: msg.request_id', msg.request_id)
if msg.request_id == 'image_data':
#print(msg.result)
print('image:', msg.result.image)
print('mouse:', msg.result.mouse)
left = msg.result.image.left
top = msg.result.image.top
pageX = msg.result.mouse.pageX
pageY = msg.result.mouse.pageY
print('x:', pageX-left)
print('y:', pageY-top)
#screenX = msg.result.mouse.screenX
#screenY = msg.result.mouse.screenY
#print('x:', screenX-left)
#print('y:', screenY-top)
def click_image(self, msg):
#print('click_image: self:', self)
#print('click_image: msg:', msg)
#print('click_image: self.name:', self.name)
print('click_image: msg.pageX:', msg.pageX)
print('click_image: msg.pageY:', msg.pageY)
print('click_image: msg.screenX:', msg.screenX)
print('click_image: msg.screenY:', msg.screenY)
# f-string needs `{{ }}` to put string `{ }` in `({{image: rect}});`
js_code = f'''
var image = document.querySelector('[name="{self.name}"]'); // put self.name
var rect = image.getBoundingClientRect();
//console.log(rect.top, rect.right, rect.bottom, rect.left);
({{image: rect, mouse:{{ pageX:{msg.pageX}, pageY:{msg.pageY}, screenX: {msg.screenX}, screenY: {msg.screenY} }} }}); // it has to be in ( )
'''
#print('click_image: before run_javascript')
#print(js_code)
jp.run_task(wp.run_javascript(js_code, request_id='image_data'))
#print('click_image: after run_javascript')
def main():
global wp # need in `wp.run_javascript`
wp = jp.WebPage()
wp.debug = True
wp.on('result_ready', result_ready)
txt = jp.Div(a=wp, text="Some text before Image to move it from border")
img1 = jp.Img(a=wp, name='image_1', src='https://www.python.org/static/community_logos/python-powered-h-140x182.png', style='display: inline')
img1.on('click', click_image)
img1.additional_properties = ['pageX', 'pageY', 'screenX', 'screenY']
img2 = jp.Img(a=wp, name='image_2', src='https://www.python.org/static/community_logos/python-powered-h-140x182.png', style='display: inline')
img2.on('click', click_image)
img2.additional_properties = ['pageX', 'pageY', 'screenX', 'screenY']
return wp
jp.justpy(main)