drawing-model / src /app /handleMouse.js
qtitpc's picture
Upload 23 files
91c8a81 verified
Raw
History Blame Contribute Delete
7.65 kB
import { createElement, getElementAtPosition, adjustElementCoordinates, cursorForPosition, resizedCoordinates, adjustmentRequired } from './element-utils';
export const createMouseHandlers = ({
action,
setAction,
tool,
setTool,
elements,
setElements,
selectedElement,
setSelectedElement,
panOffset,
setPanOffset,
scale,
scaleOffset,
startPanMousePosition,
setStartPanMousePosition,
pressedKeys,
pencilSize,
setCaptureArea,
isDrawing,
setIsDrawing
}) => {
const getMouseCoordinates = event => {
const clientX = (event.clientX - panOffset.x * scale + scaleOffset.x) / scale;
const clientY = (event.clientY - panOffset.y * scale + scaleOffset.y) / scale;
return { clientX, clientY };
};
const updateElement = (id, x1, y1, x2, y2, type, options) => {
const elementsCopy = [...elements];
switch (type) {
case "line":
case "rectangle":
elementsCopy[id] = createElement(id, x1, y1, x2, y2, type);
elementsCopy[id].size = pencilSize;
break;
case "pencil":
elementsCopy[id].points = [...elementsCopy[id].points, { x: x2, y: y2 }];
break;
case "text":
const textWidth = document
.getElementById("canvas")
.getContext("2d")
.measureText(options.text).width;
const textHeight = 24;
elementsCopy[id] = {
...createElement(id, x1, y1, x1 + textWidth, y1 + textHeight, type),
text: options.text,
};
break;
default:
throw new Error(`Type not recognised: ${type}`);
}
setElements(elementsCopy, true);
};
const handleMouseDown = event => {
if (action === "writing") return;
const { clientX, clientY } = getMouseCoordinates(event);
if (event.button === 1 || pressedKeys.has(" ")) {
setAction("panning");
setStartPanMousePosition({ x: clientX, y: clientY });
return;
}
setIsDrawing(true);
if (tool === "capture") {
const id = elements.length;
const element = createElement(id, clientX, clientY, clientX, clientY, "capture");
setElements(prevState => [...prevState, element]);
setSelectedElement(element);
setAction("drawing");
return;
}
if (tool === "eraser") {
setAction("erasing");
const elementToErase = getElementAtPosition(clientX, clientY, elements);
if (elementToErase) {
setElements(prevState =>
prevState.filter(el => el.id !== elementToErase.id)
);
}
return;
}
if (tool === "selection") {
const element = getElementAtPosition(clientX, clientY, elements);
if (element) {
if (element.type === "pencil") {
const xOffsets = element.points.map(point => clientX - point.x);
const yOffsets = element.points.map(point => clientY - point.y);
setSelectedElement({ ...element, xOffsets, yOffsets });
} else {
const offsetX = clientX - element.x1;
const offsetY = clientY - element.y1;
setSelectedElement({ ...element, offsetX, offsetY });
}
setElements(prevState => prevState);
if (element.position === "inside") {
setAction("moving");
} else {
setAction("resizing");
}
}
} else {
const id = elements.length;
const element = createElement(id, clientX, clientY, clientX, clientY, tool, pencilSize);
setElements(prevState => [...prevState, element]);
setSelectedElement(element);
setAction(tool === "text" ? "writing" : "drawing");
}
};
const handleMouseMove = event => {
const { clientX, clientY } = getMouseCoordinates(event);
if (action === "panning") {
const deltaX = clientX - startPanMousePosition.x;
const deltaY = clientY - startPanMousePosition.y;
setPanOffset({
x: panOffset.x + deltaX,
y: panOffset.y + deltaY,
});
return;
}
if (action === "erasing") {
const elementToErase = getElementAtPosition(clientX, clientY, elements);
if (elementToErase) {
setElements(prevState =>
prevState.filter(el => el.id !== elementToErase.id)
);
}
return;
}
if (tool === "selection") {
const element = getElementAtPosition(clientX, clientY, elements);
event.target.style.cursor = element ? cursorForPosition(element.position) : "default";
}
if (action === "drawing") {
const index = elements.length - 1;
const { x1, y1 } = elements[index];
if (tool === "capture") {
const element = elements[index];
const updatedElement = {
...element,
x2: clientX,
y2: clientY
};
const elementsCopy = [...elements];
elementsCopy[index] = updatedElement;
setElements(elementsCopy, true);
setCaptureArea(updatedElement);
} else {
updateElement(index, x1, y1, clientX, clientY, tool);
}
} else if (action === "moving") {
if (selectedElement.type === "pencil") {
const newPoints = selectedElement.points.map((_, index) => ({
x: clientX - selectedElement.xOffsets[index],
y: clientY - selectedElement.yOffsets[index],
}));
const elementsCopy = [...elements];
elementsCopy[selectedElement.id] = {
...elementsCopy[selectedElement.id],
points: newPoints,
};
setElements(elementsCopy, true);
} else {
const { id, x1, x2, y1, y2, type, offsetX, offsetY } = selectedElement;
const width = x2 - x1;
const height = y2 - y1;
const newX1 = clientX - offsetX;
const newY1 = clientY - offsetY;
const options = type === "text" ? { text: selectedElement.text } : {};
updateElement(id, newX1, newY1, newX1 + width, newY1 + height, type, options);
}
} else if (action === "resizing") {
const { id, type, position, ...coordinates } = selectedElement;
const { x1, y1, x2, y2 } = resizedCoordinates(clientX, clientY, position, coordinates);
updateElement(id, x1, y1, x2, y2, type);
}
};
const handleMouseUp = event => {
setIsDrawing(false);
const { clientX, clientY } = getMouseCoordinates(event);
if (selectedElement) {
if (
selectedElement.type === "text" &&
clientX - selectedElement.offsetX === selectedElement.x1 &&
clientY - selectedElement.offsetY === selectedElement.y1
) {
setAction("writing");
return;
}
const index = selectedElement.id;
const { id, type } = elements[index];
if ((action === "drawing" || action === "resizing") && adjustmentRequired(type)) {
const { x1, y1, x2, y2 } = adjustElementCoordinates(elements[index]);
updateElement(id, x1, y1, x2, y2, type);
}
}
if (action === "drawing") {
console.log("Hoàn thành một nét vẽ");
}
if (action === "writing") return;
setAction("none");
setSelectedElement(null);
};
const handleBlur = event => {
const { id, x1, y1, type } = selectedElement;
setAction("none");
setSelectedElement(null);
updateElement(id, x1, y1, null, null, type, { text: event.target.value });
};
return {
handleMouseDown,
handleMouseMove,
handleMouseUp,
handleBlur
};
};