mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 19:31:10 +00:00
add css files for components
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.side-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.left-menu{
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.right-menu{
|
||||
overflow-y: auto;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.player-wrapper {
|
||||
width: 70%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #ffdddd;
|
||||
color: #d8000c;
|
||||
padding: 6px;
|
||||
margin: 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.player-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.player-block {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
background: #000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import VideoPlayer from '../VideoPlayer/VideoPlayer';
|
||||
import AnnotationList from '../AnnotationList';
|
||||
import MediaList from '../MediaList/MediaList';
|
||||
import DetectionClassList from '../DetectionClassList/DetectionClassList';
|
||||
import CanvasEditor from '../CanvasEditor/CanvasEditor';
|
||||
import * as AnnotationService from '../../services/AnnotationService';
|
||||
import AnnotationControls from '../AnnotationControls/AnnotationControls';
|
||||
import saveAnnotation from '../../services/DataHandler';
|
||||
import './AnnotationMain.css';
|
||||
|
||||
function AnnotationMain() {
|
||||
const [files, setFiles] = useState([]);
|
||||
const [selectedFile, setSelectedFile] = useState(null);
|
||||
const [annotations, setAnnotations] = useState({});
|
||||
const [currentTime, setCurrentTime] = useState(0);
|
||||
const [selectedClass, setSelectedClass] = useState(null);
|
||||
const [detections, setDetections] = useState([]);
|
||||
const [selectedDetectionIndices, setSelectedDetectionIndices] = useState([]);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [videoWidth, setVideoWidth] = useState(640);
|
||||
const [videoHeight, setVideoHeight] = useState(480);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
const videoRef = useRef(null);
|
||||
const containerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const initialFiles = [];
|
||||
setFiles(initialFiles);
|
||||
}, []);
|
||||
|
||||
const handleFileSelect = (file) => {
|
||||
if (!file) return;
|
||||
|
||||
setSelectedFile(file);
|
||||
setAnnotations({});
|
||||
setDetections([]);
|
||||
setSelectedDetectionIndices([]);
|
||||
setCurrentTime(0);
|
||||
setIsPlaying(false);
|
||||
setErrorMessage("");
|
||||
};
|
||||
|
||||
const handleDropNewFiles = (newFiles) => {
|
||||
if (!newFiles || newFiles.length === 0) return;
|
||||
|
||||
const validFiles = [...newFiles];
|
||||
setFiles(prevFiles => [...prevFiles, ...validFiles]);
|
||||
|
||||
if (!selectedFile && validFiles.length > 0) {
|
||||
setSelectedFile(validFiles[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAnnotationSave = () => {
|
||||
if (!videoRef.current) return;
|
||||
|
||||
if (!detections || detections.length === 0) {
|
||||
setErrorMessage("Please create at least one detection before saving");
|
||||
return;
|
||||
}
|
||||
|
||||
const safeContainerRef = {
|
||||
current: {
|
||||
offsetWidth: videoWidth,
|
||||
offsetHeight: videoHeight
|
||||
}
|
||||
};
|
||||
|
||||
const imageData = AnnotationService.createAnnotationImage(
|
||||
videoRef,
|
||||
detections,
|
||||
safeContainerRef
|
||||
);
|
||||
|
||||
if (imageData) {
|
||||
setAnnotations(prevAnnotations => {
|
||||
const newAnnotations = {
|
||||
...prevAnnotations,
|
||||
[currentTime]: { time: currentTime, annotations: detections, imageData }
|
||||
};
|
||||
|
||||
saveAnnotation(currentTime, detections, imageData);
|
||||
setErrorMessage("");
|
||||
|
||||
return newAnnotations;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
if (selectedDetectionIndices.length === 0) {
|
||||
setErrorMessage("Please select a detection to delete");
|
||||
return;
|
||||
}
|
||||
|
||||
const newDetections = detections.filter((_, index) => !selectedDetectionIndices.includes(index));
|
||||
setDetections(newDetections);
|
||||
setSelectedDetectionIndices([]);
|
||||
setErrorMessage("");
|
||||
};
|
||||
|
||||
const handleAnnotationClick = (time) => {
|
||||
setCurrentTime(time);
|
||||
const annotation = annotations[time];
|
||||
if (annotation) {
|
||||
setDetections(annotation.annotations || []);
|
||||
setSelectedDetectionIndices([]);
|
||||
}
|
||||
if (videoRef.current) {
|
||||
videoRef.current.currentTime = time;
|
||||
}
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
const handleClassSelect = (cls) => {
|
||||
setSelectedClass(cls);
|
||||
};
|
||||
|
||||
const handleDetectionsChange = (newDetections) => {
|
||||
setDetections(newDetections);
|
||||
};
|
||||
|
||||
const handleSelectionChange = (newSelection) => {
|
||||
setSelectedDetectionIndices(newSelection);
|
||||
};
|
||||
|
||||
const handlePlayPause = () => {
|
||||
setIsPlaying(prev => !prev);
|
||||
|
||||
};
|
||||
|
||||
const handleFrameForward = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.currentTime += 1 / 30;
|
||||
setCurrentTime(videoRef.current.currentTime);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFrameBackward = () => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.currentTime -= 1 / 30;
|
||||
setCurrentTime(videoRef.current.currentTime);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSizeChanged = (width, height) => {
|
||||
setVideoWidth(width);
|
||||
setVideoHeight(height);
|
||||
};
|
||||
|
||||
const handleSetCurrentTime = (time) => {
|
||||
setCurrentTime(time);
|
||||
};
|
||||
|
||||
// Toggle debug mode with Ctrl+D
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e) => {
|
||||
switch (e.key) {
|
||||
case 'Space':
|
||||
|
||||
}
|
||||
if (e.ctrlKey && e.key === 'd') {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className='content-wrapper' >
|
||||
<div className='side-menu left-menu' >
|
||||
<MediaList
|
||||
files={files}
|
||||
selectedFile={selectedFile}
|
||||
onFileSelect={handleFileSelect}
|
||||
onDropNewFiles={handleDropNewFiles}
|
||||
/>
|
||||
|
||||
<DetectionClassList onClassSelect={handleClassSelect} />
|
||||
</div>
|
||||
|
||||
<div className='player-wrapper' >
|
||||
{errorMessage && (
|
||||
<div className='error-message' >
|
||||
{errorMessage}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='player-container' ref={containerRef}>
|
||||
<div className='player-block' >
|
||||
<VideoPlayer
|
||||
videoFile={selectedFile}
|
||||
currentTime={currentTime}
|
||||
videoRef={videoRef}
|
||||
isPlaying={isPlaying}
|
||||
onSizeChanged={handleSizeChanged}
|
||||
onSetCurrentTime={handleSetCurrentTime}
|
||||
>
|
||||
<CanvasEditor
|
||||
width={videoWidth}
|
||||
height={videoHeight}
|
||||
detections={detections}
|
||||
selectedDetectionIndices={selectedDetectionIndices}
|
||||
onDetectionsChange={handleDetectionsChange}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
detectionClass={selectedClass}
|
||||
/>
|
||||
</VideoPlayer>
|
||||
</div>
|
||||
|
||||
<AnnotationControls
|
||||
onFrameBackward={handleFrameBackward}
|
||||
onPlayPause={handlePlayPause}
|
||||
isPlaying={isPlaying}
|
||||
onFrameForward={handleFrameForward}
|
||||
onSaveAnnotation={handleAnnotationSave}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='side-menu right-menu'>
|
||||
<AnnotationList
|
||||
annotations={Object.values(annotations)}
|
||||
onAnnotationClick={handleAnnotationClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AnnotationMain;
|
||||
Reference in New Issue
Block a user