by roundabout, Thursday, 29 August 2024, 13:10:30 (1724937030), pushed by roundabout, Friday, 30 August 2024, 03:07:47 (1724987267)
Author identity: vlad <vlad.muntoiu@gmail.com>
f21bc7fee4231363d0e629eb7d8b265e93b1657c
static/picture-annotation.py
@@ -70,11 +70,17 @@ async def select_shape(event):
object_list.appendChild(new_label)
new_radio.addEventListener("change", change_object_type_proxy)
selected_object = selected_shape.getAttribute("data-object-type")
if not selected_object:
new_radio.setAttribute("checked", "")
for object, description in objects.items():
new_radio = document.createElement("input")
new_radio.setAttribute("type", "radio")
new_radio.setAttribute("name", "object-type")
new_radio.setAttribute("value", object)
if selected_object == object:
new_radio.setAttribute("checked", "")
new_label = document.createElement("label")
new_label.appendChild(new_radio)
new_label.append(object)
@@ -91,6 +97,8 @@ def unselect_shape(event):
selected_shape.classList.remove("selected")
selected_shape = None
object_list.innerHTML = ""
select_shape_proxy = create_proxy(select_shape)
unselect_shape_proxy = create_proxy(unselect_shape)
@@ -99,6 +107,7 @@ unselect_shape_proxy = create_proxy(unselect_shape)
# 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))
make_polygon_proxy = create_proxy(lambda event: make_polygon(event))
follow_cursor_proxy = create_proxy(follow_cursor)
@@ -137,6 +146,10 @@ helper_message.innerText = "Select a shape type then click on the image to begin
def cancel_bbox(event):
global bbox_pos, new_shape
# Key must be ESCAPE
if event is not None and event.key != "Escape":
return
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()
@@ -197,17 +210,56 @@ def make_bbox(event):
cancel_bbox(None)
polygon_points = []
def make_polygon(event):
global new_shape, polygon_points
print(new_shape.outerHTML)
polygon = new_shape.children[0]
zone_rect = zone.getBoundingClientRect()
polygon_points.append(((event.clientX - zone_rect.left) / zone_rect.width,
(event.clientY - zone_rect.top) / zone_rect.height))
# Update the polygon
polygon.setAttribute("points", " ".join([f"{point[0] * image.naturalWidth},{point[1] * image.naturalHeight}" for point in polygon_points]))
def close_polygon(event):
# Polygon is already there, but we need to remove the events
zone.removeEventListener("click", make_polygon_proxy)
zone.removeEventListener("keydown", close_polygon_proxy)
document.body.style.cursor = "auto"
def cancel_polygon(event):
# Delete the polygon
new_shape.remove()
zone.removeEventListener("click", make_polygon_proxy)
zone.removeEventListener("keydown", close_polygon_proxy)
document.body.style.cursor = "auto"
close_polygon_proxy = create_proxy(close_polygon)
def open_shape(event):
global new_shape, bbox_pos
if bbox_pos or shape_type == "select":
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%")
new_shape.setAttribute("height", "100%")
zone_rect = zone.getBoundingClientRect()
new_shape.setAttribute("viewBox", f"0 0 {image.naturalWidth} {image.naturalHeight}")
new_shape.classList.add("shape-container")
if not polygon_points:
new_shape = document.createElementNS("http://www.w3.org/2000/svg", "svg")
new_shape.setAttribute("width", "100%")
new_shape.setAttribute("height", "100%")
zone_rect = zone.getBoundingClientRect()
new_shape.setAttribute("viewBox", f"0 0 {image.naturalWidth} {image.naturalHeight}")
new_shape.classList.add("shape-container")
if shape_type == "shape-bbox":
helper_message.innerText = ("Define the first point at the intersection of the lines "
@@ -221,6 +273,22 @@ def open_shape(event):
vertical_ruler.style.display = "block"
horizontal_ruler.style.display = "block"
document.body.style.cursor = "crosshair"
elif shape_type == "shape-polygon":
helper_message.innerText = ("Click on the image to define the points of the polygon, "
"press escape to cancel, "
"or press enter to close")
if not polygon_points:
zone.addEventListener("click", make_polygon_proxy)
document.addEventListener("keydown", close_polygon_proxy)
polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon")
polygon.setAttribute("fill", "none")
polygon.setAttribute("data-object-type", "")
polygon.classList.add("shape-polygon")
polygon.classList.add("shape")
new_shape.appendChild(polygon)
zone.appendChild(new_shape)
document.body.style.cursor = "crosshair"
for button in list(document.getElementById("shape-selector").children):
templates/picture-annotation.html
@@ -13,7 +13,7 @@
<h1>Annotating: {{ resource.title }}</h1>
<p id="annotation-helper-message">Please wait for Python to load...</p>
</x-frame>
<x-frame is="main-area">
<x-frame id="main-area">
<x-buttonbox id="shape-selector">
<button class="button-flat" title="selection" id="select">
<iconify-icon icon="mdi:cursor-default"></iconify-icon>