[Feature] 饼图在无数据时支持展示占位圆
hello,我正在尝试实现这个feature,但是似乎遇到了一点问题。
// VChart\packages\vchart\src\data\transforms\pie.ts
if (data.length === 0 && showEmptyCircle) {
data[0] = {};
appendArcInfo(data[0], startAngle, endAngle);
}
我使用的spec是VChart\packages\vchart\__tests__\runtime\browser\test-page\pie.ts,只对data项作了修改(将values设为空数组),不确定为什么默认情况下绘制的圆仅有3/4,想冒昧问一下。
@FunctionEurus
Hi, 同学的实现思路没有问题, 应该添加一个占位的数据, 用于绘制一个圆形的图元. transforms\pie的功能是对原始数据进行数据转换操作, 并不适合添加或删减数据.
可以参考packages/vchart/src/series/pie/pie.ts中的逻辑, 为pie添加一个占位圆.
VChart的图表, 都是基于series设计的, 在pie.series中, 有initData、initMark、initMarkStyle三个方法.
- 在初始化数据时, 可以添加一个空白的占位数据
- 在初始化图元时, 可以添加一个emptyMark, 即一个饼图同时有pieMark和emptyMark.
- 在初始化图元样式时, 当数据项为0, 可以为emptyMark设置样式.
我在这完成了一部分代码 临时MR , 同学可以参考并实现这个feature.
非常感谢您的回复!我尝试在上述pr的基础上实现emptyCircleStyle接口时仍然遇到了一些问题,并且囿于我本身的能力以及对VChart源码的理解有限,尝试完成该feature还是有些操之过急,但我依然希望提出我的思路并得到斧正。
我的接口设计如下:
pieChart.pie.showEmptyCirclepieChart.pie.emptyCircleStyle
在绘制过程中,我发现只有this._pieMark可以获取完整的style spec,initMarkStyleWithSpec在处理this._emptyArcMark时所接收到的spec是空对象(undefined则是initMarkStyleWithSpec的第三个参数key)。
我期望当数据为空且showEmptyCircle为true时,能够通过initMarkStyleWithSpec方法为emptyMark设置自定义样式。但由于spec接收到的是空对象,导致样式没有正确应用。虽然以下实现可以绕开这个问题实现自定义占位圆样式,但我认为这不应该是正确的方法。
initMarkStyleWithSpec(mark?: IMark, spec?: any, key?: string): void {
super.initMarkStyleWithSpec(mark, spec, key);
if (mark.name === this._pieMarkName) {
// radius 配置需要额外处理比例值
const pieSpec = this.getSpec()[mark.name];
if (pieSpec) {
for (const state in pieSpec.state || {}) {
this.setMarkStyle(mark, this.generateRadiusStyle(pieSpec.state[state]), state, AttributeLevel.User_Mark);
}
}
}
// 我的实现
if (this.getRawData().latestData.length === 0 && mark.name === 'emptyMark' && this._showEmptyCircle) {
super.initMarkStyleWithSpec(mark, { style: this._spec.pie.emptyCircleStyle }, key);
}
}
如果可以,我希望能够获得以下方面的帮助:
- 确认
initMarkStyleWithSpec方法中的spec接收空对象的原因。 - 确定如何正确传递
emptyCircleStyle配置到emptyMark。 - 任何关于理解VChart源码结构和流程的建议。
如有需要,完整的修改请见此处,再次感谢您的时间。
一、首先, 需要了解VChart的图表组成: chart、component、region、series. https://visactor.io/vchart/guide/tutorial_docs/Chart_Concepts/Understanding_VChart VChart的设计约束: 1个chart对应多个series
二、spec init的逻辑
Step1: 调用renderSync, 在beforeRender中, 有一个spec的转换逻辑, 代码位置在这: packages/vchart/src/core/vchart.ts:657
需要重点阅读 this._chartSpecTransformer.transformSpec, 由Factory.createChartSpecTransformer创建.
Step2: 在pie chart的实现中, 调用了registerPieChart向Factory注册了饼图, 包含了transformer的实现, 代码位置在:packages/vchart/src/chart/pie/pie.ts
Step3: 执行transformSpec: 将一个图表spec 拆成 多个series的spec
packages/vchart/src/chart/polar/polar-transformer.ts
Step4: pie series中, 使用series spec.
三: 接口设计与补齐类型 接口的确定要谨慎, 因为要避免breakChange, 所以只能增加, 不能修改或删除, 需要对功能进行抽象, 考虑是否可以成为一个所有图表都需要的足够通用功能.
饼图这次如果实现了 showEmptyCircle、emptyCircleStyle, 在未来可能会出现这些情况: 饼图不想要占位圆, 想要占位的文本 或 icon. 除了饼图之外, 其他图表, 也想在没有数据的场景, 拥有类似能力
因此可以针对这个场景, 把功能做的更加的“抽象”和“通用”, 因此该feature的实现, 需要考虑到未来的快速扩展.
建议把showEmptyCircle、emptyCircleStyle的命名更改为 “placeholder” 或者 “emptyPlaceholder”, 结构可以由你自行设计.
@FunctionEurus 确认initMarkStyleWithSpec方法中的spec接收空对象的原因。 答: 这个方法不应使用, 接收到的空对象, 纯粹是因为漏了初始化.
确定如何正确传递emptyCircleStyle配置到emptyMark。 答: initSpec的过程中, 执行transformSpec即可. 将chart spec转换为series spec.
任何关于理解VChart源码结构和流程的建议。 答: 简单写了一下 初始化spec的流程, 你可以参考一下.
released in 1.12.0