142 lines
4.6 KiB
TypeScript
142 lines
4.6 KiB
TypeScript
/**
|
||
* 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],
|
||
};
|