Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions examples/local_browser.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,41 @@
</style>
</head>
<body>
<!-- WIP: make it more of a "Playground"? -->
<select id="example-select">
<option value="events.py">events.py</option>
<option value="noise.py">noise.py</option>
<option value="snake.py">snake.py</option>
</select>
<!-- maybe something like add example (to test spawning more canvases and also closing them?) -->
<button id="reload-example">Reload example</button>
<button id="reload-page" style="background-color: orange;"onclick="location.reload();">Reload page</button>
<select id="lib-path">
<option value="../dist/rendercanvas-2.2.1-py3-none-any.whl" selected>local ./dist/</option>
<option value="rendercanvas">latest PyPI</option>
</select>
<input type="checkbox" id="load-wgpu">Load WebGPU (experimental)</input>
<br>
<!-- maybe wrap in a div so content after it still shows? -->
<canvas id="canvas" style="background-color: lightgrey;"></canvas><br>
some text below the canvas!
<!-- TODO: redirect the Python stdout/stderr to some kind of text box at the bottom -->
<script type="text/javascript">

async function loadPythonExample(example_path){
let response = await fetch(example_path);
let pythonCode = await response.text();
return pythonCode;
}

async function main(){

// fetch the file locally for easier scripting
// --allow-file-access-from-files or local webserver
// start chrome --allow-file-access-from-files %cd%\examples\local_browser.html or local webserver
// TODO: replace the actual code here (unless you have the module)
pythonCode = await (await fetch("snake.py")).text();
// pythonCode = await (await fetch("events.py")).text();
// pythonCode = await (await fetch("noise.py")).text();

let example_select = document.getElementById("example-select");
let reload_example_button = document.getElementById("reload-example");
pythonCode = await (await fetch(example_select.value)).text();

// Load Pyodide
let pyodide = await loadPyodide();
Expand All @@ -38,6 +61,18 @@

// Run the Python code async because some calls are async it seems.
pyodide.runPythonAsync(pythonCode);

// on click, we reload the example (or a difference one)
reload_example_button.onclick = async function() {
// interrupt existing code?
// sounds complex: https://pyodide.org/en/stable/usage/keyboard-interrupts.html
pyodide.setInterruptBuffer([2]);
pyodide.setInterruptBuffer([2]);

let example_file = example_select.value;
pythonCode = await (await fetch(example_file)).text();
pyodide.runPythonAsync(pythonCode);
};
}
main();
</script>
Expand Down
44 changes: 23 additions & 21 deletions rendercanvas/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

# packages available inside pyodide
from pyodide.ffi import run_sync, create_proxy
from js import document, ImageData, Uint8ClampedArray, window, HTMLCanvasElement, ResizeObserver

Check failure on line 20 in rendercanvas/html.py

View workflow job for this annotation

GitHub Actions / Linting

Ruff (F401)

rendercanvas/html.py:20:64: F401 `js.HTMLCanvasElement` imported but unused


# needed for completeness? somehow is required for other examples - hmm?
Expand Down Expand Up @@ -84,7 +84,7 @@
res += (mouse_button_map.get(i, i),)
return res


self._pointer_inside = False # keep track for the pointer_move event
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to look into:

  • Pointer capturing
  • Mouse leave and enter events

Maybe you already have and this comment is entirely moot

# resize ? maybe composition?
# perhaps: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver

Expand All @@ -93,7 +93,7 @@
# print(entry)
new_size = ()
ratio = self.get_pixel_ratio()
if entry.devicePixelContentBoxSize: # safari doesn't

Check failure on line 96 in rendercanvas/html.py

View workflow job for this annotation

GitHub Actions / Linting

Ruff (W291)

rendercanvas/html.py:96:65: W291 Trailing whitespace
new_size = (entry.devicePixelContentBoxSize[0].inlineSize, entry.devicePixelContentBoxSize[0].blockSize)
else:
lsize = ()
Expand Down Expand Up @@ -160,9 +160,9 @@
self.canvas_element.addEventListener("pointerup", self._pointer_up_proxy)

# pointer_move
# TODO: track pointer_inside and pointer_down to only trigger this when relevant?
# also figure out why it doesn't work in the first place...
def _html_pointer_move(proxy_args):
if (not self._pointer_inside) and (not proxy_args.buttons): # only when inside or a button is pressed
return
modifiers = tuple(
[v for k, v in key_mod_map.items() if getattr(proxy_args, k)]
)
Expand Down Expand Up @@ -199,6 +199,7 @@
"time_stamp": proxy_args.timeStamp,
}
self.submit_event(event)
self._pointer_inside = True

self._pointer_enter_proxy = create_proxy(_html_pointer_enter)
self.canvas_element.addEventListener("pointerenter", self._pointer_enter_proxy)
Expand All @@ -220,6 +221,7 @@
"time_stamp": proxy_args.timeStamp,
}
self.submit_event(event)
self._pointer_inside = False

self._pointer_leave_proxy = create_proxy(_html_pointer_leave)
self.canvas_element.addEventListener("pointerleave", self._pointer_leave_proxy)
Expand Down Expand Up @@ -299,24 +301,24 @@
self._key_up_proxy = create_proxy(_html_key_up)
document.addEventListener("keyup", self._key_up_proxy)

# char
def _html_char(proxy_args):
print(dir(proxy_args))
modifiers = tuple(
[v for k, v in key_mod_map.items() if getattr(proxy_args, k)]
)
event = {
"event_type": "char",
"modifiers": modifiers,
"char_str": proxy_args.key, # unsure if this works, it's experimental anyway: https://github.com/pygfx/rendercanvas/issues/28
"time_stamp": proxy_args.timeStamp,
}
self.submit_event(event)

self._char_proxy = create_proxy(_html_char)
document.addEventListener(
"input", self._char_proxy
) # maybe just another keydown? (seems to include unicode chars)
# char ... it's not this
# def _html_char(proxy_args):
Comment on lines +304 to +305
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have a look at the implementation of char events in jupyter_rfb vispy/jupyter_rfb#119

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at that initially, I tried to avoid actually changing the webpage, but maybe there is no way around it. Which also opens new questions like should the python code spawn new canvases?
Also all the global events might mess up when there are multiple canvases...

# print(dir(proxy_args))
# modifiers = tuple(
# [v for k, v in key_mod_map.items() if getattr(proxy_args, k)]
# )
# event = {
# "event_type": "char",
# "modifiers": modifiers,
# "char_str": proxy_args.key, # unsure if this works, it's experimental anyway: https://github.com/pygfx/rendercanvas/issues/28
# "time_stamp": proxy_args.timeStamp,
# }
# self.submit_event(event)

# self._char_proxy = create_proxy(_html_char)
# document.addEventListener(
# "input", self._char_proxy
# ) # maybe just another keydown? (seems to include unicode chars)

# animate event doesn't seem to be actually implemented, and it's by the loop not the gui.

Expand Down
Loading