From 8a5859ce466be42ef938298d403d4d2baeab02f1 Mon Sep 17 00:00:00 2001 From: solocla Date: Sat, 4 Jul 2026 15:46:11 +0200 Subject: [PATCH] added free text --- public/userarea/annotationsModal.js | 222 +++++++++++++++++++++++++- public/userarea/modal_annotations.php | 7 + 2 files changed, 228 insertions(+), 1 deletion(-) diff --git a/public/userarea/annotationsModal.js b/public/userarea/annotationsModal.js index fa3eea2c..0181a90a 100644 --- a/public/userarea/annotationsModal.js +++ b/public/userarea/annotationsModal.js @@ -19,6 +19,9 @@ $(document).ready(function () { let descriptionTextbox = null; let markerObjects = {}; let nextMarkerId = 1; + let freeTextMode = false; + let freeTextObjects = {}; + let nextFreeTextId = 1; let partsListData = []; // DIMENSIONE GLOBALE MARKER let globalMarkerSize = 16; @@ -144,6 +147,9 @@ $(document).ready(function () { selectedPartNumber = null; unsavedChanges = false; partsListData = []; + freeTextMode = false; // ← aggiungi + freeTextObjects = {}; // ← aggiungi + $("#addFreeTextBtnAnnotations").removeClass("active"); // ← aggiungi if (fabricCanvas) { fabricCanvas.off(); fabricCanvas.dispose(); @@ -192,6 +198,29 @@ $(document).ready(function () { updateMarkers(); markUnsaved(); }); + + // =================== + // TESTO LIBERO — TOGGLE MODALITÀ + // =================== + $(document) + .off("click.freeTextToggle", "#addFreeTextBtnAnnotations") + .on("click.freeTextToggle", "#addFreeTextBtnAnnotations", function (e) { + e.preventDefault(); + e.stopPropagation(); + + freeTextMode = !freeTextMode; + $(this).toggleClass("active", freeTextMode); + + // Disattiva la selezione parte/marker mentre si aggiunge testo libero + if (freeTextMode) { + selectedPartNumber = null; + $("#partsListAnnotations .list-group-item").removeClass( + "active", + ); + } + + console.log("Free text mode:", freeTextMode); + }); // =================== // COLORE LISTA DESCRIZIONI // =================== @@ -205,9 +234,22 @@ $(document).ready(function () { if (descriptionTextbox && fabricCanvas) { descriptionTextbox.set("fill", globalDescriptionColor); - fabricCanvas.renderAll(); } + // Aggiorna anche i testi liberi già piazzati sulla foto corrente + const currentPhoto = $("#samplePhotoAnnotations").attr("src"); + const annotations = photoAnnotations[currentPhoto]; + if (annotations && annotations.freeTexts) { + annotations.freeTexts.forEach((entry) => { + entry.color = globalDescriptionColor; + }); + } + Object.values(freeTextObjects).forEach((obj) => { + obj.set("fill", globalDescriptionColor); + }); + + if (fabricCanvas) fabricCanvas.renderAll(); + markUnsaved(); }, ); @@ -382,7 +424,29 @@ $(document).ready(function () { console.log( "Evento mouse:down su canvas, selectedPartNumber:", selectedPartNumber, + "freeTextMode:", + freeTextMode, ); + + // Modalità testo libero: ha priorità, un solo click e si disattiva da sola + if (freeTextMode) { + if (options.target) { + console.log( + "Click su un oggetto esistente, ignoro.", + ); + return; + } + const pointer = fabricCanvas.getPointer(options.e); + const x = pointer.x / photoData.scale; + const y = pointer.y / photoData.scale; + + addFreeText(x, y); + + freeTextMode = false; + $("#addFreeTextBtnAnnotations").removeClass("active"); + return; + } + if (selectedPartNumber === null) { console.log( "Nessuna parte selezionata, ignoro il click.", @@ -437,6 +501,7 @@ $(document).ready(function () { updateMarkers(); updateDescriptions(); + updateFreeTexts(); }, 10); }); } @@ -997,7 +1062,128 @@ $(document).ready(function () { }, }); } + // =================== + // TESTO LIBERO — CREAZIONE E RENDER + // =================== + function addFreeText(x, y) { + const currentPhoto = $("#samplePhotoAnnotations").attr("src"); + if (!photoAnnotations[currentPhoto]) { + photoAnnotations[currentPhoto] = { + markers: [], + freeTexts: [], + hasDescriptions: false, + descriptionPosition: { x: 10, y: 10 }, + descriptionSize: { + width: photoData.displayWidth * 0.3, + height: photoData.displayHeight * 0.3, + }, + }; + } + if (!photoAnnotations[currentPhoto].freeTexts) { + photoAnnotations[currentPhoto].freeTexts = []; + } + + const entry = { + id: nextFreeTextId++, + x, + y, + text: "Testo", + color: globalDescriptionColor, + fontSize: Math.max(16, Math.round(globalMarkerSize * 0.8)), + }; + + photoAnnotations[currentPhoto].freeTexts.push(entry); + renderFreeText(entry, true); + markUnsaved(); + } + + function renderFreeText(entry, startEditing = false) { + const itext = new fabric.IText(entry.text, { + left: entry.x * photoData.scale, + top: entry.y * photoData.scale, + fontFamily: "Arial", + fontSize: entry.fontSize, + fill: entry.color, + selectable: true, + hasControls: true, + editable: true, + borderColor: "#333", + cornerColor: "#000", + cornerSize: 12, + transparentCorners: false, + cornerStyle: "rect", + borderScaleFactor: 2, + }); + + itext.freeTextId = entry.id; + // FIX: Fabric.js appende la