fix: canvas fits image exactly, chained annotation loading, arrow move tracking
- Canvas now sizes to match the scaled image dimensions (zero empty space) instead of using a fixed aspect ratio, fixing coordinate mismatch between editor and viewer - Annotations load only after background image is ready via _pendingAnnotations pattern, preventing placement at wrong coordinates - Arrow endpoints (arrowX1/Y1/X2/Y2) update on object:modified using transform delta, so moved arrows serialize at correct position - Coordinate scaling on load: coordScale = currentImageScale / savedImageScale handles annotations saved at different screen widths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,8 +34,9 @@
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Canvas container */
|
||||
.canvas-container {
|
||||
/* Canvas container — use custom class name to avoid conflict with
|
||||
Fabric.js internal .canvas-container wrapper div */
|
||||
.anno-canvas-wrap {
|
||||
position: relative;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -43,6 +44,10 @@
|
||||
overflow: hidden;
|
||||
min-height: 400px;
|
||||
}
|
||||
.anno-canvas-wrap canvas {
|
||||
display: block;
|
||||
}
|
||||
/* Fabric.js internal wrapper also needs display:block on canvases */
|
||||
.canvas-container canvas {
|
||||
display: block;
|
||||
}
|
||||
@@ -141,7 +146,7 @@
|
||||
<span x-text="saving ? window.__i18n_taskDrawing.saving : window.__i18n_taskDrawing.saveAnnotations"></span>
|
||||
</button>
|
||||
|
||||
<a href="{{ url_for('maker.task_editor', recipe_id=recipe.id) }}"
|
||||
<a :href="'{{ url_for('maker.task_editor', recipe_id=recipe.id) }}' + '?_=' + Date.now()"
|
||||
class="btn btn-secondary gap-1.5">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 17l-5-5m0 0l5-5m-5 5h12"/>
|
||||
@@ -245,7 +250,7 @@
|
||||
<!-- Separator -->
|
||||
<div class="w-px h-6 bg-[var(--border-color)] mx-1"></div>
|
||||
|
||||
<!-- Delete -->
|
||||
<!-- Delete selected -->
|
||||
<button type="button"
|
||||
class="anno-btn text-red-500 hover:text-red-600"
|
||||
@click="deleteAnnotation()"
|
||||
@@ -255,7 +260,21 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||
</svg>
|
||||
<span class="hidden sm:inline">{{ _('Elimina') }}</span>
|
||||
{{ _('Elimina') }}
|
||||
</button>
|
||||
|
||||
<!-- Clear All -->
|
||||
<button type="button"
|
||||
class="anno-btn text-red-500 hover:text-red-600"
|
||||
@click="if (confirm('{{ _('Eliminare tutte le annotazioni?') }}')) clearAllAnnotations()"
|
||||
title="{{ _('Cancella tutto') }}">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M9 13h6m2 9H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
{{ _('Cancella tutto') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -337,7 +356,7 @@
|
||||
<div class="tmf-card">
|
||||
<div class="tmf-card-body p-0">
|
||||
<div x-data="annotationEditor()"
|
||||
class="canvas-container"
|
||||
class="anno-canvas-wrap"
|
||||
id="annotationCanvasContainer">
|
||||
<canvas id="annotationCanvas" x-ref="fabricCanvas"></canvas>
|
||||
</div>
|
||||
@@ -353,7 +372,7 @@
|
||||
<script>
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/annotation-editor.js') }}?v=10"></script>
|
||||
<script src="{{ url_for('static', filename='js/annotation-editor.js') }}?v=25"></script>
|
||||
<script>
|
||||
function taskDrawing() {
|
||||
const taskData = window.__taskData || {};
|
||||
@@ -459,6 +478,14 @@ function taskDrawing() {
|
||||
this.errorMessage = data.detail || window.__i18n_taskDrawing.saveError;
|
||||
} else {
|
||||
this.successMessage = window.__i18n_taskDrawing.saveSuccess;
|
||||
// Store updated annotations in sessionStorage so task_editor
|
||||
// can pick them up and refresh the preview immediately.
|
||||
try {
|
||||
sessionStorage.setItem('taskDrawingUpdated', JSON.stringify({
|
||||
taskId: this.taskId,
|
||||
annotations_json: this.annotationsJson
|
||||
}));
|
||||
} catch (_e) { /* sessionStorage may be unavailable */ }
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('saveAnnotations error:', err);
|
||||
@@ -480,6 +507,10 @@ function taskDrawing() {
|
||||
window.dispatchEvent(new CustomEvent('anno-delete-selected'));
|
||||
},
|
||||
|
||||
clearAllAnnotations() {
|
||||
window.dispatchEvent(new CustomEvent('anno-clear-all'));
|
||||
},
|
||||
|
||||
setAnnoColor(color) {
|
||||
this.annoColor = color;
|
||||
window.dispatchEvent(new CustomEvent('anno-color-change', {
|
||||
|
||||
Reference in New Issue
Block a user