搜索文章

输入关键词开始搜索

可视化业务开发框架解析

思考#TODO#程序设计#3D#数据可视化#Agent#AI#数据库#架构

可视化业务框架从领域、数据、组件、场景到交付

为什么做这个框架

  • 降低可视化开发的门槛,解决新人上手成本太高的问题
  • 提升开发效率
  • 提升质量下限

可视化需求和常规前端需求的区别是什么?

可视化组件,会涉及事件、布局、交互、状态等众多内容,不像UI组件,更像一个整合多个UI组件的业务功能模块。 可视化组件中的View,才更像是常规的UI组件库。

代码

business-visualization-template

设计理念

人类设计,代理编码(Human design, Agents code!)

7层人机交互AI Workflow + 软件工程 聚焦问题领域解决方案领域 这个流程和每个环节要做的事情,必须深入思维的习惯里面去,成为原则性的内容。

自顶向下,逐步求精,逐渐固化

越到后面的环节越具体,直至产生原子函数、方法等; 抽象程度也是从大到小变化的。

  • 确定哪些是固定不变的、哪些是会随着需求变动的
  • 不变的部分就形成固化的流程、文档和代码(微内核架构的微内核部分,这部分是我们需要专注做的基建部分,就是基础框架和核心机制)
  • 让AI和人聚焦于变化的部分,缩小上下文和心智负担(即需要通过具体的插件实现的业务功能部分,比如柱状图)

AI + Template(填空题模式)

尽量让AI去填空

流程

  • 需求分析
  • 项目分析
  • 方案设计
  • 模块设计
  • 代码实现
  • 性能优化
  • 可靠性保障

Q&A

这个程序设计怎么来的?

结合业务实践经验 + 参考其他开源可视化项目的设计。

数据相关的处理代码怎么拆分

Data:原始数据的管理,数据预处理、视图元素和原始数据做一个链接(比如getGraphicElement这个方法),这个在3D里面经常用到 Model:数据驱动的核心 Controller里面也有一部分内容

Data的定位

业务无关的数据处理?? 需要挂载在Model上 中间层代理???

为什么视图元素和原始数据要做一个链接?

项目中一般存在四类数据: option:配置项 original data:业务的原始数据 layout data:布局相关的数据 view data:渲染相关的数据

一般是把2、3、4提出来做个链接,其目的是为了解决查询管理问题,提高可维护性,可以理解为是一个微型数据库,算是个cache。

因为我们经常会遇到这个场景: 改了原始数据,需要找到对应的图形元素,更新视觉效果。这就设计model-view的查询。 反过来也可以查询,即通过view获取model,不过这种场景只能通过get方法获取数据,且只能获取数据的副本,不能修改它,否则就违背了单向数据流的原则,容易产生意外的影响。

view data和layout data为什么不能放一起?

O-M-L-V 计算公式+原始数据,获得layout layout作用于model

layout放view的问题:视图层直接修改了model对象,强耦合了???不是这个原因吧??

Layout怎么处理

Layout算是视图数据下属的一个子分类 也是放Model下的Data里面管理

如何触发事件,进而更新数据?

遵循:注册-绑定-触发 的流程,通过Controller进行调度。

可以看下bar的hover事件的实现示例:

  • Controller中注册事件
// 悬停状态变更事件
this.on('barHover', (data: BarChartData | null, index: number | null) => {
  console.trace('controller触发了barHover');

  this.updateBarStyles();
});
  • View中在bindInteractionEvents()方法中给元素绑定事件
this.barGroup.on('mouseover', (e: ElementEvent) => {
  const targetRect = e.target as Rect;
  const index = this.bars.indexOf(targetRect);
  if (index !== -1) {
    this.handleInteraction('barHover', { index, event: e });
  }
});
  • 统一的机制代理触发Controller事件
/**
 * 处理交互事件 - 子类可选实现
 * @param eventType 事件类型
 * @param eventData 事件数据
 */
protected handleInteraction(eventType: string, eventData: any): void {
  this.emit('interaction', {
    type: eventType,
    data: eventData,
    target: eventData.target || null
  });

  // 触发具体的事件
  this.controller.emit(eventType, eventData);
}

Controller中处理了很多业务,是否合理?

不合理,目前的代码中,Controller既处理业务事件又处理UI事件。 需要重构下:

  1. 数据操作移至 model:将数据相关方法移到 BarChartModel
  2. 样式处理移至 view:将 updateBarStyles() 移到 BarChartView
  3. 简化 controller:只保留事件协调和渲染调度逻辑
  4. 添加服务层:复杂的样式计算可抽离为专门的 style service

Element和View的区别是什么?

Element负责图形元素的状态管理

当前的问题

循环依赖

BarChartView 在构造函数中持有了 Controller 的实例,而 Controller 也持有了 View 的实例,这形成了循环依赖 (Controller <-> View)。虽然在很多 MVC 实现中这很常见,但它会增加组件间的耦合度,使得代码更难理解和单独测试。 改进方案: 可以让 View 和 Model 一样,继承自 Eventful,成为一个独立的事件发布者。Controller 则在外部监听 View 的事件,而不是将自身实例注入到 View 中。这样可以形成更单向的数据流:View -> Controller -> Model。

TODOs

  • 结合系统架构师的内容,再细化下流程、每个环节的约束
  • 针对每个模块,增加特定的约束
  • 解决方案库的建设,比如基于/不基于坐标轴的、基于日历的等等,搞成几套固定的方案,然后让AI辅助我们思考和权衡
  • 优化Controller,明确其职责边界
  • test模块

如何快速学习掌握这个框架

  • 用Gemini提问的方式,学习这个框架
  • 用这个框架做一个新需求,或者将一个老的项目用这个框架重构