File size: 2,750 Bytes
3d7d9b5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import React, { useState } from "react";
import { AnnotationPath } from "../types";
import { useAppStore } from "../store";
export const AnnotationNode = ({ ann }: { ann: AnnotationPath }) => {
const {
zoom,
selectedNodeIds,
setSelectedNodeIds,
updateSelectedNodes,
isAnnotationMode,
isClickThrough,
annotations,
images,
textNotes,
} = useAppStore();
const [isDragging, setIsDragging] = useState(false);
const isSelected = selectedNodeIds.includes(ann.id);
const handlePointerDown = (e: React.PointerEvent) => {
if (isAnnotationMode || isClickThrough) return;
if (!isSelected) {
let idsToSelect = [ann.id];
if (ann.groupId) {
const groupAnnotations = annotations
.filter((a) => a.groupId === ann.groupId)
.map((a) => a.id);
const groupImages = images
.filter((i) => i.groupId === ann.groupId)
.map((i) => i.id);
const groupNotes = textNotes
.filter((n) => n.groupId === ann.groupId)
.map((n) => n.id);
idsToSelect = [...groupAnnotations, ...groupImages, ...groupNotes];
}
if (e.shiftKey) {
setSelectedNodeIds(
Array.from(new Set([...selectedNodeIds, ...idsToSelect])),
);
} else {
setSelectedNodeIds(idsToSelect);
}
}
setIsDragging(true);
e.currentTarget.setPointerCapture(e.pointerId);
};
const handlePointerMove = (e: React.PointerEvent) => {
if (isDragging) {
e.stopPropagation();
updateSelectedNodes(e.movementX / zoom, e.movementY / zoom, ann.id);
}
};
const handlePointerUp = (e: React.PointerEvent) => {
if (isDragging) {
setIsDragging(false);
e.currentTarget.releasePointerCapture(e.pointerId);
e.stopPropagation();
}
};
return (
<polyline
points={ann.points.map((p) => `${p.x},${p.y}`).join(" ")}
fill="none"
stroke={isSelected ? "#0A84FF" : ann.color}
strokeWidth={
ann.strokeWidth * zoom * (ann.isHighlighter ? 3 : 1) +
(isSelected ? 2 : 0)
}
strokeLinecap={ann.isHighlighter ? "square" : "round"}
strokeLinejoin={ann.isHighlighter ? "miter" : "round"}
opacity={ann.isHighlighter ? 0.4 : 1}
style={{
...(ann.isHighlighter ? { mixBlendMode: "screen" } : {}),
pointerEvents: isAnnotationMode || isClickThrough ? "none" : "stroke",
cursor: "default",
}}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
onDoubleClick={(e) => {
e.stopPropagation();
}}
/>
);
};
|