DiagramJS设计原理解读(二)
DiagramJS(一)
Diagram.js 是一个基于依赖注入
的图表/图形库核心组件,它使用 didi 库
来实现模块化和依赖管理
核心模块包括:Canvas(创建和管理SVG画布)、ElementFactory(创建元素)、ElementRegistry(注册和管理元素)、GraphicsFactory(创建SVG结构)、EventBus
渲染流程
1. 初始化流程:
- Diagram创建时,初始化核心模块(Canvas、EventBus、ElementRegistry、GraphicsFactory等)
- Canvas创建SVG容器和视口
- 触发
diagram.init
事件,通知所有模块初始化完成
2. 元素创建流程:
- 通过ElementFactory
创建元素
模型(shape或connection) - 调用Canvas的
addShape或addConnection方法
- ElementRegistry注册元素与其图形表示的
映射
关系 - GraphicsFactory创建元素的
SVG容器结构
(djs-group
> djs-element
> djs-visual
)
3. 元素渲染流程:
- GraphicsFactory调用
drawShape或drawConnection
方法 - 通过
EventBus触发
render.shape或render.connection事件 DefaultRenderer(或自定义渲染器)
响应事件,执行具体的绘制逻辑- 创建的SVG元素被添加到djs-
visual容器
中
4. 元素更新流程:
- 当元素属性变更时,调用GraphicsFactory.
update
方法 - 清除现有的视觉元素
- 重新调用
绘制方法
- 更新元素位置(对于shape类型)
5. 交互事件处理:
- InteractionEvents模块
监听DOM事件
- 将DOM事件
转换为diagram-js事件
(如element.click) - 通过EventBus
分发事件
- 相关模块响应事件,执行相应操作
GraphicsFactory
创建
SVG容器结构
,负责图形元素的创建(create)和更新(update)
,管理元素的层次结构
,触发渲染事件(render.shape、render.connection)
绘制逻辑drawShape
和drawConnection
,触发事件总线,Renderer负责具体绘制逻辑
核心功能说明
图形工厂初始化
- 依赖EventBus进行
事件通信
- 依赖ElementRegistry管理
元素注册信息
容器创建
流程
- 创建最外层group容器(djs-group)
- 创建元素容器(djs-element)
- 创建视觉容器(djs-visual)
- 根据类型添加特定样式(djs-shape/djs-connection)
元素管理
机制
- 维护
父子层级关系
- 处理元素
定位和更新
- 支持元素的
添加、更新和删除
渲染机制
- 通过
EventBus触发渲染
事件 - 支持
形状和连接线
的差异化渲染 - 提供路径计算和图形绘制接口
Render
实现
具体的绘制逻辑
,处理形状
和连接线
的绘制
- canRender :DefaultRenderer总是返回true,确保它能处理任何元素
- drawShape :创建矩形SVG元素,应用样式,并添加到视觉容器
- drawConnection :创建连接线SVG元素,应用样式,并添加到视觉容器
- getShapePath :计算形状的SVG路径字符串
- getConnectionPath :计算连接线的SVG路径字符串
渲染器继承结构
DefaultRenderer继承自BaseRenderer,采用了优先级机制
确保默认渲染器只在没有其他渲染器能处理元素时才会被调用
。DefaultRenderer的优先级被设置为最低(1),而BaseRenderer的默认优先级为1000。
渲染器初始化
DefaultRenderer在初始化时:
- 调用父类BaseRenderer的构造函数,传入eventBus和优先级
- 定义三种样式:
CONNECTION_STYLE
:连接线样式(洋红色,宽度5px)SHAPE_STYLE
:形状样式(白色填充,洋红色边框)FRAME_STYLE
:框架样式(无填充,虚线边框)
渲染流程
整个渲染流程由以下组件协同完成:
- Canvas :提供绘图容器和视口管理
- EventBus :处理渲染事件的分发
- ElementRegistry :管理元素和图形的映射关系
- GraphicsFactory :创建SVG图形元素
- Renderer :实际执行绘制操作
形状绘制流程
- GraphicsFactory接收到绘制请求
- 通过EventBus触发
'render.shape'
事件 - BaseRenderer监听该事件并
根据优先级调用合适的渲染器
- DefaultRenderer的
drawShape方法创建矩形SVG元素
根据元素类型应用不同样式
- 将创建的SVG元素添加到
视觉容器(GraphicFactory管理)
中
连接线绘制流程
- GraphicsFactory接收到绘制请求
- 通过EventBus触发
'render.connection'
事件 - BaseRenderer监听该事件并根据优先级调用合适的渲染器
- DefaultRenderer的drawConnection方法
创建多段线SVG元素
- 使用
RenderUtil.createLine
方法根据路径点创建线条
- 应用
CONNECTION_STYLE样式
- 将创建的SVG元素添加到视觉容器中
路径计算
DefaultRenderer还提供了两个重要方法来计算SVG路径
:
getShapePath
:计算形状的SVG路径,创建一个矩形路径
getConnectionPath
:计算连接线的SVG路径,根据路径点创建一个连续线段
Canvas & SVG &Renderer
Canvas
- 定义:Canvas 是 HTML5 提供的用于绘制图形的元素,通过 JavaScript 可以动态地绘制图形。
- 常见问题:如何在 Canvas 上绘制基本图形(如矩形、圆形)、如何处理图像、如何实现动画效果。
- 回答示例:Canvas 提供了一个 2D 绘图上下文,可以使用
getContext('2d')
方法获取,通过调用绘图上下文的方法来绘制图形。
SVG
- 定义:SVG 是一种基于 XML 的矢量图形格式,适用于在网页中展示高质量的图形。
- 常见问题:SVG 与 Canvas 的区别、如何在 SVG 中创建和操作图形元素、如何使用 CSS 和 JavaScript 操作 SVG。
- 回答示例:SVG 是基于矢量的,适合绘制需要缩放的图形,而 Canvas 是基于像素的,适合绘制需要频繁更新的图形。
Renderer
- 定义:在图形库中,Renderer 通常指负责将数据渲染为可视图形的组件。
- 常见问题:如何实现自定义渲染器、渲染器的生命周期、如何优化渲染性能。
- 回答示例:渲染器通常通过监听事件来决定何时更新图形,通过优化绘制路径和减少重绘次数来提高性能。
自定义Renderer
要自定义一个renderer
,首先需要理解diagram.js中的渲染机制
。diagram.js采用模块化设计
,通过事件总线(EventBus)
协调各个模块的交互。自定义renderer需要继承BaseRenderer
,并实现canRender、drawShape、drawConnection等方法
。可以通过事件监听机制
,在特定的渲染事件中调用自定义的绘制逻辑
。通过这种方式,可以灵活地扩展和定制图形的渲染行为,满足特定的业务需求。
diagram.js 设计思路
- 模块化设计:diagram.js 采用模块化设计,通过
依赖注入
系统管理各个组件,确保松耦合和高可扩展性
。 - 事件驱动:使用
EventBus 处理渲染事件
,协调Canvas、GraphicsFactory 和 Renderer
的交互。 - 渲染流程:
Canvas 管理 SVG 画布,GraphicsFactory 创建和更新图形元素,DefaultRenderer 实现具体的绘制逻辑
。