feat: initial commit web-cad-neu with docker-compose, frontend and backend
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
# Phase 3: Drawing Tools — React Wiring & State Management
|
||||
|
||||
## Goal
|
||||
Wire Phase 1 canvas/interaction engines to React state so drawing tools actually create, render, and manage elements. Implement undo/redo, command-line shortcuts, and drawing flow improvements.
|
||||
|
||||
## Requirements Covered
|
||||
- F-CAD-01: Zeichnen von Grundelementen (Linie, Kreis, Bogen, Rechteck, Polygon, Polylinie)
|
||||
- F-CAD-03: Bemaßung
|
||||
- F-CAD-05: Command Line (L, C, PL, R, A, T, DIM shortcuts)
|
||||
- F-CAD-09: Undo/Redo mit History
|
||||
- F-CAD-11: Text
|
||||
|
||||
## Current State
|
||||
- `src/interaction/index.ts` (591 lines): InteractionEngine with drawing logic for all types, callbacks (onElementCreated, onElementsDeleted, onToolStateChanged, onCursorMoved, onCommandTrigger)
|
||||
- `src/canvas/RenderEngine.ts` (588 lines): Renders all element types
|
||||
- `src/components/CanvasArea.tsx` (103 lines): Creates engine instances in useEffect but does NOT wire callbacks to React state
|
||||
- `src/App.tsx` (223 lines): Has mock state but no element management, no engine ref, no undo/redo
|
||||
|
||||
## Tasks
|
||||
|
||||
### Task 1: Refactor CanvasArea to expose engine instances
|
||||
File: `src/components/CanvasArea.tsx`
|
||||
|
||||
Current: engines created in useEffect, no external access.
|
||||
|
||||
Required:
|
||||
- Use `useRef` to hold engine instances (InteractionEngine, RenderEngine, ZoomPanController, etc.)
|
||||
- Accept new props: `onElementCreated`, `onElementsDeleted`, `onCursorMoved`, `onToolStateChanged`, `onToolChange` (tool from App → engine), `elements` (element array → engine.setElements), `snapEnabled`, `orthoEnabled`, `gridEnabled` (from App → engine state)
|
||||
- In useEffect: create engines, wire all callbacks to props, call `interaction.setCallbacks({...})`
|
||||
- Add a separate useEffect for `elements` changes → `interaction.setElements(elements)` + `spatialIndex.bulkInsert(elements)` + `renderEngine.render()`
|
||||
- Add a separate useEffect for `snapEnabled/orthoEnabled/gridEnabled` → update engine state + renderEngine options
|
||||
- Add a separate useEffect for `activeTool` → `interaction.setTool(tool)`
|
||||
- Expose zoomPan via ref callback prop `onZoomPanReady` so App can call zoomFit
|
||||
- Add `onZoomIn`, `onZoomOut`, `onZoomFit` to actually call zoomPan methods (not just log)
|
||||
- Add double-click handler: on dblclick, if drawing polyline/polygon → call confirmDraw via interaction
|
||||
|
||||
New CanvasAreaProps (add to `src/types/ui.types.ts`):
|
||||
```typescript
|
||||
export interface CanvasAreaProps {
|
||||
cursorPos: CursorPos;
|
||||
viewMode: ViewMode;
|
||||
onViewChange: (mode: ViewMode) => void;
|
||||
gridEnabled: boolean;
|
||||
orthoEnabled: boolean;
|
||||
snapEnabled: boolean;
|
||||
activeTool: string;
|
||||
elements: CADElement[];
|
||||
onElementCreated: (el: CADElement) => void;
|
||||
onElementsDeleted: (ids: string[]) => void;
|
||||
onCursorMoved: (x: number, y: number) => void;
|
||||
onToolStateChanged: (state: ToolState) => void;
|
||||
onToggleGrid: () => void;
|
||||
onToggleOrtho: () => void;
|
||||
onToggleSnap: () => void;
|
||||
onZoomIn: () => void;
|
||||
onZoomOut: () => void;
|
||||
onZoomFit: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
### Task 2: Implement undo/redo stack in App.tsx
|
||||
File: `src/App.tsx`
|
||||
|
||||
Required:
|
||||
- Add `elements` state: `useState<CADElement[]>([])`
|
||||
- Add `undoStack` and `redoStack` as `useState<CADElement[][]>`
|
||||
- `handleElementCreated`: push current elements to undoStack, add new element, clear redoStack
|
||||
- `handleElementsDeleted`: push current elements to undoStack, remove deleted, clear redoStack
|
||||
- `handleUndo`: if undoStack not empty, push current to redoStack, pop undoStack → set elements
|
||||
- `handleRedo`: if redoStack not empty, push current to undoStack, pop redoStack → set elements
|
||||
- Pass `elements` to CanvasArea
|
||||
- Pass `onElementCreated`, `onElementsDeleted` to CanvasArea
|
||||
- Wire `onCursorMoved` to update `cursorPos` state
|
||||
- Wire `onToolStateChanged` to update any relevant UI state
|
||||
|
||||
### Task 3: Wire tool selection from LeftSidebar to CanvasArea
|
||||
File: `src/App.tsx`
|
||||
|
||||
Required:
|
||||
- `activeTool` state already exists in App.tsx
|
||||
- Pass `activeTool` to CanvasArea as prop
|
||||
- CanvasArea useEffect watches `activeTool` → calls `interaction.setTool(tool as ToolType)`
|
||||
- LeftSidebar `onToolChange` already updates `activeTool` in App
|
||||
|
||||
### Task 4: Command line shortcuts (F-CAD-05)
|
||||
File: `src/App.tsx`
|
||||
|
||||
Required:
|
||||
- In `handleCommand(cmd)`, parse command and map to tool:
|
||||
- `L` or `LINE` → setTool('line')
|
||||
- `C` or `CIRCLE` → setTool('circle')
|
||||
- `A` or `ARC` → setTool('arc')
|
||||
- `R` or `RECT` or `RECTANGLE` → setTool('rect')
|
||||
- `PL` or `POLYLINE` → setTool('polyline')
|
||||
- `POL` or `POLYGON` → setTool('polygon')
|
||||
- `T` or `TEXT` → setTool('text')
|
||||
- `DIM` or `DIMENSION` → setTool('dimension')
|
||||
- `V` or `SELECT` → setTool('select')
|
||||
- `P` or `PAN` → setTool('pan')
|
||||
- `M` or `MOVE` → setTool('move')
|
||||
- `CO` or `COPY` → setTool('copy')
|
||||
- `RO` or `ROTATE` → setTool('rotate')
|
||||
- `SC` or `SCALE` → setTool('scale')
|
||||
- `MI` or `MIRROR` → setTool('mirror')
|
||||
- `DEL` or `ERASE` → setTool('delete')
|
||||
- `UNDO` or `U` → handleUndo()
|
||||
- `REDO` → handleRedo()
|
||||
- Add command to history with prefix '›'
|
||||
- Add response to history with prefix '·' (e.g. 'Linie-Werkzeug aktiv · Klicken zum Starten')
|
||||
|
||||
### Task 5: Drawing flow improvements
|
||||
File: `src/interaction/index.ts`
|
||||
|
||||
Required:
|
||||
- **Polyline/Polygon**: Add `handleDoubleClick` method — if activeTool is polyline/polygon and phase is drawing, call confirmDraw()
|
||||
- Wire dblclick event in `attach()`: `this.addListener('dblclick', this.onDoubleClick.bind(this))`
|
||||
- **Arc**: Improve 3-point arc — first click = center, second click = start point (sets radius + startAngle), third click = end point (sets endAngle). Update handleDrawDown to handle multi-point arc.
|
||||
- **Text**: After placing text element, trigger an inline edit prompt. For now, use a simple `prompt()` dialog or add `onTextEdit` callback.
|
||||
|
||||
### Task 6: Grid/Snap/Ortho toggle wiring
|
||||
File: `src/components/CanvasArea.tsx`
|
||||
|
||||
Required:
|
||||
- When `gridEnabled` prop changes: `renderEngine.setOptions({ showGrid: gridEnabled })` + re-render
|
||||
- When `snapEnabled` prop changes: `interaction.state.snapEnabled = snapEnabled` + `renderEngine.setOptions({ showSnapPoints: snapEnabled })` + re-render
|
||||
- When `orthoEnabled` prop changes: `interaction.state.ortho = orthoEnabled` + `renderEngine.setOptions({ showOrtho: orthoEnabled })` + re-render
|
||||
|
||||
## Constraints
|
||||
- TypeScript functional components, no inline styles (except where mockup uses style)
|
||||
- No styled-components, no Tailwind
|
||||
- `npx tsc --noEmit` must pass with 0 errors
|
||||
- `npx vite build` must succeed
|
||||
- Minimal changes — extend existing files, don't rewrite
|
||||
- Keep all existing CSS class names
|
||||
- Import ToolState type from interaction/index.ts where needed
|
||||
|
||||
## File Summary
|
||||
1. `src/types/ui.types.ts` — update CanvasAreaProps
|
||||
2. `src/components/CanvasArea.tsx` — expose engines, wire callbacks, add useEffects
|
||||
3. `src/App.tsx` — element state, undo/redo, command shortcuts, wire all callbacks
|
||||
4. `src/interaction/index.ts` — double-click handler, arc 3-point, text edit callback
|
||||
|
||||
## Test Criteria
|
||||
1. `npx tsc --noEmit` — 0 errors
|
||||
2. `npx vite build` — success
|
||||
3. Drawing a line: select Line tool → click start → move mouse → Enter → element appears
|
||||
4. Drawing a rect: select Rect tool → click corner → move mouse → Enter → element appears
|
||||
5. Drawing a circle: select Circle tool → click center → move mouse → Enter → element appears
|
||||
6. Polyline: select Polyline → click multiple points → double-click → element appears
|
||||
7. Command line: type 'L' → line tool activates
|
||||
8. Undo/Redo: draw element → Ctrl+Z → element disappears → Ctrl+Y → element reappears
|
||||
9. Grid toggle: click grid button → grid appears/disappears
|
||||
10. Snap toggle: click snap button → snap points appear/disappear on hover
|
||||
Reference in New Issue
Block a user