DrawFlow - Application de dessin
×
ing); canvas.addEventListener('mousemove', draw); canvas.addEventListener('mouseup', stopDrawing); canvas.addEventListener('mouseout', stopDrawing); canvas.addEventListener('touchstart', startDrawing, {passive: false}); canvas.addEventListener('touchmove', draw, {passive: false}); canvas.addEventListener('touchend', stopDrawing); canvas.addEventListener('wheel', (e) => { e.preventDefault(); const coords = getEventCoords(e); const delta = e.deltaY > 0 ? 0.9 : 1.1; const newScale = Math.min(Math.max(0.1, scale * delta), 5); offsetX = coords.x - (coords.x - offsetX) * (newScale / scale); offsetY = coords.y - (coords.y - offsetY) * (newScale / scale); scale = newScale; redrawCanvas(); }, {passive: false}); canvas.addEventListener('touchstart', (e) => { if (e.touches.length === 2) { const touch1 = e.touches[0], touch2 = e.touches[1]; lastTouchDistance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY); } }); canvas.addEventListener('touchmove', (e) => { if (e.touches.length === 2) { e.preventDefault(); const touch1 = e.touches[0], touch2 = e.touches[1]; const distance = Math.hypot(touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY); if (lastTouchDistance > 0) { const delta = distance / lastTouchDistance; const rect = canvas.getBoundingClientRect(); const centerX = ((touch1.clientX + touch2.clientX) / 2) - rect.left; const centerY = ((touch1.clientY + touch2.clientY) / 2) - rect.top; const newScale = Math.min(Math.max(0.1, scale * delta), 5); offsetX = centerX - (centerX - offsetX) * (newScale / scale); offsetY = centerY - (centerY - offsetY) * (newScale / scale); scale = newScale; redrawCanvas(); } lastTouchDistance = distance; } }, {passive: false}); canvas.addEventListener('touchend', (e) => { if (e.touches.length < 2) lastTouchDistance = 0; }); document.addEventListener('click', (e) => { if (!e.target.closest('.popup-menu') && !e.target.closest('.toolbar-btn')) { closeAllMenus(); } }); document.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { if (e.key === 'z') { e.preventDefault(); e.shiftKey ? redo() : undo(); } else if (e.key === 'c') { e.preventDefault(); clipboard = JSON.parse(JSON.stringify(selectedObjects, (k, v) => k === 'img' ? undefined : v)); } else if (e.key === 'v') { e.preventDefault(); if (clipboard.length > 0) { const newObjects = []; for (let obj of clipboard) { const newObj = JSON.parse(JSON.stringify(obj)); newObj.x += 20; newObj.y += 20; if (newObj.controlPoints) { for (let cp of newObj.controlPoints) { cp.x += 20; cp.y += 20; } } shapes.push(newObj); newObjects.push(newObj); } selectedObjects = newObjects; saveHistory(); redrawCanvas(); } } else if (e.key === 'd') { e.preventDefault(); duplicate(); } else if (e.key === 'a') { e.preventDefault(); selectedObjects = [...shapes]; redrawCanvas(); } } else if (e.key === 'Delete' || e.key === 'Backspace') { e.preventDefault(); if (selectedObjects.length > 0) { for (let obj of selectedObjects) { const idx = shapes.indexOf(obj); if (idx > -1) shapes.splice(idx, 1); } selectedObjects = []; saveHistory(); redrawCanvas(); } } else if (e.key === 'Escape') { selectedObjects = []; currentShape = null; redrawCanvas(); } }); window.addEventListener('beforeunload', () => { saveToLocalStorage(); }); initPages(); initWebcamHandlers();