mirror of
https://github.com/azaion/ui.git
synced 2026-04-22 12:56:34 +00:00
Azaion Suite to the web. First commit. Only rough sketches of future components is done.
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import * as AnnotationService from '../services/AnnotationService';
|
||||
import DetectionContainer from './DetectionContainer';
|
||||
|
||||
function CanvasEditor({
|
||||
width,
|
||||
height,
|
||||
detections,
|
||||
initialCurrentDetection = null,
|
||||
selectedDetectionIndices,
|
||||
onDetectionsChange,
|
||||
onSelectionChange,
|
||||
children,
|
||||
detectionClass
|
||||
}) {
|
||||
const containerRef = useRef(null);
|
||||
const [currentDetection, setCurrentDetection] = useState(initialCurrentDetection);
|
||||
const [mouseDownPos, setMouseDownPos] = useState(null);
|
||||
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
||||
const [resizeData, setResizeData] = useState(null);
|
||||
const [localDetections, setLocalDetections] = useState(detections || []);
|
||||
const [localSelectedIndices, setLocalSelectedIndices] = useState(selectedDetectionIndices || []);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalDetections(detections || []);
|
||||
}, [detections]);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalSelectedIndices(selectedDetectionIndices || []);
|
||||
}, [selectedDetectionIndices]);
|
||||
|
||||
const handleMouseDown = (e) => {
|
||||
e.preventDefault();
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const { x: mouseX, y: mouseY } = AnnotationService.calculateRelativeCoordinates(e, containerRef);
|
||||
setMouseDownPos({ mouseX, mouseY });
|
||||
|
||||
let detectionFound = false;
|
||||
for (let i = localDetections.length - 1; i >= 0; i--) {
|
||||
if (AnnotationService.isMouseOverDetection(e.clientX, e.clientY, localDetections[i], containerRef)) {
|
||||
if (e.ctrlKey) {
|
||||
const newSelectedIndices = localSelectedIndices.includes(i)
|
||||
? localSelectedIndices.filter(index => index !== i)
|
||||
: [...localSelectedIndices, i];
|
||||
setLocalSelectedIndices(newSelectedIndices);
|
||||
if (onSelectionChange) {
|
||||
onSelectionChange(newSelectedIndices);
|
||||
}
|
||||
} else {
|
||||
const newSelectedIndices = [i];
|
||||
setLocalSelectedIndices(newSelectedIndices);
|
||||
if (onSelectionChange) {
|
||||
onSelectionChange(newSelectedIndices);
|
||||
}
|
||||
}
|
||||
setDragOffset({
|
||||
x: mouseX - localDetections[i].x1,
|
||||
y: mouseY - localDetections[i].y1,
|
||||
});
|
||||
detectionFound = true;
|
||||
break; // Stop the loop once a detection is found
|
||||
}
|
||||
}
|
||||
|
||||
if (!detectionFound) {
|
||||
if (!e.ctrlKey) {
|
||||
setLocalSelectedIndices([]);
|
||||
if (onSelectionChange) {
|
||||
onSelectionChange([]);
|
||||
}
|
||||
}
|
||||
if (detectionClass) {
|
||||
setCurrentDetection({ x1: mouseX, y1: mouseY, x2: mouseX, y2: mouseY, class: detectionClass });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
if (!containerRef.current) return;
|
||||
const { x: mouseX, y: mouseY } = AnnotationService.calculateRelativeCoordinates(e, containerRef);
|
||||
|
||||
if (localSelectedIndices.length > 0 && mouseDownPos && !resizeData) {
|
||||
// Dragging logic
|
||||
const newDetections = [...localDetections];
|
||||
const firstSelectedIndex = localSelectedIndices[0];
|
||||
|
||||
// Check for valid index before accessing.
|
||||
if (firstSelectedIndex === undefined || !newDetections[firstSelectedIndex]) return;
|
||||
|
||||
const firstSelectedDetection = newDetections[firstSelectedIndex];
|
||||
const { newX1, newY1, newX2, newY2 } = AnnotationService.calculateNewPosition(mouseX, mouseY, dragOffset, firstSelectedDetection, containerRef);
|
||||
const deltaX = newX1 - firstSelectedDetection.x1;
|
||||
const deltaY = newY1 - firstSelectedDetection.y1;
|
||||
|
||||
localSelectedIndices.forEach(index => {
|
||||
// Check for valid index before accessing.
|
||||
if (newDetections[index] === undefined) return;
|
||||
|
||||
const detection = newDetections[index];
|
||||
let updatedX1 = detection.x1 + deltaX;
|
||||
let updatedY1 = detection.y1 + deltaY;
|
||||
let updatedX2 = detection.x2 + deltaX;
|
||||
let updatedY2 = detection.y2 + deltaY;
|
||||
|
||||
const bounds = AnnotationService.calculateNewPosition(updatedX1 + dragOffset.x, updatedY1 + dragOffset.y, dragOffset, { ...detection, x1: updatedX1, y1: updatedY1, x2: updatedX2, y2: updatedY2 }, containerRef);
|
||||
detection.x1 = bounds.newX1;
|
||||
detection.y1 = bounds.newY1;
|
||||
detection.x2 = bounds.newX2;
|
||||
detection.y2 = bounds.newY2;
|
||||
});
|
||||
|
||||
setLocalDetections(newDetections);
|
||||
if (onDetectionsChange) {
|
||||
onDetectionsChange(newDetections); // Notify about changes
|
||||
}
|
||||
} else if (currentDetection && !resizeData) {
|
||||
// Drawing a new detection.
|
||||
setCurrentDetection(prev => ({ ...prev, x2: mouseX, y2: mouseY }));
|
||||
} else if (resizeData) {
|
||||
const { index, position } = resizeData;
|
||||
if (localDetections[index] === undefined) return;
|
||||
|
||||
const newDetections = [...localDetections];
|
||||
const detection = newDetections[index];
|
||||
const updatedDetection = AnnotationService.calculateResizedPosition(mouseX, mouseY, position, detection, containerRef);
|
||||
newDetections[index] = updatedDetection;
|
||||
setLocalDetections(newDetections);
|
||||
if (onDetectionsChange) {
|
||||
onDetectionsChange(newDetections);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
if (currentDetection && mouseDownPos) {
|
||||
const dx = Math.abs(currentDetection.x2 - currentDetection.x1);
|
||||
const dy = Math.abs(currentDetection.y2 - currentDetection.y1);
|
||||
|
||||
if (dx > 5 && dy > 5) {
|
||||
const newDetections = [...localDetections, currentDetection];
|
||||
setLocalDetections(newDetections);
|
||||
if (onDetectionsChange) {
|
||||
onDetectionsChange(newDetections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentDetection(null);
|
||||
setMouseDownPos(null);
|
||||
setDragOffset({ x: 0, y: 0 });
|
||||
setResizeData(null);
|
||||
};
|
||||
|
||||
const handleDetectionMouseDown = (e, index) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!localSelectedIndices.includes(index)) {
|
||||
if (!e.ctrlKey) {
|
||||
const newSelectedIndices = [index];
|
||||
setLocalSelectedIndices(newSelectedIndices);
|
||||
onSelectionChange && onSelectionChange(newSelectedIndices);
|
||||
} else {
|
||||
const newSelectedIndices = [...localSelectedIndices, index];
|
||||
setLocalSelectedIndices(newSelectedIndices);
|
||||
onSelectionChange && onSelectionChange(newSelectedIndices);
|
||||
}
|
||||
}
|
||||
|
||||
const { x: mouseX, y: mouseY } = AnnotationService.calculateRelativeCoordinates(e, containerRef);
|
||||
setDragOffset({
|
||||
x: mouseX - localDetections[index].x1,
|
||||
y: mouseY - localDetections[index].y1,
|
||||
});
|
||||
setMouseDownPos({x: mouseX, y: mouseY})
|
||||
|
||||
};
|
||||
|
||||
const handleResize = (e, index, position) => {
|
||||
e.stopPropagation();
|
||||
setResizeData({ index, position });
|
||||
if (!localSelectedIndices.includes(index)) {
|
||||
if (!e.ctrlKey) {
|
||||
setLocalSelectedIndices([index]);
|
||||
onSelectionChange && onSelectionChange([index]);
|
||||
}
|
||||
else{
|
||||
const newSelectedIndices = [...localSelectedIndices, index];
|
||||
setLocalSelectedIndices(newSelectedIndices);
|
||||
onSelectionChange && onSelectionChange(newSelectedIndices);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: `${width}px`,
|
||||
height: `${height}px`,
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
>
|
||||
<div ref={containerRef}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseLeave={handleMouseUp}
|
||||
>
|
||||
{children}
|
||||
<DetectionContainer
|
||||
detections={localDetections}
|
||||
selectedDetectionIndices={localSelectedIndices}
|
||||
onDetectionMouseDown={handleDetectionMouseDown}
|
||||
currentDetection={currentDetection}
|
||||
onResize={handleResize}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CanvasEditor;
|
||||
Reference in New Issue
Block a user