Meta2d.js 源码解读分析
📋 项目概述
Meta2d.js 是一个实时数据响应和交互的 2D 引擎,专门用于 Web 组态、物联网、数字孪生等场景。项目采用现代化的多包架构设计,使用 pnpm workspaces 进行包管理。
🏗️ 项目整体架构
1. 多包结构设计
packages/
├── core/ # 核心引擎,最重要的包 - 所有功能的基础
├── meta2d.js/ # 主包,统一导出 - 用户主要使用的入口
├── utils/ # 工具函数 - 通用工具和算法
├── flow-diagram/ # 流程图 - 业务流程图形组件
├── class-diagram/ # 类图 - UML类图组件
├── sequence-diagram/ # 时序图 - UML时序图组件
├── activity-diagram/ # 活动图 - UML活动图组件
├── form-diagram/ # 表单图 - 表单组件
├── chart-diagram/ # 图表图 - 集成echarts等图表库
├── fta-diagram/ # 故障树分析图 - 专业分析图形
├── le5le-charts/ # 图表组件 - 自研图表库
├── layout/ # 布局算法 - 自动布局相关
├── svg/ # SVG支持 - SVG图形处理
└── plugin-mind-/ # 思维导图相关插件
核心设计理念:
- 单一职责: 每个包负责特定领域功能
- 松耦合: 包之间通过接口交互
- 可扩展: 易于添加新的图形类型和功能
🎯 核心引擎设计 (@meta2d/core)
1. 主要类结构
Meta2d 主类 (core.ts - 6446行)
职责: 整个引擎的核心控制器和协调者
export class Meta2d {
store: Meta2dStore; // 全局数据存储和状态管理
canvas: Canvas; // 画布管理器
websocket: WebSocket; // WebSocket连接
mqttClient: MqttClient; // MQTT客户端
events: Record<number, Function>; // 事件处理器映射
map: ViewMap; // 缩略图管理
// ... 更多属性
}
核心功能模块:
-
数据管理层
store: 使用全局状态管理,支持响应式数据绑定- 历史记录管理: 支持 undo/redo 操作
- 数据序列化: 支持完整的数据导入导出
-
渲染引擎层
canvas: 多层画布架构,支持复杂场景渲染- 高性能绘制: 脏标记机制 + 视口裁剪优化
- 动画系统: 支持多种动画类型和时间函数
-
网络通信层
- WebSocket: 实时双向数据通信
- MQTT: 物联网设备数据接入
- HTTP: 传统数据接口调用
- SSE: 服务器推送事件
-
事件系统
- 完整的生命周期事件 (onAdd, onDestroy, onValue等)
- 鼠标交互事件 (onClick, onMouseEnter等)
- 自定义业务事件支持
Pen 图形对象 (pen/model.ts - 844行)
职责: 所有图形元素的基础数据模型
export interface Pen extends Rect {
// 基础属性
id?: string;
type?: PenType; // Node(节点) 或 Line(连线)
name?: string; // 图形类型名称,用于渲染器选择
visible?: boolean; // 可见性控制
locked?: LockState; // 锁定状态
// 样式属性
color?: string; // 前景色
background?: string; // 背景色
lineWidth?: number; // 线宽
borderRadius?: number; // 圆角
globalAlpha?: number; // 透明度
// 文本属性
text?: string;
fontSize?: number;
fontFamily?: string;
textAlign?: TextAlign;
textColor?: string;
// 几何属性
anchors?: Point[]; // 锚点定义
children?: string[]; // 子元素ID列表
connectedLines?: ConnectLine[]; // 连接的线条
// 动画属性
frames?: Pen[]; // 关键帧序列
duration?: number; // 动画时长
animateColor?: string; // 动画时的颜色
// 交互属性
input?: boolean; // 是否可输入
dropdownList?: Dropdown[]; // 下拉选项
events?: Event[]; // 事件配置
// 数据绑定
form?: FormItem[]; // 表单绑定
realTimes?: RealTime[]; // 实时数据配置
// 生命周期回调
onAdd?: (pen: Pen) => void;
onValue?: (pen: Pen) => void;
onClick?: (pen: Pen, e: Point) => void;
onDestroy?: (pen: Pen) => void;
// ... 更多回调函数
// 计算属性 (用于动画和渲染优化)
calculative?: {
worldRect?: Rect; // 世界坐标系矩形
worldAnchors?: Point[]; // 世界坐标系锚点
active?: boolean; // 激活状态
hover?: boolean; // 悬停状态
// ... 大量计算缓存属性
};
}
核心设计理念:
- 数据驱动: 所有图形都是数据对象,支持完整序列化
- 响应式更新: 数据变化自动触发重渲染
- 状态分离: 原始数据与计算状态分离,优化性能
- 扩展性强: 支持自定义属性和回调函数
🎨 渲染系统设计
多层画布架构
enum CanvasLayer {
CanvasTemplate = 1, // 模板层 - 背景模板图形
CanvasImageBottom, // 底部图片层 - 背景图片
CanvasMain, // 主画布层 - 主要图形内容
CanvasImage // 顶部图片层 - 前景图片
}
分层渲染的优势:
- 性能优化: 不同层独立渲染,减少不必要的重绘
- Z-Index控制: 精确控制图形层次关系
- 功能分离: 不同类型内容分层管理
渲染流程优化
// 核心渲染流程
render(patchFlags?: boolean | number) {
// 1. 脏标记检查
if (!this.needRender()) return;
// 2. 视口裁剪计算
const inViewPens = this.getInViewPens();
// 3. 分层渲染
this.renderLayers(inViewPens);
// 4. 清除脏标记
this.clearPatchFlags();
}
性能优化策略:
-
脏标记机制 (
patchFlags)- 只重绘需要更新的部分
- 支持细粒度的更新控制
-
视口裁剪 (
calcInView)- 只渲染可见区域内的图形
- 大幅提升大数据量场景性能
-
离屏渲染
- 复杂图形预渲染到离屏画布
- 缓存静态内容,减少重复计算
-
批量操作
- 多个修改操作合并为一次渲染
- 减少渲染调用次数
🚀 高性能架构设计
1. 数据结构优化
// 计算属性缓存机制
calculative?: {
// 世界坐标系缓存 - 避免重复计算
worldRect?: Rect;
worldAnchors?: Point[];
worldTextRect?: Rect;
// 文本布局缓存 - 文本测量开销大
textLines?: string[];
textLineWidths?: number[];
// 渲染状态缓存 - 减少状态计算
active?: boolean;
hover?: boolean;
visible?: boolean;
// 图片资源缓存 - 避免重复加载
img?: HTMLImageElement;
backgroundImg?: HTMLImageElement;
}
2. 渲染性能优化
视口管理:
// 只渲染可见区域
calcInView(pen: Pen, store: Meta2dStore): boolean {
if (!pen.calculative.worldRect) return false;
return rectInRect(
pen.calculative.worldRect,
store.viewRect
);
}
分块渲染:
- 大场景自动分块处理
- 支持虚拟滚动机制
- 动态加载可见内容
3. 内存管理策略
// 资源清理机制
destroy(onlyData?: boolean) {
// 清理画布资源
this.canvas.destroy();
// 断开网络连接
this.closeWebsocket();
this.closeMqtt();
// 清理事件监听
this.store.emitter.all.clear();
// 清理定时器
clearInterval(this.animateTimer);
}
📡 数据通信架构
实时数据通信支持
// 多协议支持
class Meta2d {
// WebSocket 连接
async connectWebsocket(url?: string) {
this.websocket = new WebSocket(url);
this.websocket.onmessage = this.socketCallback;
}
// MQTT 连接
async connectMqtt(params: MqttParams) {
this.mqttClient = mqtt.connect(params.mqtt, params.options);
this.mqttClient.on('message', this.socketCallback);
}
// HTTP 轮询
async connectHttp() {
setInterval(() => {
this.requestHttp(this.store.data.https);
}, this.store.data.interval);
}
// Server-Sent Events
connectSSE(net: Network) {
const eventSource = new EventSource(net.url);
eventSource.onmessage = this.socketCallback;
}
}
数据绑定机制
// 数据更新API
interface IValue {
id?: string; // 图形ID
dataId?: string; // 数据ID
value: any; // 新值
[key: string]: any; // 其他属性
}
// 单个数据更新
setValue(data: IValue, options?: {
render?: boolean; // 是否重渲染
doEvent?: boolean; // 是否触发事件
history?: boolean; // 是否记录历史
}) {
// 数据验证和转换
const pen = this.findPen(data.id);
// 更新图形属性
Object.assign(pen, data);
// 触发重渲染
if (options.render) {
this.render();
}
// 触发数据事件
if (options.doEvent) {
pen.onValue?.(pen);
}
}
// 批量数据更新
setDatas(datas: IValue[], options?) {
// 批量处理,最后统一渲染
datas.forEach(data => {
this.setValue(data, { ...options, render: false });
});
if (options.render !== false) {
this.render();
}
}
🎪 动画系统架构
动画类型支持
enum LineAnimateType {
Normal, // 水流效果
Beads, // 水珠流动
Dot, // 圆点动画
Arrow, // 箭头动画
WaterDrop, // 水滴效果
Custom // 自定义动画
}
// 动画配置
interface AnimationConfig {
duration?: number; // 动画时长
linear?: boolean; // 是否匀速
animateCycle?: number; // 循环次数
animateReverse?: boolean; // 是否反向
animateTimingFunction?: string; // 时间函数
keepAnimateState?: boolean; // 保持结束状态
}
动画调度系统
// 高性能动画循环
private animate = () => {
const now = performance.now();
// 遍历所有动画对象
this.store.animates.forEach(pen => {
if (pen.calculative.pause) return;
// 计算动画进度
const progress = this.calcAnimateProgress(pen, now);
// 应用动画效果
this.applyAnimateFrame(pen, progress);
});
// 请求下一帧
requestAnimationFrame(this.animate);
};
// 动画时间函数支持
calcAnimateProgress(pen: Pen, now: number): number {
const { start, duration, animateTimingFunction } = pen.calculative;
let progress = (now - start) / duration;
// 应用缓动函数
if (animateTimingFunction) {
progress = this.applyEasing(progress, animateTimingFunction);
}
return Math.min(progress, 1);
}
🔧 扩展机制设计
1. 图形库注册系统
// 注册自定义图形
register(penMap: Record<string, Function>) {
Object.entries(penMap).forEach(([name, drawFn]) => {
globalStore.penDraw[name] = drawFn;
});
}
// 使用示例
meta2d.register({
myCustomShape: (pen: Pen, ctx: CanvasRenderingContext2D) => {
// 自定义绘制逻辑
ctx.beginPath();
ctx.arc(pen.x, pen.y, pen.width/2, 0, Math.PI * 2);
ctx.fill();
}
});
2. 插件系统架构
interface PenPlugin {
name: string;
install: (pen: Pen | string, options: any) => void;
uninstall: (pen: Pen | string, options: any) => void;
[key: string]: any;
}
// 插件管理
installPenPlugins(pen: PenSelector, plugins: PluginOptions[]) {
plugins.forEach(({ plugin, options, enable = true }) => {
if (enable) {
plugin.install(pen, options);
this.trackPlugin(pen, plugin, options);
}
});
}
3. 事件扩展机制
// 丰富的事件回调支持
interface PenEvents {
// 生命周期事件
onAdd?: (pen: Pen) => void;
onDestroy?: (pen: Pen) => void;
onValue?: (pen: Pen) => void;
// 交互事件
onClick?: (pen: Pen, e: Point) => void;
onMouseEnter?: (pen: Pen, e: Point) => void;
onMouseLeave?: (pen: Pen, e: Point) => void;
// 编辑事件
onMove?: (pen: Pen) => void;
onResize?: (pen: Pen) => void;
onRotate?: (pen: Pen) => void;
// 数据事件
onBeforeValue?: (pen: Pen, value: any) => any;
onBinds?: (pen: Pen, values: IValue[], formItem: FormItem) => IValue;
// 媒体事件
onStartVideo?: (pen: Pen) => void;
onPauseVideo?: (pen: Pen) => void;
}
💡 核心设计模式应用
1. 观察者模式 (事件系统)
// 基于 mitt 库的事件总线
import mitt from 'mitt';
class Meta2dStore {
emitter = mitt();
// 触发事件
emit(type: string, data: any) {
this.emitter.emit(type, data);
}
// 监听事件
on(type: string, handler: Function) {
this.emitter.on(type, handler);
}
}
// 使用示例
store.on('valueChanged', (data) => {
// 响应数据变化
this.updateRelatedPens(data);
});
2. 策略模式 (渲染策略)
// 不同图形类型使用不同渲染策略
const penDrawMap: Record<string, DrawFunction> = {
rectangle: drawRect,
circle: drawCircle,
line: drawLine,
curve: drawCurve,
// ... 更多图形类型
};
function renderPen(pen: Pen, ctx: CanvasRenderingContext2D) {
const drawFn = penDrawMap[pen.name];
if (drawFn) {
drawFn(pen, ctx);
}
}
3. 命令模式 (历史记录)
interface EditAction {
type: EditType;
pens?: Pen[];
oldPens?: Pen[];
// ... 其他操作数据
}
class HistoryManager {
private history: EditAction[] = [];
private index = -1;
// 执行命令并记录
execute(action: EditAction) {
this.doAction(action);
this.history.splice(++this.index, 0, action);
}
// 撤销
undo() {
if (this.index >= 0) {
const action = this.history[this.index--];
this.undoAction(action);
}
}
// 重做
redo() {
if (this.index < this.history.length - 1) {
const action = this.history[++this.index];
this.doAction(action);
}
}
}
4. 工厂模式 (对象创建)
// 图形对象工厂
class PenFactory {
static create(type: string, options: Partial<Pen>): Pen {
const basePen: Pen = {
id: generateId(),
type: PenType.Node,
x: 0, y: 0, width: 100, height: 100,
...options
};
// 根据类型设置默认属性
switch (type) {
case 'rectangle':
return { ...basePen, name: 'rectangle' };
case 'circle':
return { ...basePen, name: 'circle', borderRadius: 50 };
case 'line':
return { ...basePen, type: PenType.Line, name: 'line' };
default:
return basePen;
}
}
}
🎯 开发实践指南
1. 添加新图形类型
// 1. 定义绘制函数
function drawCustomShape(pen: Pen, ctx: CanvasRenderingContext2D) {
// 实现自定义绘制逻辑
ctx.save();
// 设置样式
ctx.fillStyle = pen.background || '#000';
ctx.strokeStyle = pen.color || '#000';
ctx.lineWidth = pen.lineWidth || 1;
// 绘制图形
ctx.beginPath();
// ... 具体绘制代码
ctx.fill();
ctx.stroke();
ctx.restore();
}
// 2. 注册图形
meta2d.register({
customShape: drawCustomShape
});
// 3. 使用图形
meta2d.addPen({
name: 'customShape',
x: 100, y: 100,
width: 200, height: 100
});
2. 扩展图形属性
// 1. 扩展 Pen 接口 (通过模块扩展)
declare module '@meta2d/core' {
interface Pen {
customProperty?: string;
customConfig?: {
option1: number;
option2: boolean;
};
}
}
// 2. 在绘制函数中使用
function drawEnhancedShape(pen: Pen, ctx: CanvasRenderingContext2D) {
// 使用自定义属性
if (pen.customProperty) {
// 根据自定义属性调整绘制
}
}
3. 实现自定义动画
// 1. 定义动画帧
const animationFrames: Pen[] = [
{ x: 0, y: 0, scale: 1 },
{ x: 100, y: 50, scale: 1.2 },
{ x: 200, y: 0, scale: 1 }
];
// 2. 应用动画
meta2d.addPen({
name: 'rectangle',
frames: animationFrames,
duration: 2000,
animateCycle: 0, // 无限循环
autoPlay: true
});
4. 添加数据通信
// 1. 配置数据源
meta2d.addPen({
name: 'gauge',
id: 'pressure-gauge',
// 绑定实时数据
realTimes: [{
key: 'value',
dataId: 'pressure.current'
}]
});
// 2. 建立连接
meta2d.connectWebsocket('ws://localhost:8080');
// 3. 处理数据更新
meta2d.on('valueChanged', (data) => {
console.log('数据更新:', data);
});
🔍 性能监控和调试
1. 性能指标
// 性能统计
statistics() {
return {
totalPens: this.store.data.pens.length,
activePens: this.store.active.length,
animatingPens: this.store.animates.length,
renderTime: this.store.renderTime,
fps: this.store.fps
};
}
2. 调试工具
// 开发模式调试
if (process.env.NODE_ENV === 'development') {
// 显示性能信息
meta2d.showStats = true;
// 显示锚点
meta2d.showAnchor = true;
// 显示边界框
meta2d.showBounds = true;
}
📚 常见问题解决
1. 性能优化建议
- 大数据量场景: 使用
visible属性控制显示,启用视口裁剪 - 复杂动画: 使用离屏渲染,减少主画布重绘
- 频繁数据更新: 使用批量更新API,避免频繁单个更新
2. 内存管理
- 及时清理: 不用的图形调用
delete()方法清理 - 资源复用: 相同图片使用相同URL,利用浏览器缓存
- 事件清理: 组件销毁时记得清理事件监听
3. 扩展开发
- 图形库: 建议创建独立的包进行管理
- 插件系统: 利用现有插件机制,避免修改核心代码
- 主题系统: 通过
setTheme实现样式统一管理
🎖️ 总结
Meta2d.js 是一个设计精良的现代化 2D 图形引擎,具有以下特点:
技术优势:
- 🚀 高性能: 多层渲染 + 脏标记 + 视口裁剪
- 🔌 高扩展: 插件系统 + 事件机制 + 图形注册
- 📡 实时数据: 多协议支持 + 响应式更新
- 🎨 丰富功能: 动画系统 + 主题系统 + 布局算法
架构优势:
- 📦 模块化: 多包架构,职责清晰
- 🏗️ 可维护: 设计模式应用,代码结构良好
- 🔧 易用性: 丰富的API,完善的类型定义
- 🌐 生态: 开源,支持多种图表库集成
仅供参考