document.addEventListener("DOMContentLoaded", function () { // Funzione per caricare il contenuto del popup async function loadPopupContent(iddatadb) { const popupContent = document.getElementById("popupContent"); if (!popupContent) { console.error("Elemento popupContent non trovato"); return; } try { const response = await fetch( `photos_popup.php?iddatadb=${iddatadb}`, ); if (!response.ok) throw new Error("Errore nella risposta del server"); popupContent.innerHTML = await response.text(); attachPhotoEventListeners(iddatadb); } catch (error) { popupContent.innerHTML = `
Errore durante il caricamento: ${error.message}
`; console.error("Errore in loadPopupContent:", error); } } // Funzione per gestire la webcam function setupWebcam(iddatadb) { const openWebcamBtn = document.getElementById("openWebcamBtn"); const webcamArea = document.getElementById("webcamArea"); const webcamVideo = document.getElementById("webcamVideo"); const captureBtn = document.getElementById("captureBtn"); const closeWebcamBtn = document.getElementById("closeWebcamBtn"); const webcamSelect = document.getElementById("webcamSelect"); let stream = null; if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { console.warn("La webcam non è supportata dal browser."); if (openWebcamBtn) openWebcamBtn.style.display = "none"; return; } if ( !openWebcamBtn || !webcamArea || !webcamVideo || !captureBtn || !closeWebcamBtn || !webcamSelect ) { console.error("Elementi webcam mancanti", { openWebcamBtn, webcamArea, webcamVideo, captureBtn, closeWebcamBtn, webcamSelect, }); return; } async function startWebcam(deviceId = null) { try { if (stream) { stream.getTracks().forEach((track) => track.stop()); stream = null; webcamVideo.srcObject = null; } const constraints = { video: deviceId ? { deviceId: { exact: deviceId } } : true, }; stream = await navigator.mediaDevices.getUserMedia(constraints); webcamVideo.srcObject = stream; webcamArea.style.display = "block"; openWebcamBtn.style.display = "none"; dropArea.style.display = "none"; } catch (error) { console.error("Errore nell'accesso alla webcam:", error); alert("Errore nell'accesso alla webcam: " + error.message); webcamArea.style.display = "none"; openWebcamBtn.style.display = "block"; dropArea.style.display = "block"; } } async function populateWebcamSelect() { try { await navigator.mediaDevices.getUserMedia({ video: true }); const devices = await navigator.mediaDevices.enumerateDevices(); const videoDevices = devices.filter( (device) => device.kind === "videoinput", ); webcamSelect.innerHTML = ''; videoDevices.forEach((device) => { const option = document.createElement("option"); option.value = device.deviceId; option.text = device.label || `Webcam ${webcamSelect.options.length}`; webcamSelect.appendChild(option); }); webcamSelect.style.display = videoDevices.length > 1 ? "block" : "none"; if (videoDevices.length > 0) { await startWebcam(videoDevices[0].deviceId); } else { alert("Nessuna webcam rilevata."); webcamArea.style.display = "none"; openWebcamBtn.style.display = "block"; dropArea.style.display = "block"; } } catch (error) { console.error("Errore nel recupero dei dispositivi:", error); alert("Errore nel recupero dei dispositivi: " + error.message); webcamSelect.style.display = "none"; } } openWebcamBtn.addEventListener("click", async () => { await populateWebcamSelect(); }); webcamSelect.addEventListener("change", async (e) => { const deviceId = e.target.value; if (deviceId) { await startWebcam(deviceId); } }); closeWebcamBtn.addEventListener("click", () => { if (stream) { stream.getTracks().forEach((track) => track.stop()); stream = null; webcamVideo.srcObject = null; } webcamArea.style.display = "none"; openWebcamBtn.style.display = "block"; dropArea.style.display = "block"; }); captureBtn.addEventListener("click", () => { const canvas = document.createElement("canvas"); canvas.width = webcamVideo.videoWidth; canvas.height = webcamVideo.videoHeight; canvas .getContext("2d") .drawImage(webcamVideo, 0, 0, canvas.width, canvas.height); canvas.toBlob(async (blob) => { const file = new File( [blob], `webcam_photo_${Date.now()}.jpg`, { type: "image/jpeg" }, ); const loader = document.getElementById("loader"); if (loader) { loader.style.display = "flex"; } await handleFiles([file], iddatadb); if (stream) { stream.getTracks().forEach((track) => track.stop()); stream = null; webcamVideo.srcObject = null; } webcamArea.style.display = "none"; openWebcamBtn.style.display = "block"; dropArea.style.display = "block"; }, "image/jpeg"); }); } async function handleFiles(files, iddatadb) { const loader = document.getElementById("loader"); if (!loader) { console.error("Elemento loader non trovato"); return; } if (!files || files.length === 0) { console.warn("Nessun file da caricare"); return; } for (const file of files) { if (!file.type.startsWith("image/")) { alert("Per favore, carica solo immagini!"); continue; } loader.style.display = "flex"; const formData = new FormData(); formData.append("photo", file); formData.append("iddatadb", iddatadb); try { const response = await fetch("upload_photo.php", { method: "POST", body: formData, }); const result = await response.json(); if (result.success) { loadPopupContent(iddatadb); } else { alert("Errore durante il caricamento: " + result.message); } } catch (error) { alert("Errore durante il caricamento: " + error.message); } finally { loader.style.display = "none"; } } } function attachPhotoEventListeners(iddatadb) { const dropArea = document.getElementById("dropArea"); const photoInput = document.getElementById("photoInput"); const photosModal = document.getElementById("photosModal"); if (!dropArea || !photoInput || !photosModal) { console.error("Elementi mancanti:", { dropArea, photoInput, photosModal, }); return; } const preventDefaults = (e) => { e.preventDefault(); e.stopPropagation(); }; ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { dropArea.addEventListener(eventName, preventDefaults, false); }); ["dragenter", "dragover"].forEach((eventName) => { dropArea.addEventListener( eventName, () => dropArea.classList.add("highlight"), false, ); }); ["dragleave", "drop"].forEach((eventName) => { dropArea.addEventListener( eventName, () => dropArea.classList.remove("highlight"), false, ); }); dropArea.addEventListener( "drop", (e) => { const files = e.dataTransfer.files; if (files.length > 0) { handleFiles(files, iddatadb); } }, false, ); dropArea.addEventListener( "click", () => { photoInput.click(); }, false, ); photoInput.addEventListener( "change", (e) => { const files = e.target.files; if (files.length > 0) { handleFiles(files, iddatadb); } e.target.value = ""; }, false, ); document.querySelectorAll(".delete-photo-btn").forEach((button) => { button.addEventListener("click", async function () { const photoId = this.getAttribute("data-photo-id"); if (confirm("Sei sicuro di voler eliminare questa foto?")) { try { const response = await fetch("delete_photo.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: `photo_id=${photoId}`, }); const result = await response.json(); if (result.success) { loadPopupContent(iddatadb); } else { alert( "Errore durante l'eliminazione: " + result.message, ); } } catch (error) { alert( "Errore durante l'eliminazione: " + error.message, ); } } }); }); document.querySelectorAll(".thumbnail").forEach((img) => { img.addEventListener("click", function () { const enlargedImage = document.getElementById("enlargedImage"); enlargedImage.src = this.src; document.getElementById("imageModal").style.display = "block"; }); }); const imageCloseBtn = document.querySelector(".image-modal-close"); if (imageCloseBtn) { imageCloseBtn.addEventListener("click", () => { document.getElementById("imageModal").style.display = "none"; }); } document .getElementById("imageModal") .addEventListener("click", function (event) { if (event.target === this) { this.style.display = "none"; } }); setupWebcam(iddatadb); const createCollageBtn = document.getElementById("createCollageBtn"); if (createCollageBtn) { createCollageBtn.addEventListener("click", () => { document.getElementById("collageModal").style.display = "block"; initCollageCanvas(); }); } const closeCollageBtn = document.querySelector(".close-collage"); if (closeCollageBtn) { closeCollageBtn.addEventListener("click", () => { document.getElementById("collageModal").style.display = "none"; if (isCropping) { exitCropMode(); } if (isRemovingBackground) { exitBackgroundRemovalMode(); } }); } let canvas; let cropRect = null; let isCropping = false; let croppedImage = null; let isApplyingCrop = false; let isRemovingBackground = false; let backgroundRemovalImage = null; let history = []; const maxHistory = 20; function initCollageCanvas() { if (typeof fabric === "undefined") { console.error("Fabric.js non è caricato!"); alert( "Errore: Fabric.js non è disponibile. Controlla la connessione al CDN.", ); return; } canvas = new fabric.Canvas("collageCanvas", { backgroundColor: "#fff", selection: true, }); fabric.Object.prototype.set({ cornerColor: "black", cornerStrokeColor: "black", cornerSize: 12, borderColor: "black", transparentCorners: false, }); canvas.on("object:modified", () => { saveCanvasState(); updateLayersPanel(); canvas.renderAll(); }); canvas.on("object:added", () => { updateLayersPanel(); }); canvas.on("object:removed", () => { updateLayersPanel(); }); canvas.on("selection:created", () => { updateButtons(); }); canvas.on("selection:updated", () => { updateButtons(); }); canvas.on("selection:cleared", () => { if (!isCropping && !isRemovingBackground) { updateButtons(); } else if (isCropping && cropRect) { canvas.setActiveObject(cropRect); canvas.renderAll(); } else if (isRemovingBackground) { canvas.setActiveObject(backgroundRemovalImage); canvas.renderAll(); } }); canvas.on("mouse:down", (event) => { if (isRemovingBackground && backgroundRemovalImage) { handleBackgroundColorSelection(event); } }); saveCanvasState(); updateLayersPanel(); updateButtons(); } function updateLayersPanel() { const layersList = document.getElementById("layersList"); if (!layersList) { console.error("Elemento layersList non trovato"); return; } layersList.innerHTML = ""; const images = canvas.getObjects("image"); images.forEach((img, index) => { let thumbSrc; try { const thumbCanvas = document.createElement("canvas"); thumbCanvas.width = 50; thumbCanvas.height = 50; const thumbFabric = new fabric.Canvas(thumbCanvas); const clonedImg = fabric.util.object.clone(img); const scaleFactor = Math.min( 50 / img.width, 50 / img.height, ); clonedImg.scaleX = scaleFactor; clonedImg.scaleY = scaleFactor; clonedImg.left = (50 - img.width * scaleFactor) / 2; clonedImg.top = (50 - img.height * scaleFactor) / 2; clonedImg.setCoords(); thumbFabric.add(clonedImg); thumbFabric.renderAll(); thumbSrc = thumbCanvas.toDataURL("image/png"); thumbFabric.dispose(); } catch (error) { console.warn( "Errore nella generazione della thumbnail per immagine", index + 1, error, ); thumbSrc = img.getSrc(); // Fallback all'URL originale } const layerItem = document.createElement("li"); const thumbImg = document.createElement("img"); thumbImg.src = thumbSrc; thumbImg.title = `Layer ${index + 1}`; thumbImg.addEventListener("click", () => { canvas.setActiveObject(img); canvas.renderAll(); }); layerItem.appendChild(thumbImg); layersList.appendChild(layerItem); }); } function saveCanvasState() { if (isCropping || isRemovingBackground) { return; } const state = JSON.stringify( canvas.toJSON([ "cornerColor", "cornerStrokeColor", "cornerSize", "borderColor", "transparentCorners", ]), ); history.push(state); if (history.length > maxHistory) { history.shift(); } updateButtons(); } function undo() { if (history.length <= 1) { return; } history.pop(); const previousState = history[history.length - 1]; if (previousState) { canvas.clear(); canvas.loadFromJSON(previousState, () => { canvas.renderAll(); updateLayersPanel(); updateButtons(); }); } else { console.warn("Nessuno stato precedente disponibile"); canvas.clear(); canvas.setBackgroundColor("#fff"); canvas.renderAll(); updateLayersPanel(); updateButtons(); } } function updateButtons() { const cropBtn = document.getElementById("cropImageBtn"); const applyCropBtn = document.getElementById("applyCropBtn"); const cancelCropBtn = document.getElementById("cancelCropBtn"); const removeBackgroundBtn = document.getElementById( "removeBackgroundBtn", ); const removeImageBtn = document.getElementById("removeImageBtn"); const undoBtn = document.getElementById("undoBtn"); const instruction = document.getElementById( "backgroundRemovalInstruction", ); const activeObject = canvas.getActiveObject(); if (isCropping && cropRect) { cropBtn.disabled = true; applyCropBtn.disabled = false; cancelCropBtn.disabled = false; removeBackgroundBtn.disabled = true; removeImageBtn.disabled = true; undoBtn.disabled = true; instruction.style.display = "none"; } else if (isRemovingBackground && backgroundRemovalImage) { cropBtn.disabled = true; applyCropBtn.disabled = true; cancelCropBtn.disabled = true; removeBackgroundBtn.disabled = true; removeImageBtn.disabled = true; undoBtn.disabled = true; instruction.style.display = "block"; } else if ( activeObject && activeObject.type === "image" && !isCropping && !isRemovingBackground ) { cropBtn.disabled = false; applyCropBtn.disabled = true; cancelCropBtn.disabled = true; removeBackgroundBtn.disabled = false; removeImageBtn.disabled = false; undoBtn.disabled = history.length <= 1; instruction.style.display = "none"; } else { cropBtn.disabled = true; applyCropBtn.disabled = true; cancelCropBtn.disabled = true; removeBackgroundBtn.disabled = true; removeImageBtn.disabled = true; undoBtn.disabled = history.length <= 1; instruction.style.display = "none"; } } function enterCropMode() { const activeObject = canvas.getActiveObject(); if (!activeObject || activeObject.type !== "image") { console.warn("Nessuna immagine selezionata per il ritaglio"); alert("Seleziona un'immagine prima di attivare il ritaglio!"); return; } isCropping = true; croppedImage = activeObject; canvas.discardActiveObject(); cropRect = new fabric.Rect({ left: activeObject.left, top: activeObject.top, width: activeObject.width * activeObject.scaleX * 0.5, height: activeObject.height * activeObject.scaleY * 0.5, fill: "rgba(0, 0, 0, 0.3)", stroke: "red", strokeWidth: 2, hasBorders: true, hasControls: true, lockRotation: true, selectable: true, cornerColor: "black", cornerStrokeColor: "black", cornerSize: 12, borderColor: "black", transparentCorners: false, }); canvas.add(cropRect); canvas.setActiveObject(cropRect); canvas.renderAll(); updateButtons(); } function exitCropMode() { if (cropRect) { canvas.remove(cropRect); cropRect = null; } isCropping = false; croppedImage = null; isApplyingCrop = false; canvas.discardActiveObject(); canvas.renderAll(); updateButtons(); } function applyCrop() { if (isApplyingCrop) { return; } if (!isCropping || !cropRect || !croppedImage) { console.warn("Condizioni per il ritaglio non soddisfatte", { isCropping, cropRect: !!cropRect, croppedImage: !!croppedImage, }); alert( "Nessun rettangolo di ritaglio attivo o immagine selezionata!", ); exitCropMode(); return; } isApplyingCrop = true; const img = croppedImage; const cropX = (cropRect.left - img.left) / img.scaleX; const cropY = (cropRect.top - img.top) / img.scaleY; const cropWidth = (cropRect.width * cropRect.scaleX) / img.scaleX; const cropHeight = (cropRect.height * cropRect.scaleY) / img.scaleY; fabric.Image.fromURL( img.getSrc(), (newImg) => { newImg.set({ left: cropRect.left, top: cropRect.top, scaleX: img.scaleX, scaleY: img.scaleY, cropX: cropX, cropY: cropY, width: cropWidth, height: cropHeight, hasControls: true, hasBorders: true, cornerColor: "black", cornerStrokeColor: "black", cornerSize: 12, borderColor: "black", transparentCorners: false, }); canvas.remove(img); canvas.remove(cropRect); canvas.add(newImg); canvas.setActiveObject(newImg); exitCropMode(); saveCanvasState(); updateLayersPanel(); canvas.renderAll(); }, { crossOrigin: "anonymous" }, ); } function enterBackgroundRemovalMode() { const activeObject = canvas.getActiveObject(); if (!activeObject || activeObject.type !== "image") { console.warn( "Nessuna immagine selezionata per la rimozione dello sfondo", ); alert( "Seleziona un'immagine prima di attivare la rimozione dello sfondo!", ); return; } isRemovingBackground = true; backgroundRemovalImage = activeObject; updateButtons(); } function exitBackgroundRemovalMode() { isRemovingBackground = false; backgroundRemovalImage = null; canvas.discardActiveObject(); canvas.renderAll(); updateButtons(); } function handleBackgroundColorSelection(event) { if (!isRemovingBackground || !backgroundRemovalImage) { console.warn( "Condizioni per la rimozione dello sfondo non soddisfatte", ); return; } const pointer = canvas.getPointer(event.e); const img = backgroundRemovalImage; const tempCanvas = document.createElement("canvas"); tempCanvas.width = img.width; tempCanvas.height = img.height; const ctx = tempCanvas.getContext("2d"); ctx.drawImage(img.getElement(), 0, 0, img.width, img.height); const imgLeft = img.left; const imgTop = img.top; const scaleX = img.scaleX; const scaleY = img.scaleY; const x = (pointer.x - imgLeft) / scaleX; const y = (pointer.y - imgTop) / scaleY; const pixelData = ctx.getImageData(x, y, 1, 1).data; const targetColor = { r: pixelData[0], g: pixelData[1], b: pixelData[2], }; removeBackground(img, targetColor); } function removeBackground(img, targetColor) { const tempCanvas = document.createElement("canvas"); tempCanvas.width = img.width; tempCanvas.height = img.height; const ctx = tempCanvas.getContext("2d"); ctx.drawImage(img.getElement(), 0, 0, img.width, img.height); const imageData = ctx.getImageData( 0, 0, tempCanvas.width, tempCanvas.height, ); const data = imageData.data; const tolerance = 50; for (let i = 0; i < data.length; i += 4) { const r = data[i]; const g = data[i + 1]; const b = data[i + 2]; if ( Math.abs(r - targetColor.r) <= tolerance && Math.abs(g - targetColor.g) <= tolerance && Math.abs(b - targetColor.b) <= tolerance ) { data[i + 3] = 0; } } ctx.putImageData(imageData, 0, 0); const newImageUrl = tempCanvas.toDataURL("image/png"); fabric.Image.fromURL( newImageUrl, (newImg) => { newImg.set({ left: img.left, top: img.top, scaleX: img.scaleX, scaleY: img.scaleY, hasControls: true, hasBorders: true, cornerColor: "black", cornerStrokeColor: "black", cornerSize: 12, borderColor: "black", transparentCorners: false, }); canvas.remove(img); canvas.add(newImg); canvas.setActiveObject(newImg); exitBackgroundRemovalMode(); saveCanvasState(); updateLayersPanel(); canvas.renderAll(); }, { crossOrigin: "anonymous" }, ); } function removeImage() { const activeObject = canvas.getActiveObject(); if (!activeObject || activeObject.type !== "image") { console.warn("Nessuna immagine selezionata per la rimozione"); alert("Seleziona un'immagine da rimuovere!"); return; } canvas.remove(activeObject); canvas.discardActiveObject(); saveCanvasState(); updateLayersPanel(); canvas.renderAll(); } const addToCanvasBtn = document.getElementById("addToCanvasBtn"); if (addToCanvasBtn) { addToCanvasBtn.addEventListener("click", () => { const checkboxes = document.querySelectorAll( ".photo-checkbox:checked", ); if (checkboxes.length === 0) { alert("Seleziona almeno una foto!"); return; } checkboxes.forEach((cb) => { const imgPath = cb.getAttribute("data-path"); fabric.Image.fromURL( imgPath, (img) => { img.set({ left: Math.random() * 600, top: Math.random() * 400, scaleX: 0.5, scaleY: 0.5, hasControls: true, hasBorders: true, cornerColor: "black", cornerStrokeColor: "black", cornerSize: 12, borderColor: "black", transparentCorners: false, }); canvas.add(img); canvas.renderAll(); }, { crossOrigin: "anonymous" }, ); }); checkboxes.forEach((cb) => (cb.checked = false)); saveCanvasState(); }); } const saveCollageBtn = document.getElementById("saveCollageBtn"); if (saveCollageBtn) { saveCollageBtn.addEventListener("click", async () => { if ( canvas.getObjects().length === 0 && !canvas.backgroundImage ) { alert("Il canvas è vuoto! Aggiungi almeno una foto."); return; } const dataURL = canvas.toDataURL({ format: "jpeg", quality: 0.8, }); const blob = await (await fetch(dataURL)).blob(); const file = new File([blob], `collage_${Date.now()}.jpg`, { type: "image/jpeg", }); await handleFiles([file], iddatadb); document.getElementById("collageModal").style.display = "none"; loadPopupContent(iddatadb); }); } const bringToFrontBtn = document.getElementById("bringToFrontBtn"); if (bringToFrontBtn) { bringToFrontBtn.addEventListener("click", () => { const activeObject = canvas.getActiveObject(); if (activeObject) { canvas.bringToFront(activeObject); canvas.renderAll(); saveCanvasState(); updateLayersPanel(); } else { alert("Seleziona un'immagine sul canvas!"); } }); } const sendToBackBtn = document.getElementById("sendToBackBtn"); if (sendToBackBtn) { sendToBackBtn.addEventListener("click", () => { const activeObject = canvas.getActiveObject(); if (activeObject) { canvas.sendToBack(activeObject); canvas.renderAll(); saveCanvasState(); updateLayersPanel(); } else { alert("Seleziona un'immagine sul canvas!"); } }); } const bringForwardBtn = document.getElementById("bringForwardBtn"); if (bringForwardBtn) { bringForwardBtn.addEventListener("click", () => { const activeObject = canvas.getActiveObject(); if (activeObject) { canvas.bringForward(activeObject); canvas.renderAll(); saveCanvasState(); updateLayersPanel(); } else { alert("Seleziona un'immagine sul canvas!"); } }); } const sendBackwardBtn = document.getElementById("sendBackwardBtn"); if (sendBackwardBtn) { sendBackwardBtn.addEventListener("click", () => { const activeObject = canvas.getActiveObject(); if (activeObject) { canvas.sendBackwards(activeObject); canvas.renderAll(); saveCanvasState(); updateLayersPanel(); } else { alert("Seleziona un'immagine sul canvas!"); } }); } const cropImageBtn = document.getElementById("cropImageBtn"); if (cropImageBtn) { cropImageBtn.addEventListener("click", () => { enterCropMode(); }); } const applyCropBtn = document.getElementById("applyCropBtn"); if (applyCropBtn) { applyCropBtn.addEventListener("click", () => { applyCrop(); }); } const cancelCropBtn = document.getElementById("cancelCropBtn"); if (cancelCropBtn) { cancelCropBtn.addEventListener("click", () => { exitCropMode(); }); } const removeBackgroundBtn = document.getElementById( "removeBackgroundBtn", ); if (removeBackgroundBtn) { removeBackgroundBtn.addEventListener("click", () => { enterBackgroundRemovalMode(); }); } const removeImageBtn = document.getElementById("removeImageBtn"); if (removeImageBtn) { removeImageBtn.addEventListener("click", () => { removeImage(); }); } const undoBtn = document.getElementById("undoBtn"); if (undoBtn) { undoBtn.addEventListener("click", () => { undo(); }); } const loader = document.getElementById("loader"); if (loader) { loader.style.display = "none"; } } const photosButtons = document.querySelectorAll(".photos-btn"); const photosModal = document.getElementById("photosModal"); const closeBtn = document.querySelector(".close-btn"); if (photosButtons.length && photosModal && closeBtn) { photosButtons.forEach((button) => { button.addEventListener("click", function () { const iddatadb = this.getAttribute("data-iddatadb"); loadPopupContent(iddatadb); photosModal.style.display = "block"; document.querySelector(".overlay").style.display = "none"; }); }); closeBtn.addEventListener("click", function () { photosModal.style.display = "none"; document.querySelector(".overlay").style.display = "none"; document.body.style.pointerEvents = "auto"; }); window.addEventListener("click", function (event) { if (event.target === photosModal) { photosModal.style.display = "none"; document.querySelector(".overlay").style.display = "none"; document.body.style.pointerEvents = "auto"; } }); } else { console.error("Elementi mancanti:", { photosButtons, photosModal, closeBtn, }); } });