Files
web-cad/frontend/src/plugins/builtin/core-annotate/index.ts
T

142 lines
4.6 KiB
TypeScript
Raw Normal View History

/**
* core-annotate Built-in V2-Plugin (Task A4.4).
*
* Werkzeuge: text (Platzierung — Inhalt via InlineTextEditor/PropertiesPanel,
* Bestandskanal onTextEdit bleibt), dimension (2-Punkt linear), leader
* (2-Punkt Pfeil+Label).
*/
import type { PluginV2, ToolExtensionV2, FullToolContext } from '../../types';
import type { CADElement } from '../../../types/cad.types';
import type { Pt } from '../../../tools/modification/geometry';
const uid = (prefix: string): string =>
`${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
/** Gemeinsamer 2-Punkt-Sitzungsstart für dimension/leader. */
let twoPointStart: Pt | null = null;
function optsOf(ctx: FullToolContext): { stroke: string; layerId: string } {
return {
stroke: (ctx.options.strokeColor as string | undefined) ?? '#e0e0e0',
layerId: (ctx.options.layerId as string | undefined) ?? 'layer-0',
};
}
function buildDimension(start: Pt, end: Pt, ctx: FullToolContext): CADElement {
const o = optsOf(ctx);
return {
id: uid('dim'),
type: 'dimension',
layerId: o.layerId,
x: (start.x + end.x) / 2,
y: (start.y + end.y) / 2,
width: Math.hypot(end.x - start.x, end.y - start.y), // Legacy: dist als Breite
height: 20,
properties: { x1: start.x, y1: start.y, x2: end.x, y2: end.y },
} as unknown as CADElement;
}
function buildLeader(start: Pt, end: Pt, ctx: FullToolContext): CADElement {
const o = optsOf(ctx);
return {
id: uid('leader'),
type: 'leader',
layerId: o.layerId,
x: end.x,
y: end.y,
width: Math.abs(end.x - start.x),
height: Math.abs(end.y - start.y),
properties: { x1: start.x, y1: start.y, x2: end.x, y2: end.y, text: '', fontSize: 12, stroke: o.stroke, strokeWidth: 1 },
} as unknown as CADElement;
}
/** Generischer 2-Punkt-Annotate-Fluss (down→Preview→up commit). */
function make2PointAnnotate(
id: 'dimension' | 'leader',
label: string,
icon: string,
build: (a: Pt, b: Pt, ctx: FullToolContext) => CADElement,
): ToolExtensionV2 {
return {
manifest: { id, label, icon, ribbonTab: 'format', tags: ['basic'] },
optionsSchema: [{ key: 'strokeColor', label: 'Farbe', type: 'color' }],
handlers: {
down(e, ctx) {
twoPointStart = e.world;
ctx.setStatus(`${label}: Startpunkt gesetzt Ende wählen`);
},
move(e, ctx) {
if (!twoPointStart) return;
ctx.setPreview?.(build(twoPointStart, e.world, ctx as FullToolContext));
},
up(e, ctx) {
const c = ctx as FullToolContext;
if (!twoPointStart || !c.doc) { twoPointStart = null; return; }
const el = build(twoPointStart, e.world, c);
c.doc.transact(() => c.doc!.addElement(el));
twoPointStart = null;
ctx.setPreview?.(null);
ctx.setStatus(`${label} erstellt (${el.id})`);
},
cancel(ctx) {
twoPointStart = null;
ctx.setPreview?.(null);
ctx.setStatus(`${label} abgebrochen`);
},
},
};
}
/**
* text-Werkzeug (A4.4): Klick platziert Textelement mit leerem Inhalt;
* Bearbeitung läuft über den bestehenden InlineTextEditor/onTextEdit-Kanal.
*/
export const textTool: ToolExtensionV2 = {
manifest: {
id: 'text',
label: 'Text',
icon: 'T',
ribbonTab: 'format',
tags: ['basic'],
description: 'Text platzieren und über Editor beschriften',
},
optionsSchema: [{ key: 'fontSize', label: 'Größe', type: 'number', min: 6, max: 72 }],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc) return;
const layerId = (c.options.layerId as string | undefined) ?? 'layer-0';
const fontSize = (c.options.fontSize as number | undefined) ?? 12;
const el = {
id: uid('text'),
type: 'text',
layerId,
x: e.world.x,
y: e.world.y,
width: 100,
height: 20,
properties: { text: '', fontSize },
} as unknown as CADElement;
c.doc.transact(() => c.doc!.addElement(el));
ctx.setStatus(`Text platziert (${el.id}) now via Editor`);
},
},
};
export const dimensionTool: ToolExtensionV2 = make2PointAnnotate('dimension', 'Bemaßung', '\u2194', buildDimension);
export const leaderTool: ToolExtensionV2 = make2PointAnnotate('leader', 'Leader', '\u21b1', buildLeader);
/** V2-Plugin: Beschriftung/Bemaßung (A4.4). */
export const coreAnnotatePlugin: PluginV2 = {
manifest: {
id: 'core-annotate',
name: 'Beschriftung (Kern)',
version: '1.0.0',
author: 'web-cad team',
description: 'Text, Bemaßung, Leader (V2).',
category: 'tools',
enabledByDefault: true,
},
tools: [textTool, dimensionTool, leaderTool],
};