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>