架构总览
架构总览
本节深入介绍 vjmapext 的系统分层、组件关系、数据流与渲染机制,帮助你理解底层运作原理,为进阶开发打下基础。
系统分层
vjmapext 采用经典的分层架构,从上到下分为应用层、核心层和基础层:
设计原则
MapCadLayer 是整个系统的中枢入口,但它不实现具体业务逻辑,而是将职责委托给各个子系统。子系统之间通过 EventBus 解耦通信,通过 CoordMapper 统一坐标转换。
组件关系
以下类图展示了 MapCadLayer 与其 readonly 成员的关系:
数据流
从实体创建到最终在地图上渲染,数据经历以下完整流程:
三数据源分桶策略
渲染管线将实体对应的 GeoJSON Feature 分配到三个 map source 中,以优化渲染性能:
| 数据源 | Source ID | 用途 | 更新频率 |
|---|---|---|---|
| Hot | mapcad-hot | 选中 / 高亮的实体 + 夹点 + 预览 | 高频(交互时每帧更新) |
| Cold | mapcad-cold | 普通静态实体 | 低频(仅实体变更时更新) |
| Dynamic | mapcad-dynamic | dynamic: true 的实体(如动画对象) | 中频(动画帧更新) |
性能优化
这种分桶策略确保大量静态实体(Cold Source)不会因为少量交互操作(Hot Source)而被反复序列化。RenderCache 进一步缓存每个实体的 GeoJSON 输出,仅在实体属性变更时重新计算。对于仅样式变化的实体(如颜色修改),采用就地属性补丁而不是重建整个 Feature 数组。
命令执行流程
以下时序图展示了用户执行一条绘图命令的完整生命周期:
命令上下文 CommandContext
每条命令执行时会收到一个 CommandContext,其中包含 store、inputManager、eventBus、coordMapper、renderPipeline、previewManager、gripManager、drawingDefaults、undoManager、blocks、map、dimReactorManager 等引用,可以访问系统的全部能力。
事件系统
EventBus 是系统内部的发布/订阅中心,所有子系统通过它进行解耦通信。支持的核心事件:
| 事件类别 | 事件名 | 触发时机 |
|---|---|---|
| 实体事件 | entity:added | 实体添加到 EntityStore |
entity:deleted | 实体从 EntityStore 删除 | |
entity:modified | 实体属性发生变更 | |
entity:mouseenter | 鼠标移入实体 | |
entity:mouseleave | 鼠标移出实体 | |
entity:click | 点击实体 | |
entity:dblclick | 双击实体 | |
| 选择事件 | selection:changed | 选中实体集合变化 |
| 命令事件 | command:started | 命令开始执行 |
command:ended | 命令执行结束 | |
| 模式事件 | mode:changed | 编辑/浏览模式切换 |
| 渲染事件 | render:requested | 请求渲染更新 |
| 存储事件 | store:changed | EntityStore 数据变化 |
| 输入事件 | input:started | 开始用户输入 |
input:ended | 用户输入结束 | |
| 框选事件 | boxselect:started | 开始框选操作 |
boxselect:ended | 框选操作结束 |
// 监听实体添加事件
mapcadLayer.eventBus.on('entity:added', (e) => {
console.log('新增实体:', e.entity.id, e.entity.type);
});
// 监听选择变化
mapcadLayer.eventBus.on('selection:changed', (e) => {
console.log('当前选中:', e.selectedIds);
});
// 监听模式切换
mapcadLayer.eventBus.on('mode:changed', (e) => {
console.log('模式切换为:', e.mode);
});渲染管线详解
RenderPipeline 采用 增量更新 + 全量重建 双模式,在性能与正确性之间取得平衡:
全量重建
在以下场景中触发:
- 首次渲染 /
forceFullRender()调用 - 坐标映射器重新绑定(地图投影变化)
- 浏览模式下的显示层级过滤变化
全量重建时,RenderPipeline 遍历 EntityStore 中所有可见实体,调用 RenderCache.getOrCompute() 获取缓存的 GeoJSON Feature,然后按实体状态(选中、动态、普通)分配到对应数据源。
增量更新
常规编辑操作(添加、删除、修改实体)触发增量更新,仅处理变化的实体:
- 样式补丁:颜色、透明度等样式属性变化时,直接修改已有 Feature 的 properties,不重建数组
- Feature 替换:几何形状变化时,从对应桶中移除旧 Feature,生成新 Feature 并追加
- 索引维护:
_entityIndex记录每个实体在哪个桶的哪个位置,支持高效定位
注意
RenderPipeline.render() 由 EntityStore 的脏标记自动触发,通常不需要手动调用。如需强制刷新(如外部修改了实体几何数据),请调用 renderPipeline.forceFullRender()。
坐标系统
CoordMapper 负责 CAD 坐标与地图经纬度之间的双向转换:
CoordMapper 在 onAdd() 时通过 bindMap() 绑定到 vjmap.Map,自动获取当前的 GeoProjection 投影参数。所有实体的坐标都使用 CAD 坐标系,渲染时由 CoordMapper 自动转换为经纬度坐标写入 GeoJSON。
下一步
- 坐标与投影 — 深入理解坐标映射原理
- MapCadLayer API — 完整的 API 参考
- 实体基础 — 学习创建和管理各种实体类型
- 命令与交互 — 掌握命令系统与用户输入