CanvasEngine API
CanvasEngine 是画布引擎的核心类,负责渲染循环、视口管理、插件协调和性能优化。
构造函数
constructor(options: EngineOptions)
创建引擎实例。
EngineOptions
interface EngineOptions {
// 必需:容器元素
container: HTMLElement;
// 可选:画布尺寸(默认使用容器尺寸)
width?: number;
height?: number;
// 可选:背景颜色
background?: string;
// 可选:运行模式(默认 'edit')
mode?: 'edit' | 'view' | 'none';
// 可选:交互控制配置
interactionConfig?: InteractionConfig;
// 可选:边快照模式(默认 'auto')
edgeSnapshot?: 'auto' | 'off' | 'always';
// 可选:拖拽时边渲染阈值
dragEdgeRenderThreshold?: {
nodes?: number; // 默认 400
edges?: number; // 默认 800
};
// 可选:标签渲染阈值
labelRenderThreshold?: {
nodes?: number; // 默认 1500
edges?: number; // 默认 3000
};
// 可选:激进降质阈值
aggressiveDegradation?: {
totalNodes?: number; // 默认 5000
totalEdges?: number; // 默认 10000
};
// 可选:空间索引配置
spatialIndex?: {
enabled?: boolean; // 默认 true
maxItems?: number; // 默认 16
maxDepth?: number; // 默认 8
disableDuringDrag?: boolean; // 默认 true
padding?: number; // 默认 32
};
}
InteractionConfig
interface InteractionConfig {
enableZoom?: boolean; // 是否允许缩放(默认 true)
enablePan?: boolean; // 是否允许平移(默认 true)
enableSelection?: boolean; // 是否允许节点选中(默认 true)
enableDrag?: boolean; // 是否允许节点拖拽(默认 true)
enableResize?: boolean; // 是否允许节点缩放(默认 true)
enableRotate?: boolean; // 是否允许节点旋转(默认 true)
}
示例
const engine = new CanvasEngine({
container: document.getElementById('canvas')!,
width: 1200,
height: 800,
background: '#ffffff',
mode: 'edit',
interactionConfig: {
enableZoom: true,
enablePan: true,
enableSelection: true,
enableDrag: true
},
dragEdgeRenderThreshold: {
nodes: 400,
edges: 800
}
});
属性
canvas
readonly canvas: HTMLCanvasElement
Canvas DOM 元素。
ctx
readonly ctx: CanvasRenderingContext2D
2D 渲染上下文。
events
readonly events: EventBus<EngineEvents & { [key: string]: any }>
事件总线。详见 事件系统。
history
readonly history: CommandHistory
命令历史管理器。详见 命令历史。
graph
readonly graph: Graph
图形数据模型。详见 Graph API。
renderers
readonly renderers: RendererRegistry
渲染器注册表。详见 渲染器注册表。
plugins
readonly plugins: PluginManager
插件管理器。详见 插件管理器。
animations
readonly animations: AnimationManager
动画管理器。详见 动画管理器。
渲染控制
start()
start(): void
启动引擎渲染循环。每帧自动调用 render() 并触发 engine:tick 事件。
engine.start();
stop()
stop(): void
停止引擎渲染循环。
engine.stop();
render()
render(time: number): void
手动触发一次渲染(通常在停止状态下使用)。
参数:
time: 当前时间戳(通常来自performance.now())
engine.stop();
engine.render(performance.now()); // 渲染一帧
destroy()
destroy(): void
销毁引擎,清理所有资源(停止渲染、断开 ResizeObserver、移除事件监听器)。
engine.destroy();
视口管理
getScale()
getScale(): number
获取当前缩放比例。
const scale = engine.getScale(); // 例如 1.5
setScale()
setScale(scale: number): void
设置缩放比例(范围:0.1 ~ 10)。
engine.setScale(1.5);
getTranslation()
getTranslation(): { x: number; y: number }
获取当前平移量(屏幕空间)。
const { x, y } = engine.getTranslation();
setTranslation()
setTranslation(x: number, y: number): void
设置平移量(屏幕空间)。
engine.setTranslation(100, 50);
zoomAt()
zoomAt(factor: number, screenX: number, screenY: number): void
在指定屏幕坐标处缩放(保持该点世界坐标不变)。
参数:
factor: 缩放因子(例如 1.2 表示放大 20%)screenX: 屏幕 X 坐标screenY: 屏幕 Y 坐标
// 在鼠标位置放大 20%
engine.zoomAt(1.2, mouseX, mouseY);
fitView()
fitView(options?: {
selectionOnly?: boolean; // 仅适配选中节点(默认 false)
padding?: number; // 边距(默认 40)
minScale?: number; // 最小缩放(默认 0.1)
maxScale?: number; // 最大缩放(默认 10)
}): boolean
自动缩放和平移以适配节点。返回是否成功执行(无节点时返回 false)。
// 适配所有节点
engine.fitView({ padding: 50 });
// 仅适配选中节点
engine.fitView({ selectionOnly: true });
// 自定义缩放范围
engine.fitView({ minScale: 0.5, maxScale: 2 });
坐标转换
toScreen()
toScreen(world: { x: number; y: number }): { x: number; y: number }
世界坐标转屏幕坐标。
const screenPos = engine.toScreen({ x: 100, y: 100 });
toWorld()
toWorld(screen: { x: number; y: number }): { x: number; y: number }
屏幕坐标转世界坐标。
const worldPos = engine.toWorld({ x: clientX, y: clientY });
交互配置
getInteractionConfig()
getInteractionConfig(): Readonly<InteractionConfig>
获取当前交互配置。
const config = engine.getInteractionConfig();
console.log(config.enableDrag); // true/false
setInteractionConfig()
setInteractionConfig(config: Partial<InteractionConfig>): void
设置交互配置(部分更新)。
// 禁用拖拽和选中
engine.setInteractionConfig({
enableDrag: false,
enableSelection: false
});
// 恢复拖拽
engine.setInteractionConfig({
enableDrag: true
});
运行模式
getMode()
getMode(): 'edit' | 'view' | 'none'
获取当前运行模式。
const mode = engine.getMode(); // 'edit' | 'view' | 'none'
setMode()
setMode(mode: 'edit' | 'view' | 'none'): void
设置运行模式。影响部分插件的行为(如 DataTooltipPlugin 仅在 'edit' 模式下工作)。
engine.setMode('view'); // 切换到预览模式
主题管理
getTheme()
getTheme(): 'light' | 'dark'
获取当前主题。
const theme = engine.getTheme(); // 'light' | 'dark'
setTheme()
setTheme(
theme: 'light' | 'dark',
overrides?: Partial<{
background: string;
grid: { color?: string; alpha?: number };
guides: { color?: string };
minimap: {
background?: string;
borderColor?: string;
nodeColor?: string;
edgeColor?: string;
viewportStroke?: string;
viewportFill?: string;
};
}>
): void
设置主题。会自动应用到画布背景和支持主题的插件(GridPlugin、GuidesPlugin、MinimapPlugin)。
参数:
theme: 主题名称overrides: 可选的调色板覆盖
// 切换到深色主题
engine.setTheme('dark');
// 自定义背景色
engine.setTheme('light', {
background: '#f5f5f5',
grid: { color: '#e0e0e0' }
});
性能优化
setPanning()
setPanning(flag: boolean): void
设置平移状态(用于内部降质渲染)。通常由 PanZoomPlugin 调用。
engine.setPanning(true); // 进入平移模式
isCurrentlyPanning()
isCurrentlyPanning(): boolean
检查当前是否处于平移状态。
const isPanning = engine.isCurrentlyPanning();
setDraggingNodes()
setDraggingNodes(flag: boolean, count?: number): void
设置节点拖动状态(用于内部降质渲染)。通常由 DragPlugin 调用。
参数:
flag: 是否正在拖动count: 拖动的节点数量(可选,默认 0)
engine.setDraggingNodes(true, 5); // 开始拖动 5 个节点
isCurrentlyDraggingNodes()
isCurrentlyDraggingNodes(): boolean
检查当前是否处于节点拖动状态。
const isDragging = engine.isCurrentlyDraggingNodes();
getDraggingNodeCount()
getDraggingNodeCount(): number
获取当前拖动的节点数量。
const count = engine.getDraggingNodeCount();
getEdgeSnapshotMode()
getEdgeSnapshotMode(): 'auto' | 'off' | 'always'
获取当前边快照模式。
const mode = engine.getEdgeSnapshotMode();
setEdgeSnapshotMode()
setEdgeSnapshotMode(mode: 'auto' | 'off' | 'always'): void
设置边快照模式:
'auto'(默认):无动态流动效果时使用快照;有 flow 动画时每帧重建'off':关闭快照,改为每帧在 world-space 绘制边'always':始终使用快照(即使存在 flow 动画,动画会被"冻结")
// 关闭边快照(适用于边动画密集场景)
engine.setEdgeSnapshotMode('off');
// 强制使用快照(提升性能但禁用边动画)
engine.setEdgeSnapshotMode('always');
历史调试
getHistoryData()
getHistoryData(format?: 'object' | 'array'): any
获取历史数据(用于调试)。
参数:
format: 数据格式'object'(默认):返回结构化对象'array':返回扁平数组
const history = engine.getHistoryData('object');
console.log(history);
尺寸调整
resize()
resize(width: number, height: number): void
手动调整画布尺寸。通常不需要调用,引擎会自动监听容器尺寸变化。
engine.resize(1200, 800);
事件
引擎会触发以下事件:
engine:tick
{ time: number }
每帧触发,包含时间戳。
engine.events.on('engine:tick', ({ time }) => {
console.log('Frame time:', time);
});
engine:resize
{ width: number; height: number }
画布尺寸改变时触发。
engine.events.on('engine:resize', ({ width, height }) => {
console.log('Canvas resized:', width, height);
});
graph:change
{ reason: string }
图形数据改变时触发。
engine.events.on('graph:change', ({ reason }) => {
console.log('Graph changed:', reason);
});
engine:theme-change
{ theme: string }
主题改变时触发。
engine.events.on('engine:theme-change', ({ theme }) => {
console.log('Theme changed:', theme);
});
使用示例
完整初始化
import {
CanvasEngine,
RectRenderer,
GridPlugin,
DragPlugin,
PanZoomPlugin
} from '@fnt-agilejs/core';
// 创建引擎
const engine = new CanvasEngine({
container: document.getElementById('canvas')!,
background: '#ffffff',
mode: 'edit',
interactionConfig: {
enableZoom: true,
enablePan: true,
enableSelection: true,
enableDrag: true
}
});
// 注册渲染器
engine.renderers.register(new RectRenderer());
// 启用插件
engine.plugins.use(new GridPlugin({ size: 20, color: '#f0f0f0' }));
engine.plugins.use(new DragPlugin());
engine.plugins.use(new PanZoomPlugin());
// 添加节点
engine.graph.addNode({
id: 'node-1',
shape: 'rect',
position: { x: 100, y: 100 },
size: { width: 120, height: 80 }
});
// 启动渲染
engine.start();
// 适配视口
engine.fitView({ padding: 50 });
切换模式
// 切换到预览模式
engine.setMode('view');
engine.setInteractionConfig({
enableDrag: false,
enableSelection: false
});
// 切换回编辑模式
engine.setMode('edit');
engine.setInteractionConfig({
enableDrag: true,
enableSelection: true
});
性能监控
let frameCount = 0;
let lastTime = performance.now();
engine.events.on('engine:tick', ({ time }) => {
frameCount++;
const elapsed = time - lastTime;
if (elapsed >= 1000) {
const fps = frameCount / (elapsed / 1000);
console.log('FPS:', fps.toFixed(2));
if (fps < 30) {
console.warn('Low FPS detected, consider optimizations');
}
frameCount = 0;
lastTime = time;
}
});
性能优化建议
- 大规模场景:使用空间索引(默认启用)
- 边动画密集:考虑设置
edgeSnapshot: 'off' - 高频拖动:调整
dragEdgeRenderThreshold阈值 - 交互禁用:在特定场景禁用不必要的交互
- 批量操作:使用事务包裹多个命令