关于可视化组件技术选型的思考

名词定义

基础组件

StandardChart所包含的标准范式组件,业务场景中真正使用的一般就是折柱饼等有限的几类图表。

业务组件

和特定业务绑定,具有特殊的交互和UI需求。
比如:海外矩形树图、F10股权图、行情图等。

注:有的业务组件可以通过SD配置得来,比如火焰图

StandardChart的弊端

个性化需求难以修改:
因为底层是基于ECharts的,所以添加和修改任何需求,都必须遵循其设计,且因为ECharts的复杂度高,需要开发者了解大量的前置知识。
关联性影响问题:
同样是由于ECharts的复杂度高、组件之间关联性强,因此容易产生修改A组件导致B组件出问题的情况。之前也出现过多次改完上线后,发现影响了其他功能的问题。
难以AIGC:
目前基于SD的HiPilot生成可视化代码,需要LLM了解的上下文太多了,导致难以通过LLM直接生成可用的代码。
粒度太大:
SD所有图表都在一个库中,整体比较臃肿,实际上业务方往往只需要一个折线图,但是不得不使用包含所有图表的CDN(类似早期ESB模式的SOA)。
而且这样也不利于KAmis的单个组件单个库的设计机制(Figma2Code要求一个组件一个仓库)。

方案选型标准

什么情况下基于SD开发,什么情况单独写?
方案选型的本质就是做权衡和取舍。当A方案的成本和收益低于B方案时,B就是更好的选择。
回顾我们之前的需求,可以总结出如下权衡点:

技术权衡点

  • 为了契合ECharts的程序流程,改动一个小需求需要大量的开发成本
  • 和ECharts的设计冲突,在当前架构下无法实现
  • 和ECharts的设计冲突,会带来大范围的影响和不可控性

业务权衡点

业务组件 ∩ StandardChart中没有的,就单独新写。

高定需求的基础框架

(TODO)技术选型

目前暂定D3 + ZRender

不过ZRender有个潜在的问题:LLM可能并不了解这个渲染库

关于UI框架,是不是选择React技术栈更好一些?

需要解决的问题

如何解决公共函数/包的修改导致其他组件受到关联影响的问题?

shadcn/ui的模式?
或者公共的函数和包,单独打包为npm,通过安装npm包的形式进行使用。

如何解决依赖的库的版本升级问题?

比如D3、ZRender升级,那么已有的所有组件是否都要升级?

需要包含的功能

机制类

机制类的内容,应该由脚手架/框架自动生成抽象接口,开发组件时再进行实现。

生命周期:
core统一进行定义。
主题机制
这个应该是每个库独立实现,不好做到代码实现层面的统一,只能做到接口和入参规范层面的统一(抽象接口)。
AIGC封装机制:
在HICharts这一层实现,可以AI自动生成封装代码、自动接入。
Timeline机制:
帧循环 + setOption重绘机制(抽象接口)。

代码组织形式

初期可以先不考虑,每个需求独立一个项目进行开发,待确定有内容是可抽取的,再抽象封装为通用的包。

参考下其他优秀的开源库的方案。
MonoRepo?
分包?
​pnpm Workspaces
Yarn + Lerna

Demo开发形式

StoryBook?

打包&发布方案

方案一:
每个项目新建一个PaaS流水线。

方案二:
只创建一个流水线,自动增量发布,参考KAmis组件的打包方案。

应用方案

CDN引入方案
SDK嵌入模式(需标准化)
MCP(开发人员和运营人员的场景)

当前代码库的规划和整理

(TODO)目标与收益分析

StandardChart

缺少抽象层:缺少清晰的抽象接口定义,导致扩展实现不统一
命名问题
theme目录的规划不合理,未体现业务特性。
耦合度高:使用依赖注入降低组件间耦合
缺乏单元测试
setTimeout的问题
TODO、FIXME
分支整理下。
通过Builder模式封装范式配置,简化业务方的自定义组件配置(VISALL其实也可以这样弄):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
bar(document.getElementById('chart'))

.withData(salesData)

.withTheme('dark')

.withTitle('销售业绩分析')

.addBarLayer({

x: 'month',

y: 'revenue',

color: 'department',

stack: true

})

.addLineLayer({

x: 'month',

y: 'target',

smooth: true

})

.configureXAxis({

title: '月份',

grid: false

})

.configureYAxis({

title: '销售额 (万元)',

format: ',.0f'

})

.render();

VISALL

分层逻辑不明确:
需要有一个明确的模块边界和接口定义
数据层(包括定义和预处理等,名字dataProcessor建议改一下)、领域逻辑层、视图层和控制层

职责划分不清:
API 模块中混合了多种职责,包括DOM操作、核心渲染逻辑和布局管理
MainStandardChartView.ts职责过多

耦合度太高:
引入依赖注入的思想,参考InversifyJS

数据预处理模块引入Zod提升程序质量和可维护性与可测试性,增加对属性值类型的验证。

缺少统一的错误处理工具和规范

缺少单元测试

需要提供更多的开发者工具和文档
HICharts