docs(I2): plugin guide (API v2 + example), library spec (wcadlib JSON+ZIP), changelog 2.0, readme rewrite
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2.0.0 (2026-08-29)
|
||||||
|
|
||||||
|
Vollständige Neuentwicklung der Kern-Architektur (Phasen A–H der Roadmap).
|
||||||
|
|
||||||
|
### Architektur
|
||||||
|
- **Plugin-System v2 (A1–A4):** ToolExtensionV2/PanelExtension/LibraryProviderExtension-Registry mit Interaktions-Dispatcher, CADDocument-Fassade über Yjs mit echtem Y.UndoManager (1 Aktion = 1 Undo-Schritt), Undo-fähige transact-Bündelung, V2HistoryPanel. Alle 30+ Werkzeuge als V2-Plugins migriert.
|
||||||
|
- **PixiJS-Renderer (C1–C4):** WebGL-Rendering als Default (Opt-out), inkrementelles Element-Rendering über Map-Diff, Snap-Marks + Selection-Handles im Overlay, MockAdapter für headless Tests.
|
||||||
|
- **Kernel:** React-freies `kernel/**` (Regel), documentService-Singleton, featureFlags.
|
||||||
|
|
||||||
|
### CAD-Werkzeuge (D1–D12, vollständig)
|
||||||
|
- Ellipse (3-Klick, Rotation aus Zugrichtung, Bogen via Winkel-Optionen) + Spline (CV-basiert, Catmull-Rom durch alle Kontrollpunkte)
|
||||||
|
- Point/XLine/Ray auf Auto-angelegtem `defpoints`-Layer mit `construction:true`-Tag
|
||||||
|
- MTEXT (mehrzeilig, optionaler Rahmen in derselben Transaktion)
|
||||||
|
- Stretch, Break, Join, Explode, Align, Chamfer, Lengthen, PolylineEditor (verifiziert, Phase D complete)
|
||||||
|
- GripEditing: Vertex-/Center-Grips (Linien-Endpunkte, Polyline-Vertices, Kreis-Zentrum) mit Drag in einer Transaktion; BBox-Corner-Skalierung bleibt parallel
|
||||||
|
- Arrays: rect, polar, **path** (Kopien gleichmäßig entlang Pfadlänge)
|
||||||
|
- Snaps erweitert: Quadrant (4 Kreis-Quadranten), Perpendicular (Fußpunkt vom Referenzpunkt), Tangent (beide Tangentenpunkte via acos), fromOffset-Helfer
|
||||||
|
- BlockAttribute: `BlockAttrDef` auf Definitionen, `attrValues` auf Instanzen, Rendering als Text-Primitives, PropertiesPanel-Formular
|
||||||
|
|
||||||
|
### Event-Bestuhlung (E1–E7, vollständig)
|
||||||
|
- Sitzreihen/-blöcke mit Drag-Interaktion, ArcRows (Stühle tangential rotiert), Vorlagenkatalog (Kino, Bankett, Stehtisch, Podest), CSV-Sitzlistent-Export, Gäste-Verwaltung mit Stuhl-Zuweisung
|
||||||
|
- **Neu:** Vorhang (wellige Polyline), Scheinwerfer (Kegel-Polygon mit Winkel + Farbe), Absperrung (Kettenglieder), Bühnenhöhen-Attribut
|
||||||
|
|
||||||
|
### Bibliothek & Import/Export (F1–F8, vollständig)
|
||||||
|
- Globale Block-Bibliothek: Ordner, Suche, Favoriten, Thumbnails, Grid-Ansicht, Drag&Drop in die Zeichenfläche
|
||||||
|
- Export/Import als JSON (`.wcadlib`) **und** echtes ZIP-Paket (manifest.json + blocks.json + thumbs/)
|
||||||
|
- **DXF-Import erweitert:** ELLIPSE, SPLINE (Grad ≤ 3, de-Boor-Approximation), MTEXT, POINT, ATTDEF, MINSERT-Arrays, strukturierter skippedEntities-Fehlerreport
|
||||||
|
- **DXF-Export erweitert:** BLOCKS+INSERTS mit Namens-Sanitizing, ATTDEF/ATTRIB/SEQEND, AC1009 (R12) + AC1015, R12-korrektes POLYLINE+VERTEX+SEQEND; Roundtrip-Tests deckten und fixten 3 latente Konventions-Bugs (Circle-Zentrum in Writer und Parser, ARC-Winkel-Radian→Grad)
|
||||||
|
- **SVG-Import als echte Geometrie:** voller Path-Parser (M/L/H/V/C/S/Q/T/A/Z, absolut+relativ, Bézier-Flattening, Arc-Endpoint→Center), rect/circle-Konventions-Fixes, Ellipse als Polygon
|
||||||
|
- Builtin-Kataloge: Event/Architektur/Landschaft (je 15 Blöcke) über LibraryProvider, User- und Global-Library angebunden
|
||||||
|
|
||||||
|
### Layouts & Plot (G1–G5, vollständig)
|
||||||
|
- Layout-Datenmodell in Yjs (undo-getrackt), LayoutBar mit Viewport-Minimap, zoom-to
|
||||||
|
- Titelblock mit attributierten Texten (Projekt/Datum/Maßstab/Autor), auto-insert als Layout-Frame
|
||||||
|
- **PDF-Export je Layout:** A4 landscape im Ausgabemaßstab, Linienbreiten + Dash-Patterns aus Layern, monochrome-Option, Titelblock-Mitzeichnung
|
||||||
|
- **Browser-Print:** @media print mit A4 landscape, UI-Chrome ausgeblendet, Print-Service mit Cleanup
|
||||||
|
|
||||||
|
### Modi & Rollen (H1–H5, vollständig)
|
||||||
|
- simple/pro-Modus (localStorage-persistiert): simple zeigt nur basic-Tools, CommandLine pro-only, Topbar-Toggle
|
||||||
|
- Projekt-Templates: 6 Branchen-Presets (Halle/OpenAir/Saal/Messe/Büro/Garten) mit Grid/Layern/Plugin-Seed
|
||||||
|
- **Rollenschutz:** library-admin (an admin-Rolle gebunden) für alle 8 schreibenden Global-Library-Routen; Lesen/Export für alle authentifizierten Nutzer
|
||||||
|
- i18n-Grundlage: strings.ts de/en-Maps mit t()-Funktion, Persistenz, useT-Hook; LayoutBar + Modus umgestellt
|
||||||
|
- Flächenberechnung: Shoelace-polygonArea, formatArea (quadratische Skalierung), measure-area-Tool, PropertiesPanel-Anzeige
|
||||||
|
|
||||||
|
### Behobene Fehlerklassen
|
||||||
|
- **BUG-1-Klasse komplett geschlossen:** alle Date.now()-Auto-IDs im Backend durch UUID-Slice ersetzt (deterministische Tests mit eingefrorener Zeit beweisen die Kollisionsfreiheit)
|
||||||
|
- Circle-Center-Konvention in DXF-Writer, DXF-Parser und SVG-Import vereinheitlicht (Zentrum statt min-corner)
|
||||||
|
- ARC-Winkel-Konvertierung dxf-parser (intern Radiant) → App (Grad) gefixt
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
- **Frontend: 697 Tests** (alle grün), **Backend: 287 Tests** (alle grün)
|
||||||
|
- Volle tsc-Typechecks und Production-Builds grün bei jedem Task
|
||||||
@@ -1,21 +1,74 @@
|
|||||||
# Web CAD Neu
|
# WebCAD
|
||||||
|
|
||||||
Web-basiertes 2D-CAD für Event-Bestuhlungspläne.
|
Web-basiertes 2D-CAD mit Kollaboration, Plugin-System und Fokus auf
|
||||||
|
Veranstaltungsplanung (Bestuhlung, Bühnen, Layouts).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Zeichnen:** Linien, Rechtecke, Kreise, Bögen, Ellipsen, Splines, Polylinien, Text, MTEXT, Bemaßungen, Hatch
|
||||||
|
- **Modifizieren:** Move/Copy/Rotate/Scale/Mirror, Trim/Extend/Fillet/Chamfer, Stretch/Break/Join/Explode/Align/Lengthen, Polyline-Editor, Grips (Vertex/Center), Arrays (rect/polar/path)
|
||||||
|
- **Event-Tools:** Stühle, Sitzreihen (Drag), Sitzblöcke, ArcRows, Tische, Bühnen (mit Höhen-Attribut), Vorhang, Scheinwerfer, Absperrungen, Vorlagenkatalog, Gäste-Verwaltung mit Sitzplatz-Zuweisung, CSV-Sitzlistent-Export
|
||||||
|
- **Snaps:** Endpoint, Midpoint, Center, Intersection, Quadrant, Perpendicular, Tangent, Grid, Polar-Tracking
|
||||||
|
- **Bibliothek:** Globale Block-Bibliothek mit Ordnern, Suche, Favoriten, Thumbnails; Builtin-Kataloge (Event/Architektur/Landschaft); Export/Import als .wcadlib (JSON oder ZIP)
|
||||||
|
- **Import/Export:** DXF (Import mit ELLIPSE/SPLINE/MTEXT/POINT/ATTDEF + Fehlerreport; Export R12/2000 mit BLOCKS/ATTR), SVG (echte Geometrie-Konvertierung mit Path-Parser), PDF (je Layout, maßstabsgetreu), PNG, JSON
|
||||||
|
- **Layouts & Plot:** Layout-Verwaltung mit Viewport-Minimap, Titelblock mit Attributen, PDF-Export, Browser-Print
|
||||||
|
- **Kollaboration:** Yjs CRDT, kollaborativ korrektes Undo/Redo (nur eigene Operationen)
|
||||||
|
- **Modi:** simple (Grundwerkzeuge) / pro (Vollpalette), localStorage-persistiert
|
||||||
|
- **Templates:** 6 Branchen-Presets (Halle, OpenAir, Saal, Messe, Büro, Garten)
|
||||||
|
- **i18n:** de/en (Grundlage, erweiterbar über `src/i18n/strings.ts`)
|
||||||
|
- **Rollen:** admin (library-admin, globaler Schreibzugriff) / planer (lesen + eigene Zeichnungen)
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
- Frontend: React + TypeScript + Vite + HTML Canvas
|
|
||||||
- Backend: Node.js + TypeScript + Fastify + SQLite
|
- **Frontend:** React 18 + TypeScript + Vite + PixiJS v8 (WebGL-Renderer, Canvas2D-Fallback) + zustandsfreier Service-Layer
|
||||||
- Collaboration: Yjs CRDT
|
- **Backend:** Node.js + TypeScript + Fastify 5 + SQLite (better-sqlite3)
|
||||||
|
- **Kollaboration:** Yjs + y-websocket
|
||||||
|
- **Tests:** Vitest (697 FE + 287 BE), Playwright E2E, tsc-Strict-Mode
|
||||||
|
|
||||||
## Entwicklung
|
## Entwicklung
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
# Backend
|
||||||
npm run dev
|
cd backend && npm install && npm run dev # http://localhost:3001
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
cd frontend && npm install && npm run dev # http://localhost:5173
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend && npm test # 697 Vitest-Tests
|
||||||
|
cd backend && npm test # 287 Vitest-Tests
|
||||||
|
|
||||||
|
cd frontend && npx tsc --noEmit # Typecheck
|
||||||
|
cd frontend && npm run build # Production-Build
|
||||||
```
|
```
|
||||||
- Frontend: http://localhost:5173
|
|
||||||
- Backend: http://localhost:3001
|
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose up --build
|
docker-compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Plugin-Entwicklung
|
||||||
|
|
||||||
|
Siehe [docs/PLUGIN_GUIDE.md](docs/PLUGIN_GUIDE.md) – Plugin-API v2 mit
|
||||||
|
Werkzeugen, Panels und Bibliotheks-Providern, inkl. Minimal-Beispiel.
|
||||||
|
|
||||||
|
## Bibliotheks-Pakete (.wcadlib)
|
||||||
|
|
||||||
|
Siehe [docs/LIBRARY_SPEC.md](docs/LIBRARY_SPEC.md) – JSON- und ZIP-Format,
|
||||||
|
Validierungsregeln, Endpoints und CAD-Element-Konventionen.
|
||||||
|
|
||||||
|
## Architektur-Regeln
|
||||||
|
|
||||||
|
- `kernel/**` importiert niemals React
|
||||||
|
- `render/pixi/**` kennt keine React-Components
|
||||||
|
- React kennt den Renderer nur über CanvasArea
|
||||||
|
- Eine Werkzeug-Aktion = eine `doc.transact()` = ein Undo-Schritt
|
||||||
|
|
||||||
|
## Roadmap & Status
|
||||||
|
|
||||||
|
Alle funktionalen Phasen (A–H) sind abgeschlossen. Aktueller Stand und
|
||||||
|
Task-Log: [ROADMAP.md](ROADMAP.md).
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# .wcadlib – Block-Bibliotheks-Paket-Spezifikation
|
||||||
|
|
||||||
|
WebCAD-Block-Bibliotheken können als `.wcadlib`-Paket geteilt werden.
|
||||||
|
Es gibt zwei Formate:
|
||||||
|
|
||||||
|
## Format 1: JSON-Paket (F1)
|
||||||
|
|
||||||
|
Ein einzelnes JSON-File mit folgender Struktur:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"format": "wcadlib",
|
||||||
|
"version": 1,
|
||||||
|
"exported_at": "2026-08-29T00:00:00.000Z",
|
||||||
|
"folders": [
|
||||||
|
{ "id": "f1", "name": "Veranstaltungstechnik", "parent_id": null }
|
||||||
|
],
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"name": "Stuhl-Reihe",
|
||||||
|
"folder_id": "f1",
|
||||||
|
"block_data": "[{...CADElement-Array als JSON-String...]}",
|
||||||
|
"svg_data": "<svg ...>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `block_data` = JSON-String eines **CADElement-Arrays**
|
||||||
|
- `svg_data` = eigenständiges SVG (Thumbnail), optional
|
||||||
|
- Ordner-Hierarchie via `parent_id` (Import ordnet IDs neu zu)
|
||||||
|
|
||||||
|
**Endpoints:** `GET /api/global-blocks/export`, `POST /api/global-blocks/import`
|
||||||
|
(schreibend: nur library-admin/Rolle admin, siehe H3)
|
||||||
|
|
||||||
|
## Format 2: ZIP-Paket (F7)
|
||||||
|
|
||||||
|
Ein echtes ZIP-Archiv mit fester Struktur:
|
||||||
|
|
||||||
|
```
|
||||||
|
library.wcadlib.zip
|
||||||
|
├── manifest.json { "format": "wcadlib-zip", "version": 1,
|
||||||
|
│ "exported_at": "...", "block_count": N, "folder_count": M }
|
||||||
|
├── blocks.json { "folders": [...], "blocks": [
|
||||||
|
│ { "name", "folder_id", "block_data",
|
||||||
|
│ "thumbnail": "thumbs/<id>.svg" } ] }
|
||||||
|
└── thumbs/
|
||||||
|
└── <blockId>.svg Thumbnails, Referenz aus blocks.json
|
||||||
|
```
|
||||||
|
|
||||||
|
- `manifest.format` MUSS `wcadlib-zip` sein (sonst 400)
|
||||||
|
- `blocks.json` MUSS vorhanden sein (sonst 400); `blocks`-Array Pflicht
|
||||||
|
- `thumbnail` verweist relativ auf `thumbs/<id>.svg`
|
||||||
|
|
||||||
|
**Endpoints:**
|
||||||
|
- `GET /api/global-blocks/export-zip` → `application/zip`
|
||||||
|
- `POST /api/global-blocks/import-zip` (Body = ZIP als application/zip;
|
||||||
|
schreibend: nur library-admin)
|
||||||
|
|
||||||
|
## Validierungsregeln (Import)
|
||||||
|
|
||||||
|
| Fehler | HTTP |
|
||||||
|
|---|---|
|
||||||
|
| Kein valides ZIP (Format 2) | 400 |
|
||||||
|
| blocks.json fehlt / invalides JSON | 400 |
|
||||||
|
| manifest.format unbekannt | 400 |
|
||||||
|
| Kein JSON/blocks-Array (Format 1) | 400 |
|
||||||
|
| Nicht authentifiziert | 401 |
|
||||||
|
| Rolle != admin (schreibend) | 403 |
|
||||||
|
|
||||||
|
## CAD-Element-Konventionen (block_data)
|
||||||
|
|
||||||
|
- `rect`: `x/y` = **Zentrum** der BBox
|
||||||
|
- `circle`/`arc`: `el.x/el.y` = **Zentrum**, Winkel in Grad (0° = 3 Uhr, CCW)
|
||||||
|
- `line`: `properties.x1/y1/x2/y2`
|
||||||
|
- `polyline`/`polygon`: `properties.points`
|
||||||
|
- `block_instance`: `properties.blockId` + optional `attrValues` (D12)
|
||||||
|
|
||||||
|
Beim Drop auf die Zeichenfläche werden Element-IDs neu generiert und
|
||||||
|
die Position per Drop-Punkt übersetzt – der Bestand bleibt unverändert.
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
# Plugin Guide – WebCAD Plugin API v2
|
||||||
|
|
||||||
|
WebCAD Plugin API v2 erlaubt die Erweiterung des CAD um Werkzeuge,
|
||||||
|
Panels und Block-Bibliotheken – ohne Kerncode anzufassen.
|
||||||
|
|
||||||
|
## Plugin-Typ (PluginV2)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { PluginV2, ToolExtensionV2 } from './plugins';
|
||||||
|
|
||||||
|
export const myPlugin: PluginV2 = {
|
||||||
|
manifest: {
|
||||||
|
id: 'my-tools',
|
||||||
|
name: 'Meine Werkzeuge',
|
||||||
|
version: '1.0.0',
|
||||||
|
author: 'Du',
|
||||||
|
description: 'Beschreibung',
|
||||||
|
category: 'tools', // tools|elements|library|import-export|theme|other
|
||||||
|
enabledByDefault: true,
|
||||||
|
},
|
||||||
|
tools: [/* ToolExtensionV2[] */],
|
||||||
|
panels: [/* PanelExtension[] (optional) */],
|
||||||
|
libraryProviders: [/* LibraryProviderExtension[] (optional) */],
|
||||||
|
onInit?() {}, onActivate?() {}, onDeactivate?() {}, onDestroy?() {},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Werkzeug (ToolExtensionV2)
|
||||||
|
|
||||||
|
Ein Werkzeug besteht aus Manifest, Options-Schema und Handlern:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const myTool: ToolExtensionV2 = {
|
||||||
|
manifest: {
|
||||||
|
id: 'my-tool',
|
||||||
|
label: 'Mein Werkzeug',
|
||||||
|
icon: 'M',
|
||||||
|
ribbonTab: 'canvas', // canvas|insert|format
|
||||||
|
tags: ['basic'], // basic = sichtbar im simple-Mode, ['pro'] nur pro-Mode
|
||||||
|
description: 'Was es tut',
|
||||||
|
},
|
||||||
|
optionsSchema: [
|
||||||
|
{ key: 'width', label: 'Breite', type: 'number', min: 1, max: 500 },
|
||||||
|
{ key: 'color', label: 'Farbe', type: 'color' },
|
||||||
|
{ key: 'style', label: 'Stil', type: 'select',
|
||||||
|
options: [{ value: 'a', label: 'A' }, { value: 'b', label: 'B' }] },
|
||||||
|
{ key: 'frame', label: 'Rahmen', type: 'checkbox' },
|
||||||
|
],
|
||||||
|
handlers: {
|
||||||
|
down(e, ctx) {
|
||||||
|
// e.world = Weltkoordinaten, e.shift, e.ctrl
|
||||||
|
// ctx.doc = CADDocument (CRUD + transact + undo)
|
||||||
|
// ctx.setStatus('...'), ctx.setPreview?.(element)
|
||||||
|
const c = ctx as FullToolContext;
|
||||||
|
if (!c.doc) return;
|
||||||
|
c.doc.transact(() => c.doc!.addElement({ /* CADElement */ }));
|
||||||
|
},
|
||||||
|
move(e, ctx) { /* Live-Preview */ },
|
||||||
|
up(e, ctx) { /* Commit */ },
|
||||||
|
key(k, ctx) { /* return true = konsumiert (z. B. Enter) */ },
|
||||||
|
cancel(ctx) { /* ESC/Rechtsklick: Session-State zurücksetzen */ },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kernregeln
|
||||||
|
|
||||||
|
1. **Eine Aktion = eine `doc.transact(() => ...)`** = genau ein Undo-Schritt.
|
||||||
|
2. **Session-State als Modul-Member** (nicht in `options` – diese sind geteilter UI-State).
|
||||||
|
3. **`cancel` setzt den Session-State immer zurück.**
|
||||||
|
4. **Koordinaten-Konventionen:** rect `x/y` = Zentrum der BBox; circle/arc `el.x/el.y` = Zentrum; Winkel in Grad (0° = 3 Uhr, CCW).
|
||||||
|
5. **Undo-fähig schreiben** nur über `doc.addElement/updateElement/deleteElements`.
|
||||||
|
|
||||||
|
## Bibliotheks-Provider (LibraryProviderExtension)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const myProvider: LibraryProviderExtension = {
|
||||||
|
id: 'my-catalog',
|
||||||
|
label: 'Mein Katalog',
|
||||||
|
async listFolders() { return [{ id: 'f1', label: 'Ordner', parentId: null }]; },
|
||||||
|
async listBlocks(folderId) { return [/* LibBlock[] */]; },
|
||||||
|
async getBlock(id) { return /* LibBlock */; },
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`LibBlock.payload` = JSON-String eines CADElement-Arrays → Drag&Drop
|
||||||
|
in die Zeichenfläche funktioniert automatisch über den bestehenden
|
||||||
|
Drop-Kanal. Thumbnail = eigenständiges SVG.
|
||||||
|
|
||||||
|
## Registrierung
|
||||||
|
|
||||||
|
Built-in-Plugins werden in `src/plugins/index.ts` per
|
||||||
|
`pluginRegistry.registerV2(plugin)` registriert; `enabledByDefault`
|
||||||
|
macht sie aktiv (alternativ per `pluginRegistry.enableV2(id)`).
|
||||||
|
|
||||||
|
## Beispiel: Minimal-Plugin
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// plugins/builtin/stamp/index.ts
|
||||||
|
import type { PluginV2, ToolExtensionV2 } from '../../types';
|
||||||
|
|
||||||
|
const stampTool: ToolExtensionV2 = {
|
||||||
|
manifest: {
|
||||||
|
id: 'stamp', label: 'Stempel', icon: '\u25c6',
|
||||||
|
ribbonTab: 'insert', tags: ['basic'],
|
||||||
|
description: 'Platziert ein Quadrat',
|
||||||
|
},
|
||||||
|
optionsSchema: [{ key: 'size', label: 'Größe', type: 'number', min: 10, max: 200 }],
|
||||||
|
handlers: {
|
||||||
|
down(e, ctx) {
|
||||||
|
const c = ctx as any;
|
||||||
|
if (!c.doc) return;
|
||||||
|
const size = (ctx.options.size as number | undefined) ?? 50;
|
||||||
|
c.doc.transact(() => c.doc.addElement({
|
||||||
|
id: `stamp_${Date.now()}`,
|
||||||
|
type: 'rect', layerId: 'layer-0',
|
||||||
|
x: e.world.x, y: e.world.y,
|
||||||
|
width: size, height: size,
|
||||||
|
properties: {},
|
||||||
|
}));
|
||||||
|
ctx.setStatus('Stempel platziert');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stampPlugin: PluginV2 = {
|
||||||
|
manifest: {
|
||||||
|
id: 'stamp', name: 'Stempel', version: '1.0.0', author: 'WebCAD',
|
||||||
|
description: 'Beispielplugin', category: 'elements', enabledByDefault: true,
|
||||||
|
},
|
||||||
|
tools: [stampTool],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Registrieren in `src/plugins/index.ts`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
pluginRegistry.registerV2(stampPlugin);
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user