mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 23:41:10 +00:00
add css files for components
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
.editor-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.canvas-editor {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: auto;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import * as AnnotationService from '../../services/AnnotationService';
|
||||
import DetectionContainer from '../DetectionContainer';
|
||||
import './CanvasEditor.css';
|
||||
|
||||
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 || []);
|
||||
const [dimensions, setDimensions] = useState({ width: width || 640, height: height || 480 });
|
||||
|
||||
// Track if we're in a dragging operation
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (width && height) {
|
||||
setDimensions({ width, height });
|
||||
}
|
||||
}, [width, height]);
|
||||
|
||||
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,
|
||||
});
|
||||
setIsDragging(true);
|
||||
detectionFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
setIsDragging(true);
|
||||
const newDetections = [...localDetections];
|
||||
const firstSelectedIndex = localSelectedIndices[0];
|
||||
|
||||
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 => {
|
||||
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);
|
||||
}
|
||||
} else if (currentDetection && !resizeData) {
|
||||
setCurrentDetection(prev => ({ ...prev, x2: mouseX, y2: mouseY }));
|
||||
} else if (resizeData) {
|
||||
setIsDragging(true);
|
||||
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 = (e) => {
|
||||
// If we're dragging (or resizing), stop propagation to prevent other elements from reacting
|
||||
if (isDragging || resizeData) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (currentDetection && mouseDownPos) {
|
||||
const dx = Math.abs(currentDetection.x2 - currentDetection.x1);
|
||||
const dy = Math.abs(currentDetection.y2 - currentDetection.y1);
|
||||
|
||||
if (dx > 5 && dy > 5) {
|
||||
// Normalize coordinates so x1,y1 is always top-left and x2,y2 is bottom-right
|
||||
const normalizedDetection = {
|
||||
...currentDetection,
|
||||
x1: Math.min(currentDetection.x1, currentDetection.x2),
|
||||
y1: Math.min(currentDetection.y1, currentDetection.y2),
|
||||
x2: Math.max(currentDetection.x1, currentDetection.x2),
|
||||
y2: Math.max(currentDetection.y1, currentDetection.y2),
|
||||
};
|
||||
|
||||
const newDetections = [...localDetections, normalizedDetection];
|
||||
setLocalDetections(newDetections);
|
||||
if (onDetectionsChange) {
|
||||
onDetectionsChange(newDetections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentDetection(null);
|
||||
setMouseDownPos(null);
|
||||
setDragOffset({ x: 0, y: 0 });
|
||||
setResizeData(null);
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
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 });
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
// Add a document-level mouse move and up handler for dragging outside container
|
||||
useEffect(() => {
|
||||
if (isDragging || resizeData) {
|
||||
const handleDocumentMouseMove = (e) => {
|
||||
handleMouseMove(e);
|
||||
};
|
||||
|
||||
const handleDocumentMouseUp = (e) => {
|
||||
handleMouseUp(e);
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleDocumentMouseMove);
|
||||
document.addEventListener('mouseup', handleDocumentMouseUp);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', handleDocumentMouseMove);
|
||||
document.removeEventListener('mouseup', handleDocumentMouseUp);
|
||||
};
|
||||
}
|
||||
}, [isDragging, resizeData, mouseDownPos]);
|
||||
|
||||
return (
|
||||
<div className='editor-container' >
|
||||
<div className='canvas-editor'
|
||||
ref={containerRef}
|
||||
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