forked from Github/frigate
New mask/zone editor and motion tuner (#11020)
* initial working konva * working multi polygons * multi zones * clean up * new zone dialog * clean up * relative coordinates and colors * fix color order * better motion tuner * objects for zones * progress * merge dev * edit pane * motion and object masks * filtering * add objects and unsaved to type * motion tuner, edit controls, tooltips * object and motion edit panes * polygon item component, switch color, object form, hover cards * working zone edit pane * working motion masks * object masks and deletion of all types * use FilterSwitch * motion tuner fixes and tweaks * clean up * tweaks * spaces in camera name * tweaks * allow dragging of points while drawing polygon * turn off editing mode when switching camera * limit interpolated coordinates and use crosshair cursor * padding * fix tooltip trigger for icons * konva tweaks * consolidate * fix top menu items on mobile
This commit is contained in:
102
web/src/utils/canvasUtil.ts
Normal file
102
web/src/utils/canvasUtil.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Vector2d } from "konva/lib/types";
|
||||
|
||||
export const getAveragePoint = (points: number[]): Vector2d => {
|
||||
let totalX = 0;
|
||||
let totalY = 0;
|
||||
for (let i = 0; i < points.length; i += 2) {
|
||||
totalX += points[i];
|
||||
totalY += points[i + 1];
|
||||
}
|
||||
return {
|
||||
x: totalX / (points.length / 2),
|
||||
y: totalY / (points.length / 2),
|
||||
};
|
||||
};
|
||||
|
||||
export const getDistance = (node1: number[], node2: number[]): string => {
|
||||
const diffX = Math.abs(node1[0] - node2[0]);
|
||||
const diffY = Math.abs(node1[1] - node2[1]);
|
||||
const distanceInPixel = Math.sqrt(diffX * diffX + diffY * diffY);
|
||||
return distanceInPixel.toFixed(2);
|
||||
};
|
||||
|
||||
export const dragBoundFunc = (
|
||||
stageWidth: number,
|
||||
stageHeight: number,
|
||||
vertexRadius: number,
|
||||
pos: Vector2d,
|
||||
): Vector2d => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
if (pos.x + vertexRadius > stageWidth) x = stageWidth;
|
||||
if (pos.x - vertexRadius < 0) x = 0;
|
||||
if (pos.y + vertexRadius > stageHeight) y = stageHeight;
|
||||
if (pos.y - vertexRadius < 0) y = 0;
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
export const minMax = (points: number[]): [number, number] => {
|
||||
return points.reduce(
|
||||
(acc: [number | undefined, number | undefined], val) => {
|
||||
acc[0] = acc[0] === undefined || val < acc[0] ? val : acc[0];
|
||||
acc[1] = acc[1] === undefined || val > acc[1] ? val : acc[1];
|
||||
return acc;
|
||||
},
|
||||
[undefined, undefined],
|
||||
) as [number, number];
|
||||
};
|
||||
|
||||
export const interpolatePoints = (
|
||||
points: number[][],
|
||||
width: number,
|
||||
height: number,
|
||||
newWidth: number,
|
||||
newHeight: number,
|
||||
): number[][] => {
|
||||
const newPoints: number[][] = [];
|
||||
|
||||
for (const [x, y] of points) {
|
||||
const newX = Math.min(+((x * newWidth) / width).toFixed(3), newWidth);
|
||||
const newY = Math.min(+((y * newHeight) / height).toFixed(3), newHeight);
|
||||
newPoints.push([newX, newY]);
|
||||
}
|
||||
|
||||
return newPoints;
|
||||
};
|
||||
|
||||
export const parseCoordinates = (coordinatesString: string) => {
|
||||
const coordinates = coordinatesString.split(",");
|
||||
const points = [];
|
||||
|
||||
for (let i = 0; i < coordinates.length; i += 2) {
|
||||
const x = parseFloat(coordinates[i]);
|
||||
const y = parseFloat(coordinates[i + 1]);
|
||||
points.push([x, y]);
|
||||
}
|
||||
|
||||
return points;
|
||||
};
|
||||
|
||||
export const flattenPoints = (points: number[][]): number[] => {
|
||||
return points.reduce((acc, point) => [...acc, ...point], []);
|
||||
};
|
||||
|
||||
export const toRGBColorString = (color: number[], darkened: boolean) => {
|
||||
if (color.length !== 3) {
|
||||
return "rgb(220,0,0,0.5)";
|
||||
}
|
||||
|
||||
return `rgba(${color[2]},${color[1]},${color[0]},${darkened ? "0.7" : "0.3"})`;
|
||||
};
|
||||
|
||||
export const masksAreIdentical = (arr1: string[], arr2: string[]): boolean => {
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < arr1.length; i++) {
|
||||
if (arr1[i] !== arr2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
50
web/src/utils/zoneEdutUtil.ts
Normal file
50
web/src/utils/zoneEdutUtil.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export const reviewQueries = (
|
||||
name: string,
|
||||
review_alerts: boolean,
|
||||
review_detections: boolean,
|
||||
camera: string,
|
||||
alertsZones: string[],
|
||||
detectionsZones: string[],
|
||||
) => {
|
||||
let alertQueries = "";
|
||||
let detectionQueries = "";
|
||||
let same_alerts = false;
|
||||
let same_detections = false;
|
||||
|
||||
const alerts = new Set<string>(alertsZones || []);
|
||||
|
||||
if (review_alerts) {
|
||||
alerts.add(name);
|
||||
} else {
|
||||
same_alerts = !alerts.has(name);
|
||||
alerts.delete(name);
|
||||
}
|
||||
|
||||
alertQueries = [...alerts]
|
||||
.map((zone) => `&cameras.${camera}.review.alerts.required_zones=${zone}`)
|
||||
.join("");
|
||||
|
||||
const detections = new Set<string>(detectionsZones || []);
|
||||
|
||||
if (review_detections) {
|
||||
detections.add(name);
|
||||
} else {
|
||||
same_detections = !detections.has(name);
|
||||
detections.delete(name);
|
||||
}
|
||||
|
||||
detectionQueries = [...detections]
|
||||
.map(
|
||||
(zone) => `&cameras.${camera}.review.detections.required_zones=${zone}`,
|
||||
)
|
||||
.join("");
|
||||
|
||||
if (!alertQueries && !same_alerts) {
|
||||
alertQueries = `&cameras.${camera}.review.alerts`;
|
||||
}
|
||||
if (!detectionQueries && !same_detections) {
|
||||
detectionQueries = `&cameras.${camera}.review.detections`;
|
||||
}
|
||||
|
||||
return { alertQueries, detectionQueries };
|
||||
};
|
||||
Reference in New Issue
Block a user