Skip to content

Commit

Permalink
Zone/mask editor improvements (#11236)
Browse files Browse the repository at this point in the history
* add points to completed polygons in zone/mask editor

* change line order so edges are more easily clickable
  • Loading branch information
hawkeye217 authored May 4, 2024
1 parent f0054ce commit 51dcdd6
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 175 deletions.
1 change: 1 addition & 0 deletions web/src/components/settings/MasksAndZones.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ export default function MasksAndZones({
scaledHeight &&
editingPolygons ? (
<PolygonCanvas
containerRef={containerRef}
camera={cameraConfig.name}
width={scaledWidth}
height={scaledHeight}
Expand Down
138 changes: 19 additions & 119 deletions web/src/components/settings/PolygonCanvas.tsx
Original file line number Diff line number Diff line change
@@ -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 { Stage, Layer, Image } from "react-konva";
import Konva from "konva";
Expand All @@ -7,6 +7,7 @@ import { Polygon, PolygonType } from "@/types/canvas";
import { useApiHost } from "@/api";

type PolygonCanvasProps = {
containerRef: RefObject<HTMLDivElement>;
camera: string;
width: number;
height: number;
Expand All @@ -18,6 +19,7 @@ type PolygonCanvasProps = {
};

export function PolygonCanvas({
containerRef,
camera,
width,
height,
Expand Down Expand Up @@ -55,10 +57,6 @@ export function PolygonCanvas({
};
}, [videoElement]);

const getMousePos = (stage: Konva.Stage) => {
return [stage.getPointerPosition()!.x, stage.getPointerPosition()!.y];
};

const addPointToPolygon = (polygon: Polygon, newPoint: number[]) => {
const points = polygon.points;
const pointsOrder = polygon.pointsOrder;
Expand Down Expand Up @@ -99,37 +97,6 @@ export function PolygonCanvas({
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>) => {
if (activePolygonIndex === undefined || !polygons) {
return;
Expand All @@ -138,11 +105,13 @@ export function PolygonCanvas({
const updatedPolygons = [...polygons];
const activePolygon = updatedPolygons[activePolygonIndex];
const stage = e.target.getStage()!;
const mousePos = getMousePos(stage);
const mousePos = stage.getPointerPosition() ?? { x: 0, y: 0 };
const intersection = stage.getIntersection(mousePos);

if (
activePolygon.points.length >= 3 &&
isMouseOverFirstPoint(activePolygon, mousePos)
intersection?.getClassName() == "Circle" &&
intersection?.name() == "point-0"
) {
// Close the polygon
updatedPolygons[activePolygonIndex] = {
Expand All @@ -152,12 +121,13 @@ export function PolygonCanvas({
setPolygons(updatedPolygons);
} else {
if (
!activePolygon.isFinished &&
!isMouseOverAnyPoint(activePolygon, mousePos)
(!activePolygon.isFinished &&
intersection?.getClassName() !== "Circle") ||
(activePolygon.isFinished && intersection?.name() == "unfilled-line")
) {
const { updatedPoints, updatedPointsOrder } = addPointToPolygon(
activePolygon,
mousePos,
[mousePos.x, mousePos.y],
);

updatedPolygons[activePolygonIndex] = {
Expand All @@ -168,62 +138,6 @@ export function PolygonCanvas({
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 = (
Expand All @@ -237,7 +151,8 @@ export function PolygonCanvas({
const activePolygon = updatedPolygons[activePolygonIndex];
const stage = e.target.getStage();
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];
if (pos[0] < 0) pos[0] = 0;
if (pos[1] < 0) pos[1] = 0;
Expand Down Expand Up @@ -272,26 +187,17 @@ export function PolygonCanvas({
}
};

const handleStageMouseOver = (
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
) => {
const handleStageMouseOver = () => {
if (activePolygonIndex === undefined || !polygons) {
return;
}

const updatedPolygons = [...polygons];
const activePolygon = updatedPolygons[activePolygonIndex];
const stage = e.target.getStage()!;
const mousePos = getMousePos(stage);

if (
activePolygon.isFinished ||
isMouseOverAnyPoint(activePolygon, mousePos) ||
isMouseOverFirstPoint(activePolygon, mousePos)
)
return;

e.target.getStage()!.container().style.cursor = "crosshair";
if (containerRef.current && !activePolygon.isFinished) {
containerRef.current.style.cursor = "crosshair";
}
};

useEffect(() => {
Expand Down Expand Up @@ -336,6 +242,7 @@ export function PolygonCanvas({
selectedZoneMask.includes(polygon.type)) &&
index !== activePolygonIndex && (
<PolygonDrawer
stageRef={stageRef}
key={index}
points={polygon.points}
isActive={index === activePolygonIndex}
Expand All @@ -344,10 +251,6 @@ export function PolygonCanvas({
color={polygon.color}
handlePointDragMove={handlePointDragMove}
handleGroupDragEnd={handleGroupDragEnd}
handleMouseOverStartPoint={handleMouseOverStartPoint}
handleMouseOutStartPoint={handleMouseOutStartPoint}
handleMouseOverAnyPoint={handleMouseOverAnyPoint}
handleMouseOutAnyPoint={handleMouseOutAnyPoint}
/>
),
)}
Expand All @@ -356,6 +259,7 @@ export function PolygonCanvas({
(selectedZoneMask === undefined ||
selectedZoneMask.includes(polygons[activePolygonIndex].type)) && (
<PolygonDrawer
stageRef={stageRef}
key={activePolygonIndex}
points={polygons[activePolygonIndex].points}
isActive={true}
Expand All @@ -364,10 +268,6 @@ export function PolygonCanvas({
color={polygons[activePolygonIndex].color}
handlePointDragMove={handlePointDragMove}
handleGroupDragEnd={handleGroupDragEnd}
handleMouseOverStartPoint={handleMouseOverStartPoint}
handleMouseOutStartPoint={handleMouseOutStartPoint}
handleMouseOverAnyPoint={handleMouseOverAnyPoint}
handleMouseOutAnyPoint={handleMouseOutAnyPoint}
/>
)}
</Layer>
Expand Down
Loading

0 comments on commit 51dcdd6

Please sign in to comment.