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();