task(A4.1): wire dispatcher to canvas - doc bridge, selection bridge, activeTool sync
This commit is contained in:
@@ -14,6 +14,9 @@ import { GroupManager } from '../tools/modification/GroupTool';
|
|||||||
import { formatCoordinate } from '../utils/format';
|
import { formatCoordinate } from '../utils/format';
|
||||||
import { InteractionDispatcher } from '../interaction/dispatcher';
|
import { InteractionDispatcher } from '../interaction/dispatcher';
|
||||||
import { logger } from '../utils/logger';
|
import { logger } from '../utils/logger';
|
||||||
|
import { CADDocument } from '../kernel/document/CADDocument';
|
||||||
|
import { YjsDocument } from '../crdt/YjsDocument';
|
||||||
|
import { pluginRegistry } from '../plugins';
|
||||||
|
|
||||||
const CanvasArea: React.FC<CanvasAreaProps> = ({
|
const CanvasArea: React.FC<CanvasAreaProps> = ({
|
||||||
cursorPos, viewMode, onViewChange, gridEnabled, orthoEnabled, snapEnabled,
|
cursorPos, viewMode, onViewChange, gridEnabled, orthoEnabled, snapEnabled,
|
||||||
@@ -29,6 +32,8 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
|
|||||||
const renderEngineRef = useRef<RenderEngine | null>(null);
|
const renderEngineRef = useRef<RenderEngine | null>(null);
|
||||||
const interactionRef = useRef<InteractionEngine | null>(null);
|
const interactionRef = useRef<InteractionEngine | null>(null);
|
||||||
const dispatcherRef = useRef<InteractionDispatcher | null>(null);
|
const dispatcherRef = useRef<InteractionDispatcher | null>(null);
|
||||||
|
/** Bereits an onElementCreated gemeldete V2-Element-IDs (verhindert Doppelmeldung bei jedem onChanged-Frame). */
|
||||||
|
const announcedV2Ids = useRef<Set<string>>(new Set());
|
||||||
const spatialIndexRef = useRef<SpatialIndex | null>(null);
|
const spatialIndexRef = useRef<SpatialIndex | null>(null);
|
||||||
const layerManagerRef = useRef<LayerManager | null>(null);
|
const layerManagerRef = useRef<LayerManager | null>(null);
|
||||||
const selectionEngineRef = useRef<SelectionEngine | null>(null);
|
const selectionEngineRef = useRef<SelectionEngine | null>(null);
|
||||||
@@ -47,17 +52,38 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
|
|||||||
canvas, zoomPan, renderEngine, snapEngine, selectionEngine, spatialIndex, layerManager,
|
canvas, zoomPan, renderEngine, snapEngine, selectionEngine, spatialIndex, layerManager,
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── Task A2: V2-Tool-Dispatcher hinter Feature-Flag ──
|
// ── Task A2/A4: V2-Tool-Dispatcher hinter Feature-Flag ──
|
||||||
// Flag VITE_TOOL_DISPATCHER=v2 (in .env / Shell): aktiviert den neuen
|
// Flag VITE_TOOL_DISPATCHER=v2: aktiviert den InteractionDispatcher UND
|
||||||
// InteractionDispatcher parallel zur Legacy InteractionEngine.
|
// verdrahtet ihn mit einem lokalen CADDocument + SelectionBridge (Task A4.1).
|
||||||
// Tools mit handlers werden dann über die Plugin-API v2 geroutet.
|
|
||||||
if (import.meta.env.VITE_TOOL_DISPATCHER === 'v2') {
|
if (import.meta.env.VITE_TOOL_DISPATCHER === 'v2') {
|
||||||
|
const ydoc = new YjsDocument();
|
||||||
|
ydoc.data.layers.set('layer-0', {
|
||||||
|
id: 'layer-0', name: 'Standard', visible: true, locked: false,
|
||||||
|
color: '#ffffff', lineType: 'solid', transparency: 0, sortOrder: 0, parentId: null,
|
||||||
|
} as never);
|
||||||
|
const v2Doc = new CADDocument(ydoc);
|
||||||
|
// Committete V2-Elemente fließen über den etablierten Kanal in UI/State:
|
||||||
|
v2Doc.onChanged(() => {
|
||||||
|
for (const el of v2Doc.getAllElements()) {
|
||||||
|
if (!announcedV2Ids.current.has(el.id)) {
|
||||||
|
announcedV2Ids.current.add(el.id);
|
||||||
|
onElementCreated(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
dispatcherRef.current = new InteractionDispatcher(canvas, {
|
dispatcherRef.current = new InteractionDispatcher(canvas, {
|
||||||
zoomPan,
|
zoomPan,
|
||||||
setStatus: (msg) => {
|
setStatus: (msg) => {
|
||||||
/* StatusBar-Bridge folgt in A3 */
|
/* StatusBar-Bridge folgt in A4 */
|
||||||
},
|
},
|
||||||
setPreview: (el) => renderEngine.setPreviewElement(el as CADElement | null),
|
setPreview: (el) => renderEngine.setPreviewElement(el as CADElement | null),
|
||||||
|
getDoc: () => v2Doc,
|
||||||
|
getSelectionBridge: () => ({
|
||||||
|
getIds: () => Array.from(selectionEngine.getSelectedIds()),
|
||||||
|
setIds: (ids) => selectionEngine.selectByIds(ids, false),
|
||||||
|
hitTest: (wx, wy, tol) => renderEngine.hitTest(wx, wy, tol),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
logger.info('InteractionDispatcher v2 aktiviert (VITE_TOOL_DISPATCHER=v2)');
|
logger.info('InteractionDispatcher v2 aktiviert (VITE_TOOL_DISPATCHER=v2)');
|
||||||
}
|
}
|
||||||
@@ -249,6 +275,11 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
|
|||||||
const interaction = interactionRef.current;
|
const interaction = interactionRef.current;
|
||||||
if (!interaction) return;
|
if (!interaction) return;
|
||||||
interaction.setTool(activeTool as ToolType);
|
interaction.setTool(activeTool as ToolType);
|
||||||
|
// Task A4.1: V2-Werkzeuge zusätzlich an den Dispatcher routen (Flag aktiv).
|
||||||
|
// Legacy bleibt parallel aktiv für noch nicht migrierte Tools.
|
||||||
|
dispatcherRef.current?.setActive(
|
||||||
|
pluginRegistry.getToolV2(activeTool) ? activeTool : null,
|
||||||
|
);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [activeTool]);
|
}, [activeTool]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user