Feat: 워크스페이스 페이지에 캔버스 추가 - S11P21S002-104
This commit is contained in:
parent
bac5e993a5
commit
89f4a2a94c
@ -3,42 +3,15 @@ import Konva from 'konva';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Circle, Image, Layer, Line, Rect, Stage } from 'react-konva';
|
||||
import useImage from 'use-image';
|
||||
import { Label } from '@/types';
|
||||
import LabelRect from './LabelRect';
|
||||
import { Vector2d } from 'konva/lib/types';
|
||||
import LabelPolygon from './LabelPolygon';
|
||||
import CanvasControlBar from '../CanvasControlBar';
|
||||
|
||||
const mockLabels: Label[] = Array.from({ length: 10 }, (_, i) => {
|
||||
const startX = Math.random() * 1200 + 300;
|
||||
const startY = Math.random() * 2000 + 300;
|
||||
const color = Math.floor(Math.random() * 65535)
|
||||
.toString(16)
|
||||
.padStart(4, '0');
|
||||
|
||||
return {
|
||||
id: i,
|
||||
name: `label-${i}`,
|
||||
type: i % 2 === 0 ? 'polygon' : 'rect',
|
||||
color: i % 2 === 0 ? `#ff${color}` : `#${color}ff`,
|
||||
coordinates:
|
||||
i % 2 === 0
|
||||
? [
|
||||
[startX, startY],
|
||||
[startX + 200, startY + 50],
|
||||
[startX + 300, startY + 300],
|
||||
[startX + 100, startY + 250],
|
||||
]
|
||||
: [
|
||||
[startX, startY],
|
||||
[startX + 300, startY + 300],
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
export default function ImageCanvas() {
|
||||
const stageWidth = window.innerWidth;
|
||||
const stageHeight = window.innerHeight;
|
||||
const sidebarSize = useCanvasStore((state) => state.sidebarSize);
|
||||
const stageWidth = window.innerWidth * ((100 - sidebarSize) / 100) - 280;
|
||||
const stageHeight = window.innerHeight - 64;
|
||||
const stageRef = useRef<Konva.Stage>(null);
|
||||
const dragLayerRef = useRef<Konva.Layer>(null);
|
||||
const scale = useRef<number>(0);
|
||||
@ -209,11 +182,6 @@ export default function ImageCanvas() {
|
||||
return { x: scale.current, y: scale.current };
|
||||
};
|
||||
|
||||
// TODO: remove mock data
|
||||
useEffect(() => {
|
||||
useCanvasStore.setState({ labels: mockLabels });
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!stageRef.current) return;
|
||||
stageRef.current.container().style.cursor = drawState === 'pointer' ? 'default' : 'crosshair';
|
||||
|
@ -4,8 +4,48 @@ import { Label, Project } from '@/types';
|
||||
import { ResizablePanelGroup, ResizablePanel } from '../ui/resizable';
|
||||
import WorkspaceSidebar from '../WorkspaceSidebar';
|
||||
import WorkspaceLabelBar from '../WorkspaceLabelBar';
|
||||
import { useEffect } from 'react';
|
||||
import useCanvasStore from '@/stores/useCanvasStore';
|
||||
|
||||
const mockLabels: Label[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Label 1',
|
||||
color: '#FFaa33',
|
||||
coordinates: [
|
||||
[700, 100],
|
||||
[1200, 800],
|
||||
],
|
||||
type: 'rect',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Label 2',
|
||||
color: '#aaFF55',
|
||||
coordinates: [
|
||||
[200, 200],
|
||||
[400, 200],
|
||||
[500, 500],
|
||||
[400, 800],
|
||||
[200, 800],
|
||||
[100, 500],
|
||||
],
|
||||
type: 'polygon',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Label 3',
|
||||
color: '#77aaFF',
|
||||
coordinates: [
|
||||
[1000, 1000],
|
||||
[1800, 1800],
|
||||
],
|
||||
type: 'rect',
|
||||
},
|
||||
];
|
||||
|
||||
export default function WorkspaceLayout() {
|
||||
const setLabels = useCanvasStore((state) => state.setLabels);
|
||||
const workspace: { name: string; projects: Project[] } = {
|
||||
name: 'Workspace-name-1',
|
||||
projects: [
|
||||
@ -60,29 +100,10 @@ export default function WorkspaceLayout() {
|
||||
},
|
||||
],
|
||||
};
|
||||
const labels: Label[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Label 1',
|
||||
color: '#FFaa33',
|
||||
coordinates: [],
|
||||
type: 'rect',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Label 2',
|
||||
color: '#aaFF55',
|
||||
coordinates: [],
|
||||
type: 'rect',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Label 3',
|
||||
color: '#77aaFF',
|
||||
coordinates: [],
|
||||
type: 'rect',
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
setLabels(mockLabels);
|
||||
}, [setLabels]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -97,7 +118,7 @@ export default function WorkspaceLayout() {
|
||||
<main className="h-full grow">
|
||||
<Outlet />
|
||||
</main>
|
||||
<WorkspaceLabelBar labels={labels} />
|
||||
<WorkspaceLabelBar labels={mockLabels} />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
|
@ -3,8 +3,11 @@ import { ResizableHandle, ResizablePanel } from '../ui/resizable';
|
||||
import ProjectStructure from './ProjectStructure';
|
||||
import { Button } from '../ui/button';
|
||||
import { Project } from '@/types';
|
||||
import useCanvasStore from '@/stores/useCanvasStore';
|
||||
|
||||
export default function WorkspaceSidebar({ workspaceName, projects }: { workspaceName: string; projects: Project[] }) {
|
||||
const setSidebarSize = useCanvasStore((state) => state.setSidebarSize);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResizablePanel
|
||||
@ -12,9 +15,7 @@ export default function WorkspaceSidebar({ workspaceName, projects }: { workspac
|
||||
maxSize={35}
|
||||
defaultSize={20}
|
||||
className="flex h-full flex-col bg-gray-100"
|
||||
onResize={(size) => {
|
||||
console.log(size);
|
||||
}}
|
||||
onResize={(size) => setSidebarSize(size)}
|
||||
>
|
||||
<header className="body flex w-full items-center gap-2 p-2">
|
||||
<h1 className="w-full overflow-hidden text-ellipsis whitespace-nowrap">{workspaceName}</h1>
|
||||
|
@ -9,6 +9,7 @@ import AdminMemberManage from '@/components/AdminMemberManage';
|
||||
import OAuthCallback from '@/components/OAuthCallback';
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import ImageCanvas from '@/components/ImageCanvas';
|
||||
|
||||
export const webPath = {
|
||||
home: () => '/',
|
||||
@ -49,7 +50,7 @@ const router = createBrowserRouter([
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <div>workspace</div>,
|
||||
element: <ImageCanvas />,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -2,10 +2,13 @@ import { Label } from '@/types';
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface CanvasState {
|
||||
sidebarSize: number;
|
||||
image: string;
|
||||
labels: Label[];
|
||||
drawState: 'pen' | 'rect' | 'pointer';
|
||||
setSidebarSize: (width: number) => void;
|
||||
changeImage: (image: string, labels: Label[]) => void;
|
||||
setLabels: (labels: Label[]) => void;
|
||||
addLabel: (label: Label) => void;
|
||||
removeLabel: (labelId: number) => void;
|
||||
updateLabel: (label: Label) => void;
|
||||
@ -13,11 +16,14 @@ interface CanvasState {
|
||||
}
|
||||
|
||||
const useCanvasStore = create<CanvasState>()((set) => ({
|
||||
sidebarSize: 20,
|
||||
image: '',
|
||||
labels: [],
|
||||
drawState: 'pointer',
|
||||
setSidebarSize: (width) => set({ sidebarSize: width }),
|
||||
changeImage: (image: string, labels: Label[]) => set({ image, labels }),
|
||||
addLabel: (label: Label) => set((state) => ({ labels: [...state.labels, label] })),
|
||||
setLabels: (labels) => set({ labels }),
|
||||
removeLabel: (labelId: number) => set((state) => ({ labels: state.labels.filter((label) => label.id !== labelId) })),
|
||||
updateLabel: (label: Label) => set((state) => ({ labels: state.labels.map((l) => (l.id === label.id ? label : l)) })),
|
||||
setDrawState: (drawState) => set({ drawState }),
|
||||
|
Loading…
Reference in New Issue
Block a user