roundabout,
created on Monday, 19 August 2024, 16:05:11 (1724083511),
received on Monday, 19 August 2024, 16:05:16 (1724083516)
Author identity: vlad <vlad.muntoiu@gmail.com>
ebc5eaa33368d9916ecdf3a5226f192e6fe8880f
static/picture-annotation.py
@@ -5,9 +5,29 @@ document.getElementById("shape-options").style.display = "flex"
image = document.getElementById("annotation-image")
zone = document.getElementById("annotation-zone")
confirm_button = document.getElementById("annotation-confirm")
cancel_button = document.getElementById("annotation-cancel")
confirm_button.style.display = "none"
cancel_button.style.display = "none"
shape_type = ""
bbox_pos = None
new_shape = None
def follow_cursor(event):
rect = zone.getBoundingClientRect()
x = event.clientX - rect.left
y = event.clientY - rect.top
vertical_ruler.style.left = str(x) + "px"
horizontal_ruler.style.top = str(y) + "px"
# These are functions usable in JS
cancel_bbox_proxy = create_proxy(lambda event: cancel_bbox(event))
make_bbox_proxy = create_proxy(lambda event: make_bbox(event))
follow_cursor_proxy = create_proxy(follow_cursor)
def switch_shape(event):
@@ -16,7 +36,6 @@ def switch_shape(event):
shape_type = shape
print("Shape is now of type:", shape)
vertical_ruler = document.getElementById("annotation-ruler-vertical")
horizontal_ruler = document.getElementById("annotation-ruler-horizontal")
vertical_ruler_2 = document.getElementById("annotation-ruler-vertical-secondary")
@@ -26,22 +45,33 @@ helper_message = document.getElementById("annotation-helper-message")
helper_message.innerText = "Select a shape type then click on the image to begin defining it"
def follow_cursor(event):
rect = zone.getBoundingClientRect()
x = event.clientX - rect.left
y = event.clientY - rect.top
vertical_ruler.style.left = str(x) + "px"
horizontal_ruler.style.top = str(y) + "px"
def cancel_bbox(event):
global bbox_pos, new_shape
bbox_pos = None
if new_shape is not None and event is not None:
# Require event so the shape is kept when it ends normally
new_shape.remove()
new_shape = None
zone.removeEventListener("click", make_bbox_proxy)
document.removeEventListener("keydown", cancel_bbox_proxy)
cancel_button.removeEventListener("click", cancel_bbox_proxy)
bbox_pos = None
vertical_ruler.style.display = "none"
horizontal_ruler.style.display = "none"
vertical_ruler_2.style.display = "none"
horizontal_ruler_2.style.display = "none"
document.body.style.cursor = "auto"
cancel_button.style.display = "none"
helper_message.innerText = "Select a shape type then click on the image to begin defining it"
def make_bbox(event):
global new_shape, bbox_pos
zone_rect = zone.getBoundingClientRect()
if bbox_pos is None:
helper_message.innerText = "Now define the second point"
bbox_pos = [(event.clientX - zone_rect.left) / zone_rect.width,
(event.clientY - zone_rect.top) / zone_rect.height]
vertical_ruler_2.style.left = str(bbox_pos[0] * 100) + "%"
@@ -50,11 +80,15 @@ def make_bbox(event):
horizontal_ruler_2.style.display = "block"
else:
x0, y0 = bbox_pos
x0, y0 = bbox_pos.copy()
x1 = (event.clientX - zone_rect.left) / zone_rect.width
y1 = (event.clientY - zone_rect.top) / zone_rect.height
rectangle = document.createElementNS("http://www.w3.org/2000/svg", "rect")
new_shape.appendChild(rectangle)
zone.appendChild(new_shape)
minx = min(x0, x1)
miny = min(y0, y1)
maxx = max(x0, x1)
@@ -67,27 +101,12 @@ def make_bbox(event):
rectangle.setAttribute("fill", "none")
rectangle.classList.add("shape-bbox")
new_shape.appendChild(rectangle)
zone.appendChild(new_shape)
vertical_ruler.style.display = "none"
horizontal_ruler.style.display = "none"
vertical_ruler_2.style.display = "none"
horizontal_ruler_2.style.display = "none"
document.body.style.cursor = "auto"
zone.removeEventListener("click", create_proxy(make_bbox))
return
zone.addEventListener(
"mousemove",
create_proxy(follow_cursor)
)
new_shape = None
cancel_bbox(None)
def open_shape(event):
global last_click_position, new_shape
global new_shape, bbox_pos
if bbox_pos:
return
print("Creating a new shape of type:", shape_type)
new_shape = document.createElementNS("http://www.w3.org/2000/svg", "svg")
new_shape.setAttribute("width", "100%")
@@ -96,26 +115,23 @@ def open_shape(event):
new_shape.setAttribute("viewBox", f"0 0 {image.naturalWidth} {image.naturalHeight}")
if shape_type == "shape-bbox":
helper_message.innerText = ("Define the first point at the intersection of the lines "
"by clicking on the image, or click the cross to cancel")
cancel_button.addEventListener("click", cancel_bbox_proxy)
document.addEventListener("keydown", cancel_bbox_proxy)
cancel_button.style.display = "block"
bbox_pos = None
zone.addEventListener(
"click",
create_proxy(make_bbox)
)
zone.addEventListener("click", make_bbox_proxy)
vertical_ruler.style.display = "block"
horizontal_ruler.style.display = "block"
document.body.style.cursor = "crosshair"
for button in list(document.getElementById("shape-selector").children):
button.addEventListener(
"click",
create_proxy(switch_shape)
)
button.addEventListener("click", create_proxy(switch_shape))
print("Shape", button.id, "is available")
zone.addEventListener(
"click",
create_proxy(open_shape)
)
zone.addEventListener("mousemove", follow_cursor_proxy)
zone.addEventListener("click", create_proxy(open_shape))
templates/picture-annotation.html
@@ -37,7 +37,7 @@
<iconify-icon icon="mdi:gesture"></iconify-icon>
</button>
<button class="button-flat" title="point" id="shape-point">
<iconify-icon icon="mdi:circle"></iconify-icon>
<iconify-icon icon="mdi:crosshairs-gps"></iconify-icon>
</button>
<button class="button-flat" title="whole picture" id="shape-all">
<iconify-icon icon="mdi:image"></iconify-icon>
@@ -51,10 +51,10 @@
<div id="annotation-ruler-horizontal-secondary" class="annotation-ruler"></div>
</div>
<x-buttonbox style="display: none;" id="shape-options">
<button class="button-flat" title="cancel" disabled>
<button class="button-flat" title="cancel" id="annotation-cancel">
<iconify-icon icon="mdi:close"></iconify-icon>
</button>
<button class="button-flat" title="apply" disabled>
<button class="button-flat" title="apply" id="annotation-confirm">
<iconify-icon icon="mdi:check"></iconify-icon>
</button>
</x-buttonbox>