Meta2d.js 源码解读分析

Meta2d.js 源码解读分析

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;              // 缩略图管理
  // ... 更多属性
}

核心功能模块:

  1. 数据管理层

    • store: 使用全局状态管理,支持响应式数据绑定
    • 历史记录管理: 支持 undo/redo 操作
    • 数据序列化: 支持完整的数据导入导出
  2. 渲染引擎层

    • canvas: 多层画布架构,支持复杂场景渲染
    • 高性能绘制: 脏标记机制 + 视口裁剪优化
    • 动画系统: 支持多种动画类型和时间函数
  3. 网络通信层

    • WebSocket: 实时双向数据通信
    • MQTT: 物联网设备数据接入
    • HTTP: 传统数据接口调用
    • SSE: 服务器推送事件
  4. 事件系统

    • 完整的生命周期事件 (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();
}

性能优化策略:

  1. 脏标记机制 (patchFlags)

    • 只重绘需要更新的部分
    • 支持细粒度的更新控制
  2. 视口裁剪 (calcInView)

    • 只渲染可见区域内的图形
    • 大幅提升大数据量场景性能
  3. 离屏渲染

    • 复杂图形预渲染到离屏画布
    • 缓存静态内容,减少重复计算
  4. 批量操作

    • 多个修改操作合并为一次渲染
    • 减少渲染调用次数

🚀 高性能架构设计

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,完善的类型定义
  • 🌐 生态: 开源,支持多种图表库集成

仅供参考


本人自动发布于:https://github.com/giscafer/blog/issues/75

相关文章