roundabout,
created on Tuesday, 7 January 2025, 13:03:32 (1736255012),
received on Tuesday, 7 January 2025, 13:23:33 (1736256213)
Author identity: vlad <vlad.muntoiu@gmail.com>
e2664aa732ca99b9332b6b7481e3cce1e0c5d96b
static/efficient-ui
@@ -1 +1 @@
Subproject commit 30b18afca348bd1168ee40ef9d11b1fb8fd502b9
Subproject commit e4a04ff48c746340fe1568e6b2b8efc2040f30c3
static/picture-annotation.py
@@ -1,3 +1,5 @@
import pyscript
import js
from pyscript import document, fetch as pyfetch
from pyscript.ffi import create_proxy
import asyncio
@@ -14,6 +16,10 @@ delete_button = document.getElementById("annotation-delete")
previous_button = document.getElementById("annotation-previous")
next_button = document.getElementById("annotation-next")
save_button = document.getElementById("annotation-save")
zoom_slider = document.getElementById("zoom-slider")
zoom_in_button = document.getElementById("zoom-in")
zoom_out_button = document.getElementById("zoom-out")
zoom_indicator = document.getElementById("zoom-indicator")
object_list = document.getElementById("object-types")
object_list_content = document.getElementById("object-types-content")
@@ -692,6 +698,8 @@ scale = 1
translate_x = 0
translate_y = 0
scale_exponent = 0
def update_transform():
zone.style.transform = f"translate({translate_x}px, {translate_y}px) scale({scale}) "
object_list.style.transform = f"scale({1/scale})" # neutralise the zoom
@@ -709,9 +717,8 @@ def update_transform():
shape.setAttribute("transform", f"scale({scale})")
shape.setAttribute("transform-origin", "0 0")
scale_exponent = 0
zoom_indicator.innerText = f"{scale:.3f}x"
zoom_offset = (0, 0)
def compute_zoom_translation_around_point(element, x, y, sc, nsc):
rect = element.getBoundingClientRect()
@@ -754,6 +761,7 @@ def on_wheel(event):
translate_y -= offset_y
scale = new_scale
zoom_slider.value = scale_exponent
update_transform()
@@ -844,6 +852,7 @@ def on_touch_move(event):
last_touch_positions = current_positions
last_touch_distance = current_distance
zoom_slider.value = scale_exponent
update_transform()
@@ -853,6 +862,25 @@ def on_touch_end(event):
last_touch_positions = None
last_touch_distance = None
def zoom_slider_change(event):
global scale, scale_exponent
scale_exponent = float(event.currentTarget.value)
scale = 2 ** scale_exponent
update_transform()
def zoom_in(event):
zoom_slider.stepUp()
zoom_slider.dispatchEvent(js.Event.new("input"))
def zoom_out(event):
zoom_slider.stepDown()
zoom_slider.dispatchEvent(js.Event.new("input"))
zoom_container.addEventListener("wheel", on_wheel)
zoom_container.addEventListener("mousedown", on_mouse_down)
document.addEventListener("mousemove", on_mouse_move)
@@ -860,7 +888,11 @@ document.addEventListener("mouseup", on_mouse_up)
zone.addEventListener("touchstart", on_touch_start)
zone.addEventListener("touchmove", on_touch_move)
zone.addEventListener("touchend", on_touch_end)
zoom_slider.addEventListener("input", zoom_slider_change)
zoom_in_button.addEventListener("click", zoom_in)
zoom_out_button.addEventListener("click", zoom_out)
# Load existing annotations, if any
put_shapes(await load_shapes())
update_transform()
print("Ready!")
static/style.css
@@ -801,11 +801,11 @@ nav .button-flat .ripple-pad {
align-items: center;
}
#annotation-controls > x-buttonbox > button:has(iconify-icon) {
#annotation-controls > x-buttonbox button:has(iconify-icon) {
aspect-ratio: 1;
}
#annotation-controls > x-buttonbox > button > iconify-icon {
#annotation-controls > x-buttonbox button > iconify-icon {
font-size: 1.5rem;
}
@@ -859,3 +859,15 @@ body.fixed-content-area > main {
display: flex;
flex-direction: column;
}
#annotation-zoom-controls {
display: flex;
gap: 0.5rem;
justify-content: center;
align-items: center;
}
#zoom-indicator {
width: 7ch;
text-align: right;
}
templates/picture-annotation.html
@@ -32,6 +32,16 @@
<button class="button-flat" title="point" id="shape-point">
<iconify-icon icon="mdi:crosshairs-gps"></iconify-icon>
</button>
<x-hbox id="annotation-zoom-controls">
<span id="zoom-indicator">1.000x</span>
<button class="button-flat" title="zoom out" id="zoom-out">
<iconify-icon icon="mdi:magnify-minus"></iconify-icon>
</button>
<input type="range" id="zoom-slider" min="-4" max="6" step="0.25" value="0" aria-label="Zoom">
<button class="button-flat" title="zoom in" id="zoom-in">
<iconify-icon icon="mdi:magnify-plus"></iconify-icon>
</button>
</x-hbox>
</x-buttonbox>
<x-buttonbox style="display: none;" id="shape-options">
<button class="button-flat" title="cancel" id="annotation-cancel">