0%

ECharts图元拾取方案

背景

降低图表开发成本的几大节点

1. D3.js的诞生

D3的核心概念:Data-Driven Documents,以数据去驱动视图的渲染,使开发者摆脱了繁琐的视图渲染细节。不再需要手动增删改具体的svg节点,以及其内置的优秀布局算法。极大的降低了图表开发的门槛(体现在布局算法层面),以及提高图表的开发效率(不再需要去维护具体视图)。

2. ECharts

ECharts通过配置式的方式去创建图表并搭配完善的文档,先天性的就会比D3编码式的图表绘制方式门槛要低、效率要高。并且ECharts将图表的开发逻辑做了一个倒置,从由图元组合形成图表(绘制点线面、图例、提示框来组合成一个完善的图表),改为了从图表的可配置项中选择一些合适的搭配(选择显示X轴、Y轴图例等)。进一步降低了图表开发的心智负担同时规范了图表样式。

3. 各类图表编辑器的出现

DataVeasyvchartcube等图表编辑器的出现,将图表的配置项进一步抽象成了一些可见、可读的、GUI化的配置表单。用户通过拖拉拽以及点点点的方式来生成图表。这里将文档阅读、以及编码测试两个流程优化了出去。进一步降低了图表开发的门槛与成本。

4. AI生成

近年来随着AIGC的大规模应用,以Chat-GPT为代表的AI通过其巨大的语料库以及优秀的语言模型,基本已经做到了的通过自然语言来生成绘制图表的代码,将图表的生产方式从UI交互提升到了自然语言描述。但由于AI的不稳定性,由AI生成的图表普遍不能直接应用于生产,仍然需要一定量的微调,这就又对开发者的编程技巧有了一定的要求。

各类图表编辑器的一些困境

灵活性

这里以ChartCube中的饼图举例,虽然图例提供了众多的位置(方位分为上下左右、水平位置分为左中右)。但仍然无法将图例配置在环状图的中心位置。针对于其他的配置点例如:环形图扇区的装饰、整体的自定义背景等没有表单即无法配置。在灵活性上相较于编码式的生成图表始终会有所差距。

image-20230423190226024

学习成本

这里以几个图表类编辑器的配置表单举例,众多的表单配置虽然不至于晦涩难懂,但也让人感觉无从下手,在传统的面向图元的设计思维下,要改某个图元的某个样式,需要解决几个问题:1. 这个图元对应的配置项表单在哪?2.这个图元对应的配置项表单里有没有我需要的那个配置项?本质上均为面对众多的配置项如何快速索引的问题。

image-20230423191657942

这里我们设计的图表编辑器采用了图元拾取的方案,点击图元会将表单做筛选,仅显示拾取的图元所对应的配置项,以解决配置项表单快速索引的问题,进一步降低学习成本。

关于图元拾取的详细背景这里有个调研:ECharts源码解析之图元拾取可供参阅。

本文仅介绍在图表编辑器内部实现图元拾取的具体方案。同时也欢迎体验我们开发的图表编辑器Charts-Studio

图元拾取面临的问题

本节及下文中的图表引擎均为ECharts。

拾取困难

ECharts作为一个配置的图表引擎,同时默认的渲染器又是Canvas。在Canvas上做元素识别涉及到图形的识别具有先天困难度。

图元信息不足

即便采用svg渲染器来规避图形识别的问题。仍然会有图元信息不足的问题,比如在折线图中,X轴的轴线、轴分割线、刻度线、以及映射数据的折现对应的svg标签均为path缺少有效的手段去区分一个path对应的图元究竟是什么。

图元拾取的解决方案

图元信息标注

这里直接引用ECharts源码解析之图元拾取的结论。

由于图元信息不足,要实现图元拾取对图元原始信息的注入不可避免,改动规模较大,对ECharts代码进行二次侵入的方式不可行。需ECharts新增属性的字段来描述图元的原始信息。

我们对ECharts的图形引擎ZrenderElement对象做了扩充,新增了EditorInfo属性以描述该图元对应的原始信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export interface EditorInfo {
// 组件名称
component: string,
// 元素名称
element: string,
// 组件下标
componentIndex?: number,
// 数据下标
dataIndex?: number
// 子类型
subType?: string
}

declare module 'zrender/src/Element' {
export default class Element {
__editorInfo?: EditorInfo;
}
}

以饼图为例,我们对【待绘制的扇区】标注了图元信息,并且新增了环境变量,只有在__EDITOR__的情景下才会对图元的原始信息作注入。

1
2
3
4
5
6
7
8
9
if (__EDITOR__) {
addEditorInfo(piePiece, {
component: 'series',
subType: 'pie',
element: 'piece',
componentIndex: componentIndex,
dataIndex: idx
});
}

在对绝大多数图元做了标注之后我们提交了PR这里可以见feat(devInfo): set devInfo into component by sz-p · Pull Request #17698 · apache/echarts (github.com)

图元信息获取

这里借助Zrender,在__EDITOR__模式下将图元信息直接写入了标签的elTarget属性。点击到具体的图元之后通过解析elTarget属性以获取图元的原始信息。

1
<path d="M50 96.6667L112 68.3333L174 195.8333L236 110.8333L298 181.6667L360 125" fill="none" stroke="rgb(24,144,255)" stroke-width="2" stroke-linejoin="bevel" elTarget="{&quot;component&quot;:&quot;series&quot;,&quot;subType&quot;:&quot;line&quot;,&quot;element&quot;:&quot;polyline&quot;,&quot;componentIndex&quot;:0}" origin-transition="opacity 0.3s ease-out 0s" style="transition: opacity 0.3s ease-out 0s;" origin-opacity="null" opacity="null"></path>

表单筛选

这里仅涉及编辑器内部私有状态的调整不再说明。

效果

Apr-23-2023 20-15-21

参考 & 引用

ECharts源码解析之图元拾取 | SZ 博客 (sz-p.cn)

ChartCube - 在线图表制作工具 (alipay.com)

http://datav.aliyun.com/

新建标签页 (easyv.cloud)