Plugin Examples
About 2 min
Plugin Examples
This chapter provides a complete plugin development example.
Complete Plugin Example
// my-drawing-tools-plugin.ts
import type {
Plugin,
PluginManifest,
PluginContext,
CommandOptions,
RibbonButtonConfig
} from 'vjcad';
import {
Engine,
Point2D,
CircleEnt,
LineEnt,
PointInputOptions,
RealInputOptions,
IntegerInputOptions,
InputStatusEnum,
CadEvents
} from 'vjcad';
// ===== Command 1: Draw circle with centerlines =====
class CenterLineCircleCommand {
async main(): Promise<void> {
// Get center point
const centerOpt = new PointInputOptions("Specify center point:");
const centerResult = await Engine.getPoint(centerOpt);
if (centerResult.status !== InputStatusEnum.OK) return;
const center = centerResult.value;
// Get radius
const radiusOpt = new RealInputOptions("Specify radius:");
radiusOpt.defaultValue = 50;
const radiusResult = await Engine.getReal(radiusOpt);
if (radiusResult.status !== InputStatusEnum.OK) return;
const radius = radiusResult.value;
// Start undo group
Engine.undoManager.start_undoMark();
try {
// Create circle
const circle = new CircleEnt(center, radius);
circle.setDefaults();
// Create centerlines
const extend = radius * 0.2;
const hLine = new LineEnt(
new Point2D(center.x - radius - extend, center.y),
new Point2D(center.x + radius + extend, center.y)
);
const vLine = new LineEnt(
new Point2D(center.x, center.y - radius - extend),
new Point2D(center.x, center.y + radius + extend)
);
hLine.setDefaults();
vLine.setDefaults();
hLine.lineType = 'CENTER';
vLine.lineType = 'CENTER';
// Add entities
Engine.addEntities([circle, hLine, vLine], { recordUndo: true });
Engine.pcanvas.regen();
} finally {
Engine.undoManager.end_undoMark();
}
}
}
// ===== Command 2: Batch color modification =====
class BatchColorCommand {
async main(): Promise<void> {
// Select entities
const selResult = await Engine.getSelections();
if (selResult.status !== InputStatusEnum.OK || selResult.value.length === 0) {
return;
}
// Get color
const colorOpt = new IntegerInputOptions("Enter color index (1-255):");
colorOpt.defaultValue = 1;
const colorResult = await Engine.getInteger(colorOpt);
if (colorResult.status !== InputStatusEnum.OK) return;
// Modify color
Engine.setEntityColor(selResult.value, colorResult.value);
Engine.pcanvas.regen();
}
}
// ===== Plugin definition =====
const manifest: PluginManifest = {
id: 'drawing-tools',
name: 'Drawing Toolset',
version: '1.0.0',
author: 'WebCAD Team',
description: 'Provides additional drawing tool commands',
keywords: ['drawing', 'tool', 'circle']
};
const plugin: Plugin = {
manifest,
async onLoad(context: PluginContext): Promise<void> {
console.log('[Drawing Tools] Plugin loading...');
},
async onActivate(context: PluginContext): Promise<void> {
// Register commands
context.registerCommand('CLCIRCLE', 'Circle with Centerlines', CenterLineCircleCommand);
context.registerCommand('BATCHCOLOR', 'Batch Color Change', BatchColorCommand);
// Register icon
context.registerIcon('CLCIRCLE', `<svg viewBox="0 0 24 24">
<circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/>
<line x1="4" y1="12" x2="20" y2="12" stroke="currentColor" stroke-dasharray="2,2"/>
<line x1="12" y1="4" x2="12" y2="20" stroke="currentColor" stroke-dasharray="2,2"/>
</svg>`);
// Add to Ribbon
const buttons: RibbonButtonConfig[] = [
{ cmd: 'CLCIRCLE', label: 'Center Circle', tooltip: 'Draw a circle with centerlines' },
{ cmd: 'BATCHCOLOR', label: 'Batch Color', tooltip: 'Change entity colors in batch' }
];
context.addRibbonGroup('home', {
id: 'drawing-tools',
label: 'Drawing Tools',
primaryButtons: buttons
});
// Listen to events
context.on(CadEvents.EntityAdded, (args) => {
console.log(`[Drawing Tools] New entity: ${args.entity.type}`);
});
console.log('[Drawing Tools] Plugin activated');
},
async onDeactivate(context: PluginContext): Promise<void> {
context.unregisterCommand('CLCIRCLE');
context.unregisterCommand('BATCHCOLOR');
context.removeRibbonGroup('home', 'drawing-tools');
console.log('[Drawing Tools] Plugin deactivated');
},
async onUnload(context: PluginContext): Promise<void> {
console.log('[Drawing Tools] Plugin unloaded');
}
};
export default plugin;Plugin Loading Methods
import { PluginManager, PluginSourceType } from 'vjcad';
const pluginMgr = PluginManager.getInstance();
// Load from URL
await pluginMgr.loadPlugin({
type: PluginSourceType.Url,
js: 'https://example.com/plugins/my-plugin.js',
css: 'https://example.com/plugins/my-plugin.css',
autoActivate: true
});
// Load from code content
await pluginMgr.loadPlugin({
type: PluginSourceType.Content,
js: pluginJsCode,
autoActivate: true
});Plugin Management
const pluginMgr = PluginManager.getInstance();
// Get loaded plugins
const plugins = pluginMgr.getLoadedPlugins();
// Activate plugin
await pluginMgr.activatePlugin('my-plugin');
// Deactivate plugin
await pluginMgr.deactivatePlugin('my-plugin');
// Unload plugin
await pluginMgr.unloadPlugin('my-plugin');
// Get plugin state
const state = pluginMgr.getPluginState('my-plugin');Plugin Development Tips
Resource Cleanup
Clean up all registered resources in onDeactivate:
async onDeactivate(context: PluginContext): Promise<void> {
// Unregister command
context.unregisterCommand('MYCMD');
// Remove UI element
context.removeRibbonGroup('home', 'my-group');
// Events are cleaned automatically, but can also be cleaned manually
}Error Handling
async onActivate(context: PluginContext): Promise<void> {
try {
// Initialization logic
} catch (error) {
console.error('Plugin activation failed:', error);
throw error; // Throwing sets the plugin state to Error
}
}Dependency Management
const manifest: PluginManifest = {
id: 'my-plugin',
name: 'My Plugin',
version: '1.0.0',
dependencies: ['base-tools'], // Dependent plugins
minEngineVersion: '1.0.0' // Minimum engine version
};Next Steps
- Event System - event types
- UI Extension - detailed Ribbon configuration