roundabout,
created on Thursday, 5 September 2024, 08:43:10 (1725525790),
received on Thursday, 5 September 2024, 10:39:47 (1725532787)
Author identity: vlad <vlad.muntoiu@gmail.com>
610489a27a2da9b629f66fcdb24c2c7242e24f83
app.py
@@ -36,6 +36,12 @@ def split(value, separator=None, maxsplit=-1):
return value.split(separator, maxsplit)
@app.template_filter("median")
def median(value):
value = list(value) # prevent generators
return sorted(value)[len(value) // 2]
with app.app_context():
class User(db.Model):
static/picture-annotation.py
@@ -116,7 +116,7 @@ def put_shapes(json_shapes):
rectangle.setAttribute("width", str(shape["shape"]["w"] * image.naturalWidth))
rectangle.setAttribute("height", str(shape["shape"]["h"] * image.naturalHeight))
rectangle.setAttribute("fill", "none")
rectangle.setAttribute("data-object-type", shape["object"])
rectangle.setAttribute("data-object-type", shape["object"] or "")
rectangle.classList.add("shape-bbox")
rectangle.classList.add("shape")
new_shape.appendChild(rectangle)
@@ -126,7 +126,7 @@ def put_shapes(json_shapes):
[f"{point['x'] * image.naturalWidth},{point['y'] * image.naturalHeight}" for point in shape["shape"]])
polygon.setAttribute("points", points)
polygon.setAttribute("fill", "none")
polygon.setAttribute("data-object-type", shape["object"])
polygon.setAttribute("data-object-type", shape["object"] or "")
polygon.classList.add(f"shape-{shape['type']}")
polygon.classList.add("shape")
new_shape.appendChild(polygon)
@@ -137,7 +137,7 @@ def put_shapes(json_shapes):
point.setAttribute("r", "0")
point.classList.add("shape-point")
point.classList.add("shape")
point.setAttribute("data-object-type", shape["object"])
point.setAttribute("data-object-type", shape["object"] or "")
new_shape.appendChild(point)
zone.appendChild(new_shape)
static/style.css
@@ -130,6 +130,9 @@ iconify-icon {
.shape-container-viewonly > .shape-point {
stroke: var(--color-info);
transition: r 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
stroke-width 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
filter 0.25s cubic-bezier(0.61, 1, 0.88, 1);
}
.shape-label {
@@ -162,6 +165,12 @@ iconify-icon {
transform: scale(1);
}
/* Hide points with a bubble */
#annotation-zone:has(+ x-buttonbox #show-objects:checked) > .shape-container-viewonly > .shape-point:has(+ foreignObject) {
r: 0;
border-width: 0;
}
#annotation-zone:has(+ x-buttonbox #show-shapes:checked) > .shape-container-viewonly > .shape {
fill-opacity: 0.1;
stroke-opacity: 1;
templates/picture.html
@@ -1,5 +1,14 @@
{% extends "default.html" %}
{% block title %}Picture | gigadata{% endblock %}
{% macro shape_label(x, y, text) %}
{% if text %}
<foreignObject height="100%" width="100%" x="{{ x * size[0] }}" y="{{ y * size[1] }}">
<div class="shape-label">
{{ text }}
</div>
</foreignObject>
{% endif %}
{% endmacro %}
{% block content %}
<x-frame style="--width: 768px">
<h1>{{ resource.title }}</h1>
@@ -12,10 +21,13 @@
<svg class="shape-container-viewonly" viewBox="0 0 {{ size[0] }} {{ size[1] }}">
<rect x="{{ region.json.shape.x * size[0] }}"
y="{{ region.json.shape.y * size[1] }}"
width="{{ region.json.shape.width * size[0] }}"
height="{{ region.json.shape.height * size[1] }}"
width="{{ region.json.shape.w * size[0] }}"
height="{{ region.json.shape.h * size[1] }}"
fill="none" class="shape-bbox shape"
></rect>
{% set centre_x = region.json.shape.x + region.json.shape.w / 2 %}
{% set centre_y = region.json.shape.y + region.json.shape.h / 2 %}
{{ shape_label(centre_x, centre_y, region.object_id) }}
</svg>
{% elif region.json.type == "polygon" %}
<svg class="shape-container-viewonly" viewBox="0 0 {{ size[0] }} {{ size[1] }}">
@@ -26,19 +38,20 @@
{% set right = region.json.shape | sort(attribute='x') | last %}
{% set centre_x = (left.x + right.x) / 2 %}
{% set centre_y = (top.y + bottom.y) / 2 %}
<foreignObject height="100%" width="100%" x="{{ centre_x * size[0] }}" y="{{ centre_y * size[1] }}">
<div class="shape-label">
{{ region.object_id }}
</div>
</foreignObject>
{{ shape_label(centre_x, centre_y, region.object_id) }}
</svg>
{% elif region.json.type == "polyline" %}
<svg class="shape-container-viewonly" viewBox="0 0 {{ size[0] }} {{ size[1] }}">
<polyline points="{% for point in region.json.shape %}{{ point.x * size[0] }},{{ point.y * size[1] }} {% endfor %}" fill="none" class="shape-polyline shape"></polyline>
<polyline points="{% for point in region.json.shape %}{{ point.x * size[0] }},{{ point.y * size[1] }} {% endfor %}" fill="none" class="shape-polyline shape">
{# Median point #}
{% set centre_x = region.json.shape | map(attribute="x") | median %}
{% set centre_y = region.json.shape | map(attribute="y") | median %}
{{ shape_label(centre_x, centre_y, region.object_id) }}
</svg>
{% elif region.json.type == "point" %}
<svg class="shape-container-viewonly" viewBox="0 0 {{ size[0] }} {{ size[1] }}">
<circle cx="{{ region.json.shape.x * size[0] }}" cy="{{ region.json.shape.y * size[1] }}" r="0" fill="none" class="shape-point shape"></circle>
{{ shape_label(region.json.shape.x, region.json.shape.y, region.object_id) }}
</svg>
{% endif %}
{% endfor %}