mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-26 02:40:44 -06:00
Zone/mask editor improvements (#11236)
* add points to completed polygons in zone/mask editor * change line order so edges are more easily clickable
This commit is contained in:
parent
f0054ceba4
commit
51dcdd6f4b
@ -629,6 +629,7 @@ export default function MasksAndZones({
|
|||||||
scaledHeight &&
|
scaledHeight &&
|
||||||
editingPolygons ? (
|
editingPolygons ? (
|
||||||
<PolygonCanvas
|
<PolygonCanvas
|
||||||
|
containerRef={containerRef}
|
||||||
camera={cameraConfig.name}
|
camera={cameraConfig.name}
|
||||||
width={scaledWidth}
|
width={scaledWidth}
|
||||||
height={scaledHeight}
|
height={scaledHeight}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo, useRef, useState, useEffect } from "react";
|
import React, { useMemo, useRef, useState, useEffect, RefObject } from "react";
|
||||||
import PolygonDrawer from "./PolygonDrawer";
|
import PolygonDrawer from "./PolygonDrawer";
|
||||||
import { Stage, Layer, Image } from "react-konva";
|
import { Stage, Layer, Image } from "react-konva";
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
@ -7,6 +7,7 @@ import { Polygon, PolygonType } from "@/types/canvas";
|
|||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
|
|
||||||
type PolygonCanvasProps = {
|
type PolygonCanvasProps = {
|
||||||
|
containerRef: RefObject<HTMLDivElement>;
|
||||||
camera: string;
|
camera: string;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@ -18,6 +19,7 @@ type PolygonCanvasProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function PolygonCanvas({
|
export function PolygonCanvas({
|
||||||
|
containerRef,
|
||||||
camera,
|
camera,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@ -55,10 +57,6 @@ export function PolygonCanvas({
|
|||||||
};
|
};
|
||||||
}, [videoElement]);
|
}, [videoElement]);
|
||||||
|
|
||||||
const getMousePos = (stage: Konva.Stage) => {
|
|
||||||
return [stage.getPointerPosition()!.x, stage.getPointerPosition()!.y];
|
|
||||||
};
|
|
||||||
|
|
||||||
const addPointToPolygon = (polygon: Polygon, newPoint: number[]) => {
|
const addPointToPolygon = (polygon: Polygon, newPoint: number[]) => {
|
||||||
const points = polygon.points;
|
const points = polygon.points;
|
||||||
const pointsOrder = polygon.pointsOrder;
|
const pointsOrder = polygon.pointsOrder;
|
||||||
@ -99,37 +97,6 @@ export function PolygonCanvas({
|
|||||||
return { updatedPoints, updatedPointsOrder };
|
return { updatedPoints, updatedPointsOrder };
|
||||||
};
|
};
|
||||||
|
|
||||||
const isMouseOverFirstPoint = (polygon: Polygon, mousePos: number[]) => {
|
|
||||||
if (!polygon || !polygon.points || polygon.points.length < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const [firstPoint] = polygon.points;
|
|
||||||
const distance = Math.hypot(
|
|
||||||
mousePos[0] - firstPoint[0],
|
|
||||||
mousePos[1] - firstPoint[1],
|
|
||||||
);
|
|
||||||
return distance < 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMouseOverAnyPoint = (polygon: Polygon, mousePos: number[]) => {
|
|
||||||
if (!polygon || !polygon.points || polygon.points.length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 1; i < polygon.points.length; i++) {
|
|
||||||
const point = polygon.points[i];
|
|
||||||
const distance = Math.hypot(
|
|
||||||
mousePos[0] - point[0],
|
|
||||||
mousePos[1] - point[1],
|
|
||||||
);
|
|
||||||
if (distance < 10) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseDown = (e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
const handleMouseDown = (e: KonvaEventObject<MouseEvent | TouchEvent>) => {
|
||||||
if (activePolygonIndex === undefined || !polygons) {
|
if (activePolygonIndex === undefined || !polygons) {
|
||||||
return;
|
return;
|
||||||
@ -138,11 +105,13 @@ export function PolygonCanvas({
|
|||||||
const updatedPolygons = [...polygons];
|
const updatedPolygons = [...polygons];
|
||||||
const activePolygon = updatedPolygons[activePolygonIndex];
|
const activePolygon = updatedPolygons[activePolygonIndex];
|
||||||
const stage = e.target.getStage()!;
|
const stage = e.target.getStage()!;
|
||||||
const mousePos = getMousePos(stage);
|
const mousePos = stage.getPointerPosition() ?? { x: 0, y: 0 };
|
||||||
|
const intersection = stage.getIntersection(mousePos);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
activePolygon.points.length >= 3 &&
|
activePolygon.points.length >= 3 &&
|
||||||
isMouseOverFirstPoint(activePolygon, mousePos)
|
intersection?.getClassName() == "Circle" &&
|
||||||
|
intersection?.name() == "point-0"
|
||||||
) {
|
) {
|
||||||
// Close the polygon
|
// Close the polygon
|
||||||
updatedPolygons[activePolygonIndex] = {
|
updatedPolygons[activePolygonIndex] = {
|
||||||
@ -152,12 +121,13 @@ export function PolygonCanvas({
|
|||||||
setPolygons(updatedPolygons);
|
setPolygons(updatedPolygons);
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
!activePolygon.isFinished &&
|
(!activePolygon.isFinished &&
|
||||||
!isMouseOverAnyPoint(activePolygon, mousePos)
|
intersection?.getClassName() !== "Circle") ||
|
||||||
|
(activePolygon.isFinished && intersection?.name() == "unfilled-line")
|
||||||
) {
|
) {
|
||||||
const { updatedPoints, updatedPointsOrder } = addPointToPolygon(
|
const { updatedPoints, updatedPointsOrder } = addPointToPolygon(
|
||||||
activePolygon,
|
activePolygon,
|
||||||
mousePos,
|
[mousePos.x, mousePos.y],
|
||||||
);
|
);
|
||||||
|
|
||||||
updatedPolygons[activePolygonIndex] = {
|
updatedPolygons[activePolygonIndex] = {
|
||||||
@ -168,62 +138,6 @@ export function PolygonCanvas({
|
|||||||
setPolygons(updatedPolygons);
|
setPolygons(updatedPolygons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseOverStartPoint = (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => {
|
|
||||||
if (activePolygonIndex === undefined || !polygons) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activePolygon = polygons[activePolygonIndex];
|
|
||||||
if (!activePolygon.isFinished && activePolygon.points.length >= 3) {
|
|
||||||
e.target.getStage()!.container().style.cursor = "default";
|
|
||||||
e.currentTarget.scale({ x: 2, y: 2 });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseOutStartPoint = (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => {
|
|
||||||
e.currentTarget.scale({ x: 1, y: 1 });
|
|
||||||
|
|
||||||
if (activePolygonIndex === undefined || !polygons) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activePolygon = polygons[activePolygonIndex];
|
|
||||||
if (
|
|
||||||
(!activePolygon.isFinished && activePolygon.points.length >= 3) ||
|
|
||||||
activePolygon.isFinished
|
|
||||||
) {
|
|
||||||
e.currentTarget.scale({ x: 1, y: 1 });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseOverAnyPoint = (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => {
|
|
||||||
if (!polygons) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.target.getStage()!.container().style.cursor = "move";
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseOutAnyPoint = (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => {
|
|
||||||
if (activePolygonIndex === undefined || !polygons) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const activePolygon = polygons[activePolygonIndex];
|
|
||||||
if (activePolygon.isFinished) {
|
|
||||||
e.target.getStage()!.container().style.cursor = "default";
|
|
||||||
} else {
|
|
||||||
e.target.getStage()!.container().style.cursor = "crosshair";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePointDragMove = (
|
const handlePointDragMove = (
|
||||||
@ -237,7 +151,8 @@ export function PolygonCanvas({
|
|||||||
const activePolygon = updatedPolygons[activePolygonIndex];
|
const activePolygon = updatedPolygons[activePolygonIndex];
|
||||||
const stage = e.target.getStage();
|
const stage = e.target.getStage();
|
||||||
if (stage) {
|
if (stage) {
|
||||||
const index = e.target.index - 1;
|
// we add an unfilled line for adding points when finished
|
||||||
|
const index = e.target.index - (activePolygon.isFinished ? 2 : 1);
|
||||||
const pos = [e.target._lastPos!.x, e.target._lastPos!.y];
|
const pos = [e.target._lastPos!.x, e.target._lastPos!.y];
|
||||||
if (pos[0] < 0) pos[0] = 0;
|
if (pos[0] < 0) pos[0] = 0;
|
||||||
if (pos[1] < 0) pos[1] = 0;
|
if (pos[1] < 0) pos[1] = 0;
|
||||||
@ -272,26 +187,17 @@ export function PolygonCanvas({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStageMouseOver = (
|
const handleStageMouseOver = () => {
|
||||||
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => {
|
|
||||||
if (activePolygonIndex === undefined || !polygons) {
|
if (activePolygonIndex === undefined || !polygons) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedPolygons = [...polygons];
|
const updatedPolygons = [...polygons];
|
||||||
const activePolygon = updatedPolygons[activePolygonIndex];
|
const activePolygon = updatedPolygons[activePolygonIndex];
|
||||||
const stage = e.target.getStage()!;
|
|
||||||
const mousePos = getMousePos(stage);
|
|
||||||
|
|
||||||
if (
|
if (containerRef.current && !activePolygon.isFinished) {
|
||||||
activePolygon.isFinished ||
|
containerRef.current.style.cursor = "crosshair";
|
||||||
isMouseOverAnyPoint(activePolygon, mousePos) ||
|
}
|
||||||
isMouseOverFirstPoint(activePolygon, mousePos)
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
e.target.getStage()!.container().style.cursor = "crosshair";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -336,6 +242,7 @@ export function PolygonCanvas({
|
|||||||
selectedZoneMask.includes(polygon.type)) &&
|
selectedZoneMask.includes(polygon.type)) &&
|
||||||
index !== activePolygonIndex && (
|
index !== activePolygonIndex && (
|
||||||
<PolygonDrawer
|
<PolygonDrawer
|
||||||
|
stageRef={stageRef}
|
||||||
key={index}
|
key={index}
|
||||||
points={polygon.points}
|
points={polygon.points}
|
||||||
isActive={index === activePolygonIndex}
|
isActive={index === activePolygonIndex}
|
||||||
@ -344,10 +251,6 @@ export function PolygonCanvas({
|
|||||||
color={polygon.color}
|
color={polygon.color}
|
||||||
handlePointDragMove={handlePointDragMove}
|
handlePointDragMove={handlePointDragMove}
|
||||||
handleGroupDragEnd={handleGroupDragEnd}
|
handleGroupDragEnd={handleGroupDragEnd}
|
||||||
handleMouseOverStartPoint={handleMouseOverStartPoint}
|
|
||||||
handleMouseOutStartPoint={handleMouseOutStartPoint}
|
|
||||||
handleMouseOverAnyPoint={handleMouseOverAnyPoint}
|
|
||||||
handleMouseOutAnyPoint={handleMouseOutAnyPoint}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
@ -356,6 +259,7 @@ export function PolygonCanvas({
|
|||||||
(selectedZoneMask === undefined ||
|
(selectedZoneMask === undefined ||
|
||||||
selectedZoneMask.includes(polygons[activePolygonIndex].type)) && (
|
selectedZoneMask.includes(polygons[activePolygonIndex].type)) && (
|
||||||
<PolygonDrawer
|
<PolygonDrawer
|
||||||
|
stageRef={stageRef}
|
||||||
key={activePolygonIndex}
|
key={activePolygonIndex}
|
||||||
points={polygons[activePolygonIndex].points}
|
points={polygons[activePolygonIndex].points}
|
||||||
isActive={true}
|
isActive={true}
|
||||||
@ -364,10 +268,6 @@ export function PolygonCanvas({
|
|||||||
color={polygons[activePolygonIndex].color}
|
color={polygons[activePolygonIndex].color}
|
||||||
handlePointDragMove={handlePointDragMove}
|
handlePointDragMove={handlePointDragMove}
|
||||||
handleGroupDragEnd={handleGroupDragEnd}
|
handleGroupDragEnd={handleGroupDragEnd}
|
||||||
handleMouseOverStartPoint={handleMouseOverStartPoint}
|
|
||||||
handleMouseOutStartPoint={handleMouseOutStartPoint}
|
|
||||||
handleMouseOverAnyPoint={handleMouseOverAnyPoint}
|
|
||||||
handleMouseOutAnyPoint={handleMouseOutAnyPoint}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Layer>
|
</Layer>
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { useCallback, useMemo, useRef, useState } from "react";
|
import {
|
||||||
|
RefObject,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { Line, Circle, Group } from "react-konva";
|
import { Line, Circle, Group } from "react-konva";
|
||||||
import {
|
import {
|
||||||
minMax,
|
minMax,
|
||||||
@ -9,9 +16,9 @@ import {
|
|||||||
import type { KonvaEventObject } from "konva/lib/Node";
|
import type { KonvaEventObject } from "konva/lib/Node";
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
import { Vector2d } from "konva/lib/types";
|
import { Vector2d } from "konva/lib/types";
|
||||||
import { isMobileOnly } from "react-device-detect";
|
|
||||||
|
|
||||||
type PolygonDrawerProps = {
|
type PolygonDrawerProps = {
|
||||||
|
stageRef: RefObject<Konva.Stage>;
|
||||||
points: number[][];
|
points: number[][];
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
isHovered: boolean;
|
isHovered: boolean;
|
||||||
@ -19,21 +26,10 @@ type PolygonDrawerProps = {
|
|||||||
color: number[];
|
color: number[];
|
||||||
handlePointDragMove: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
handlePointDragMove: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
||||||
handleGroupDragEnd: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
handleGroupDragEnd: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
||||||
handleMouseOverStartPoint: (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => void;
|
|
||||||
handleMouseOutStartPoint: (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => void;
|
|
||||||
handleMouseOverAnyPoint: (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => void;
|
|
||||||
handleMouseOutAnyPoint: (
|
|
||||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PolygonDrawer({
|
export default function PolygonDrawer({
|
||||||
|
stageRef,
|
||||||
points,
|
points,
|
||||||
isActive,
|
isActive,
|
||||||
isHovered,
|
isHovered,
|
||||||
@ -41,31 +37,41 @@ export default function PolygonDrawer({
|
|||||||
color,
|
color,
|
||||||
handlePointDragMove,
|
handlePointDragMove,
|
||||||
handleGroupDragEnd,
|
handleGroupDragEnd,
|
||||||
handleMouseOverStartPoint,
|
|
||||||
handleMouseOutStartPoint,
|
|
||||||
handleMouseOverAnyPoint,
|
|
||||||
handleMouseOutAnyPoint,
|
|
||||||
}: PolygonDrawerProps) {
|
}: PolygonDrawerProps) {
|
||||||
const vertexRadius = isMobileOnly ? 12 : 6;
|
const vertexRadius = 6;
|
||||||
const flattenedPoints = useMemo(() => flattenPoints(points), [points]);
|
const flattenedPoints = useMemo(() => flattenPoints(points), [points]);
|
||||||
const [stage, setStage] = useState<Konva.Stage>();
|
|
||||||
const [minMaxX, setMinMaxX] = useState([0, 0]);
|
const [minMaxX, setMinMaxX] = useState([0, 0]);
|
||||||
const [minMaxY, setMinMaxY] = useState([0, 0]);
|
const [minMaxY, setMinMaxY] = useState([0, 0]);
|
||||||
const groupRef = useRef<Konva.Group>(null);
|
const groupRef = useRef<Konva.Group>(null);
|
||||||
|
const [cursor, setCursor] = useState("default");
|
||||||
|
|
||||||
const handleGroupMouseOver = (
|
const handleMouseOverPoint = (
|
||||||
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
|
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||||
) => {
|
) => {
|
||||||
if (!isFinished) return;
|
if (!e.target) return;
|
||||||
e.target.getStage()!.container().style.cursor = "move";
|
|
||||||
setStage(e.target.getStage()!);
|
if (!isFinished && points.length >= 3 && e.target.name() === "point-0") {
|
||||||
|
e.target.scale({ x: 2, y: 2 });
|
||||||
|
setCursor("crosshair");
|
||||||
|
} else {
|
||||||
|
setCursor("move");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGroupMouseOut = (
|
const handleMouseOutPoint = (
|
||||||
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
|
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||||
) => {
|
) => {
|
||||||
if (!e.target || !isFinished) return;
|
if (!e.target) return;
|
||||||
e.target.getStage()!.container().style.cursor = "default";
|
|
||||||
|
if (isFinished) {
|
||||||
|
setCursor("default");
|
||||||
|
} else {
|
||||||
|
setCursor("crosshair");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.target.name() === "point-0") {
|
||||||
|
e.target.scale({ x: 1, y: 1 });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGroupDragStart = () => {
|
const handleGroupDragStart = () => {
|
||||||
@ -76,13 +82,13 @@ export default function PolygonDrawer({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const groupDragBound = (pos: Vector2d) => {
|
const groupDragBound = (pos: Vector2d) => {
|
||||||
if (!stage) {
|
if (!stageRef.current) {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { x, y } = pos;
|
let { x, y } = pos;
|
||||||
const sw = stage.width();
|
const sw = stageRef.current.width();
|
||||||
const sh = stage.height();
|
const sh = stageRef.current.height();
|
||||||
|
|
||||||
if (minMaxY[0] + y < 0) y = -1 * minMaxY[0];
|
if (minMaxY[0] + y < 0) y = -1 * minMaxY[0];
|
||||||
if (minMaxX[0] + x < 0) x = -1 * minMaxX[0];
|
if (minMaxX[0] + x < 0) x = -1 * minMaxX[0];
|
||||||
@ -99,6 +105,14 @@ export default function PolygonDrawer({
|
|||||||
[color],
|
[color],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!stageRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stageRef.current.container().style.cursor = cursor;
|
||||||
|
}, [stageRef, cursor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group
|
<Group
|
||||||
name="polygon"
|
name="polygon"
|
||||||
@ -107,55 +121,62 @@ export default function PolygonDrawer({
|
|||||||
onDragStart={isActive ? handleGroupDragStart : undefined}
|
onDragStart={isActive ? handleGroupDragStart : undefined}
|
||||||
onDragEnd={isActive ? handleGroupDragEnd : undefined}
|
onDragEnd={isActive ? handleGroupDragEnd : undefined}
|
||||||
dragBoundFunc={isActive ? groupDragBound : undefined}
|
dragBoundFunc={isActive ? groupDragBound : undefined}
|
||||||
onMouseOver={isActive ? handleGroupMouseOver : undefined}
|
|
||||||
onTouchStart={isActive ? handleGroupMouseOver : undefined}
|
|
||||||
onMouseOut={isActive ? handleGroupMouseOut : undefined}
|
|
||||||
>
|
>
|
||||||
<Line
|
<Line
|
||||||
|
name="filled-line"
|
||||||
points={flattenedPoints}
|
points={flattenedPoints}
|
||||||
stroke={colorString(true)}
|
stroke={colorString(true)}
|
||||||
strokeWidth={3}
|
strokeWidth={3}
|
||||||
|
hitStrokeWidth={12}
|
||||||
closed={isFinished}
|
closed={isFinished}
|
||||||
fill={colorString(isActive || isHovered ? true : false)}
|
fill={colorString(isActive || isHovered ? true : false)}
|
||||||
|
onMouseOver={() =>
|
||||||
|
isFinished ? setCursor("move") : setCursor("crosshair")
|
||||||
|
}
|
||||||
|
onMouseOut={() =>
|
||||||
|
isFinished ? setCursor("default") : setCursor("crosshair")
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
{isFinished && isActive && (
|
||||||
|
<Line
|
||||||
|
name="unfilled-line"
|
||||||
|
points={flattenedPoints}
|
||||||
|
hitStrokeWidth={12}
|
||||||
|
closed={isFinished}
|
||||||
|
fillEnabled={false}
|
||||||
|
onMouseOver={() => setCursor("crosshair")}
|
||||||
|
onMouseOut={() =>
|
||||||
|
isFinished ? setCursor("default") : setCursor("crosshair")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{points.map((point, index) => {
|
{points.map((point, index) => {
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const x = point[0];
|
const x = point[0];
|
||||||
const y = point[1];
|
const y = point[1];
|
||||||
const startPointAttr =
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
hitStrokeWidth: 12,
|
|
||||||
onMouseOver: handleMouseOverStartPoint,
|
|
||||||
onMouseOut: handleMouseOutStartPoint,
|
|
||||||
}
|
|
||||||
: null;
|
|
||||||
const otherPointsAttr =
|
|
||||||
index !== 0
|
|
||||||
? {
|
|
||||||
onMouseOver: handleMouseOverAnyPoint,
|
|
||||||
onMouseOut: handleMouseOutAnyPoint,
|
|
||||||
}
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Circle
|
<Circle
|
||||||
key={index}
|
key={index}
|
||||||
|
name={`point-${index}`}
|
||||||
x={x}
|
x={x}
|
||||||
y={y}
|
y={y}
|
||||||
radius={vertexRadius}
|
radius={vertexRadius}
|
||||||
stroke={colorString(true)}
|
stroke={colorString(true)}
|
||||||
fill="#ffffff"
|
fill="#ffffff"
|
||||||
strokeWidth={3}
|
strokeWidth={3}
|
||||||
|
hitStrokeWidth={index === 0 ? 12 : 9}
|
||||||
|
onMouseOver={handleMouseOverPoint}
|
||||||
|
onMouseOut={handleMouseOutPoint}
|
||||||
draggable={isActive}
|
draggable={isActive}
|
||||||
onDragMove={isActive ? handlePointDragMove : undefined}
|
onDragMove={isActive ? handlePointDragMove : undefined}
|
||||||
dragBoundFunc={(pos) => {
|
dragBoundFunc={(pos) => {
|
||||||
if (stage) {
|
if (stageRef.current) {
|
||||||
return dragBoundFunc(
|
return dragBoundFunc(
|
||||||
stage.width(),
|
stageRef.current.width(),
|
||||||
stage.height(),
|
stageRef.current.height(),
|
||||||
vertexRadius,
|
vertexRadius,
|
||||||
pos,
|
pos,
|
||||||
);
|
);
|
||||||
@ -163,8 +184,6 @@ export default function PolygonDrawer({
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
{...startPointAttr}
|
|
||||||
{...otherPointsAttr}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -41,7 +41,7 @@ export default function PolygonEditControls({
|
|||||||
...activePolygon.pointsOrder.slice(0, lastPointOrderIndex),
|
...activePolygon.pointsOrder.slice(0, lastPointOrderIndex),
|
||||||
...activePolygon.pointsOrder.slice(lastPointOrderIndex + 1),
|
...activePolygon.pointsOrder.slice(lastPointOrderIndex + 1),
|
||||||
],
|
],
|
||||||
isFinished: false,
|
isFinished: activePolygon.isFinished && activePolygon.points.length > 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
setPolygons(updatedPolygons);
|
setPolygons(updatedPolygons);
|
||||||
|
Loading…
Reference in New Issue
Block a user