roundabout,
created on Saturday, 4 January 2025, 10:49:10 (1735987750),
received on Saturday, 4 January 2025, 14:08:16 (1735999696)
Author identity: vlad <vlad.muntoiu@gmail.com>
056dce4e24d3cb1ad3a0987ee6c2318ec1fcf9f1
static/picture-annotation.py
@@ -177,6 +177,36 @@ next_shape_key_proxy = create_proxy(lambda event: event.key == "ArrowRight" and
previous_shape_key_proxy = create_proxy(lambda event: event.key == "ArrowLeft" and previous_shape_proxy(None)) def get_centre(shape): if shape.tagName == "rect": x = float(shape.getAttribute("x")) + float(shape.getAttribute("width")) / 2 y = float(shape.getAttribute("y")) + float(shape.getAttribute("height")) / 2 elif shape.tagName == "polygon": points = shape.getAttribute("points").split(" ") # Average of the extreme points sorted_x = sorted([float(point.split(",")[0]) for point in points]) sorted_y = sorted([float(point.split(",")[1]) for point in points]) top = sorted_y[0] bottom = sorted_y[-1] left = sorted_x[0] right = sorted_x[-1] x = (left + right) / 2 y = (top + bottom) / 2 elif shape.tagName == "polyline": points = shape.getAttribute("points").split(" ") # Median point x = float(points[len(points) // 2].split(",")[0]) y = float(points[len(points) // 2].split(",")[1]) elif shape.tagName == "circle" and shape.classList.contains("shape-point"): x = float(shape.getAttribute("cx")) y = float(shape.getAttribute("cy")) else: return None return x, y async def focus_shape(shape): global selected_shape
@@ -198,6 +228,10 @@ async def focus_shape(shape):
document.addEventListener("keydown", next_shape_key_proxy) document.addEventListener("keydown", previous_shape_key_proxy) object_list.style.display = "flex" object_list.style.left = str(get_centre(shape)[0] / image.naturalWidth * 100) + "%" object_list.style.top = str(get_centre(shape)[1] / image.naturalHeight * 100) + "%" object_list.innerHTML = "" new_radio = document.createElement("input")
@@ -294,6 +328,7 @@ def unselect_shape(event):
selected_shape = None object_list.innerHTML = "" object_list.style.display = "none"delete_button.style.display = "none" next_button.style.display = "none" previous_button.style.display = "none"
@@ -310,6 +345,7 @@ def delete_shape(event):
selected_shape.parentNode.remove() selected_shape = None object_list.innerHTML = "" object_list.style.display = "none"delete_button.style.display = "none" next_button.style.display = "none" previous_button.style.display = "none"
@@ -366,6 +402,12 @@ def switch_shape(event):
print("Shape is now of type:", shape) def select_mode(): global shape_type shape_type = "select" document.getElementById("select").click() vertical_ruler = document.getElementById("annotation-ruler-vertical") horizontal_ruler = document.getElementById("annotation-ruler-horizontal") vertical_ruler_2 = document.getElementById("annotation-ruler-vertical-secondary")
static/style.css
@@ -770,3 +770,13 @@ nav .button-flat .ripple-pad {
text-transform: uppercase; color: var(--color-accent); } #object-types { z-index: 3; background: var(--color-card); box-shadow: var(--shadow-card); padding: 1rem; border-radius: var(--radius-card); position: absolute; display: none; }
templates/picture-annotation.html
@@ -14,7 +14,6 @@
<script type="module" src="https://pyscript.net/releases/2024.8.2/core.js"></script> <x-frame style="--width: 768px"> <h1>Annotating: {{ resource.title }}</h1><p id="annotation-helper-message">Please wait for Python to load...</p> </x-frame> <x-frame id="main-area">
@@ -36,6 +35,7 @@
</button> </x-buttonbox> <div id="annotation-zone"> <x-vbox id="object-types" style="--gap-box: 0.25rem; --padding-box: 1rem;"></x-vbox><img id="annotation-image" src="/raw/picture/{{ resource.id }}" alt=""> <div id="annotation-ruler-vertical" class="annotation-ruler"></div> <div id="annotation-ruler-horizontal" class="annotation-ruler"></div>
@@ -66,8 +66,6 @@
Save </button> </x-buttonbox> <x-vbox id="object-types" style="--gap-box: 0.25rem; --padding-box: 1rem;"></x-vbox></x-frame> <input type="hidden" id="resource-id" name="resource-id" value="{{ resource.id }}"> <script type="mpy" src="/static/picture-annotation.py"></script>