From ac1723523d52d62f7e95b5188809d4806770aabe Mon Sep 17 00:00:00 2001
From: Kasmine <736929286@qq.com>
Date: Mon, 28 Dec 2020 20:01:30 +0800
Subject: [PATCH] feat: changedata (#2142)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs(line-demo): 优化基础折线图 demo
* feat(core): plot core 提供 updateOptions 方法 & 提供 changedata 复写
* feat(line): 折线图支持动态更新数据
- overrider changedata
- provide demo
* feat(gauge): 仪表盘支持动态更新数据
- 抽取获取 view data 的工具方法
- override changeData
* feat(gauge): 优化仪表盘的 changedata, 每一次 changedata 只做一次 paint 绘制
- [x] 单测
* fix(gauge): 修改文档 & demo
* feat(🔨): 增加测试用例
* feat(gauge): 添加仪表盘 utils 测试用例
* fix: 修改 cr 建议
* docs: 更新网站 demo 截图
---
__tests__/unit/core/index-spec.ts | 38 +++++-
__tests__/unit/plots/gauge/index-spec.ts | 4 +
__tests__/unit/plots/gauge/statistic-spec.ts | 17 +++
__tests__/unit/plots/gauge/utils-spec.ts | 28 +++++
__tests__/unit/plots/line/change-data-spec.ts | 51 ++++++++
docs/api/plots/gauge.zh.md | 6 +-
examples/line/basic/demo/dynamic-line.ts | 29 +++++
.../line/basic/demo/line-with-data-marker.ts | 118 ++++++++++++++++++
examples/line/basic/demo/line.ts | 11 --
examples/line/basic/demo/meta.json | 30 ++++-
examples/line/basic/demo/spline.ts | 19 +++
examples/progress-plots/gauge/demo/basic.ts | 7 +-
examples/progress-plots/gauge/demo/complex.ts | 4 +-
src/core/plot.ts | 13 +-
src/plots/gauge/adaptor.ts | 30 +++--
src/plots/gauge/constant.ts | 4 +
src/plots/gauge/index.ts | 21 +++-
src/plots/gauge/utils.ts | 24 +++-
src/plots/line/index.ts | 9 ++
19 files changed, 421 insertions(+), 42 deletions(-)
create mode 100644 __tests__/unit/plots/gauge/utils-spec.ts
create mode 100644 __tests__/unit/plots/line/change-data-spec.ts
create mode 100644 examples/line/basic/demo/dynamic-line.ts
create mode 100644 examples/line/basic/demo/line-with-data-marker.ts
create mode 100644 examples/line/basic/demo/spline.ts
diff --git a/__tests__/unit/core/index-spec.ts b/__tests__/unit/core/index-spec.ts
index b91c720872..9db3b189fe 100644
--- a/__tests__/unit/core/index-spec.ts
+++ b/__tests__/unit/core/index-spec.ts
@@ -40,6 +40,40 @@ describe('core', () => {
line.destroy();
});
+ it('updateOption without render', () => {
+ const options = {
+ width: 400,
+ height: 300,
+ data: [
+ { date: '12-01', value: 1, type: 'bb' },
+ { date: '12-02', value: 12, type: 'bb' },
+ ],
+ xField: 'date',
+ yField: 'value',
+ seriesField: 'type',
+ };
+ const line = new Line(createDiv(), options);
+
+ line.render();
+
+ // @ts-ignore
+ line.updateOption({
+ data: [...line.options.data, { date: '12-01', value: 4, type: 'cc' }, { date: '12-02', value: 19, type: 'cc' }],
+ });
+
+ expect(line.chart.geometries[0].elements.length).toBe(1);
+
+ line.render();
+ expect(line.chart.geometries[0].elements.length).toBe(2);
+
+ line.update({
+ data: [...line.options.data, { date: '12-01', value: 4, type: 'dd' }, { date: '12-02', value: 19, type: 'dd' }],
+ });
+ expect(line.chart.geometries[0].elements.length).toBe(3);
+
+ line.destroy();
+ });
+
it('update mix with default options', () => {
const options = {
width: 400,
@@ -53,9 +87,7 @@ describe('core', () => {
line.render();
const curOptions = clone(line.options);
- line.update({ ...options, width: 500 });
-
- line.render();
+ line.update({ width: 500 });
expect(isEqual(line.options, deepMix(curOptions, { ...options, width: 500 }))).toBeTruthy();
diff --git a/__tests__/unit/plots/gauge/index-spec.ts b/__tests__/unit/plots/gauge/index-spec.ts
index 48cc6a990d..2cbc582757 100644
--- a/__tests__/unit/plots/gauge/index-spec.ts
+++ b/__tests__/unit/plots/gauge/index-spec.ts
@@ -1,4 +1,5 @@
import { Gauge } from '../../../../src';
+import { INDICATEOR_VIEW_ID, RANGE_VIEW_ID } from '../../../../src/plots/gauge/constant';
import { pick } from '../../../../src/utils';
import { createDiv } from '../../../utils/dom';
@@ -114,6 +115,8 @@ describe('gauge', () => {
});
gauge.render();
+ expect(gauge.chart.views[0].id).toEqual(INDICATEOR_VIEW_ID);
+ expect(gauge.chart.views[1].id).toEqual(RANGE_VIEW_ID);
// @ts-ignore
expect(gauge.chart.views[1].getYScales()[0].ticks).toEqual([0, 0.25, 0.5, 0.75, 1]);
expect(gauge.chart.views.length).toBe(2);
@@ -141,6 +144,7 @@ describe('gauge', () => {
gauge.render();
+ expect(gauge.chart.views[0].id).toEqual(RANGE_VIEW_ID);
expect(gauge.chart.views.length).toBe(1);
expect(gauge.chart.views[0].geometries[0].type).toBe('interval');
diff --git a/__tests__/unit/plots/gauge/statistic-spec.ts b/__tests__/unit/plots/gauge/statistic-spec.ts
index 4258f71a8b..91df010fc2 100644
--- a/__tests__/unit/plots/gauge/statistic-spec.ts
+++ b/__tests__/unit/plots/gauge/statistic-spec.ts
@@ -44,6 +44,23 @@ describe('gauge statistic', () => {
expect((annotations[0] as HTMLElement).innerText).toBe('测试');
});
+ it('change data', () => {
+ gauge.changeData(0.35);
+ const annotations = document.body.querySelectorAll('.g2-html-annotation');
+ expect(annotations.length).toBe(2);
+ expect((annotations[1] as HTMLElement).innerText).toBe('35.0%');
+
+ gauge.changeData(0.15);
+ expect((document.body.querySelectorAll('.g2-html-annotation')[1] as HTMLElement).innerText).toBe('15.0%');
+
+ gauge.update({ statistic: { content: {}, title: false } });
+ expect(document.body.querySelectorAll('.g2-html-annotation').length).toBe(1);
+ expect((document.body.querySelectorAll('.g2-html-annotation')[0] as HTMLElement).innerText).toBe('15.0%');
+
+ gauge.changeData(0.05);
+ expect((document.body.querySelectorAll('.g2-html-annotation')[0] as HTMLElement).innerText).toBe('5.0%');
+ });
+
afterAll(() => {
gauge.destroy();
});
diff --git a/__tests__/unit/plots/gauge/utils-spec.ts b/__tests__/unit/plots/gauge/utils-spec.ts
new file mode 100644
index 0000000000..d809956757
--- /dev/null
+++ b/__tests__/unit/plots/gauge/utils-spec.ts
@@ -0,0 +1,28 @@
+import { PERCENT, RANGE_TYPE, RANGE_VALUE } from '../../../../src/plots/gauge/constant';
+import { getIndicatorData, getRangeData } from '../../../../src/plots/gauge/utils';
+
+describe('gauge utils to getData', () => {
+ it('get indicatorData', () => {
+ expect(getIndicatorData(0.1)).toEqual([{ [PERCENT]: 0.1 }]);
+ expect(getIndicatorData(1.4)).toEqual([{ [PERCENT]: 1 }]);
+ expect(getIndicatorData(-0.4)).toEqual([{ [PERCENT]: 0 }]);
+ });
+
+ it('get rangeData', () => {
+ expect(getRangeData(0.5, { ticks: [0, 0.3, 1] })).toEqual([
+ { [RANGE_VALUE]: 0.3, [RANGE_TYPE]: '1' },
+ { [RANGE_VALUE]: 0.7, [RANGE_TYPE]: '2' },
+ ]);
+
+ expect(getRangeData(0.5)).toEqual([
+ { [RANGE_VALUE]: 0.5, [RANGE_TYPE]: '1' },
+ { [RANGE_VALUE]: 0.5, [RANGE_TYPE]: '2' },
+ ]);
+
+ expect(getRangeData(-0.5)).toEqual([{ [RANGE_VALUE]: 1, [RANGE_TYPE]: '2' }]);
+ expect(getRangeData(1.5)).toEqual([{ [RANGE_VALUE]: 1, [RANGE_TYPE]: '1' }]);
+
+ expect(getRangeData(0)).toEqual([{ [RANGE_VALUE]: 1, [RANGE_TYPE]: '2' }]);
+ expect(getRangeData(1)).toEqual([{ [RANGE_VALUE]: 1, [RANGE_TYPE]: '1' }]);
+ });
+});
diff --git a/__tests__/unit/plots/line/change-data-spec.ts b/__tests__/unit/plots/line/change-data-spec.ts
new file mode 100644
index 0000000000..1565f29aa6
--- /dev/null
+++ b/__tests__/unit/plots/line/change-data-spec.ts
@@ -0,0 +1,51 @@
+import { Line } from '../../../../src';
+import { partySupport } from '../../../data/party-support';
+import { createDiv } from '../../../utils/dom';
+
+describe('line', () => {
+ it('change data', () => {
+ const line = new Line(createDiv(), {
+ width: 400,
+ height: 300,
+ data: partySupport.filter((o) => ['FF'].includes(o.type)),
+ xField: 'date',
+ yField: 'value',
+ seriesField: 'type',
+ color: ['blue', 'red'],
+ appendPadding: 10,
+ connectNulls: true,
+ });
+
+ line.render();
+
+ expect(line.chart.geometries[0].elements.length).toBe(1);
+
+ line.changeData(partySupport.filter((o) => ['FF', 'Lab'].includes(o.type)));
+ expect(line.chart.geometries[0].elements.length).toBe(2);
+ expect(line.options.data).toEqual(partySupport.filter((o) => ['FF', 'Lab'].includes(o.type)));
+
+ line.destroy();
+ });
+
+ it('add point', () => {
+ const line = new Line(createDiv(), {
+ width: 400,
+ height: 300,
+ data: [
+ { type: '1', value: 10 },
+ { type: '2', value: 3 },
+ ],
+ xField: 'type',
+ yField: 'value',
+ point: {},
+ });
+
+ line.render();
+ expect(line.chart.geometries[1].elements.length).toBe(2);
+
+ line.changeData([...line.options.data, { type: '3', value: 10 }]);
+ expect(line.chart.geometries[1].elements.length).toBe(3);
+
+ line.destroy();
+ });
+});
diff --git a/docs/api/plots/gauge.zh.md b/docs/api/plots/gauge.zh.md
index 2455c72bdc..cd96d8ecba 100644
--- a/docs/api/plots/gauge.zh.md
+++ b/docs/api/plots/gauge.zh.md
@@ -49,8 +49,10 @@ order: 22
| 配置项 | 类型 | 描述 |
| ------ | -------- | ------------------------------------ |
-| ticks | number[] | 辅助圆弧显示数字数组 |
-| color | string[] | 辅助圆弧的颜色色板,按照色板顺序取值 |
+| ticks | _number[]_ | 辅助圆弧显示数字数组 |
+| color | _string/|string[]_ | 辅助圆弧的颜色色板,按照色板顺序取值; 当设置 ticks 时,color 无法使用回调的方式 |
+
+
#### axis
diff --git a/examples/line/basic/demo/dynamic-line.ts b/examples/line/basic/demo/dynamic-line.ts
new file mode 100644
index 0000000000..1dc92d8fbe
--- /dev/null
+++ b/examples/line/basic/demo/dynamic-line.ts
@@ -0,0 +1,29 @@
+import { Line } from '@antv/g2plot';
+
+fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json')
+ .then((res) => res.json())
+ .then((data) => {
+ const line = new Line('container', {
+ data,
+ padding: 'auto',
+ xField: 'Date',
+ yField: 'scales',
+ xAxis: {
+ type: 'timeCat',
+ tickCount: 5,
+ },
+ });
+
+ line.render();
+
+ let year = 2017;
+ let month = 2;
+ const interval = setInterval(() => {
+ if (year > 2211) {
+ clearInterval(interval);
+ }
+ month = (month + 1) % 12;
+ year += Math.ceil(month / 12);
+ line.changeData([...line.options.data, { Date: `${year}-${month}`, scales: 1300 * Math.random() + 500 }]);
+ }, 500);
+ });
diff --git a/examples/line/basic/demo/line-with-data-marker.ts b/examples/line/basic/demo/line-with-data-marker.ts
new file mode 100644
index 0000000000..ec3444ee77
--- /dev/null
+++ b/examples/line/basic/demo/line-with-data-marker.ts
@@ -0,0 +1,118 @@
+import { G2, Line } from '@antv/g2plot';
+
+G2.registerShape('point', 'breath-point', {
+ draw(cfg, container) {
+ const data = cfg.data;
+ const point = { x: cfg.x, y: cfg.y };
+ const group = container.addGroup();
+ if (data.time === '14.20' && data.date === 'today') {
+ const decorator1 = group.addShape('circle', {
+ attrs: {
+ x: point.x,
+ y: point.y,
+ r: 10,
+ fill: cfg.color,
+ opacity: 0.5,
+ },
+ });
+ const decorator2 = group.addShape('circle', {
+ attrs: {
+ x: point.x,
+ y: point.y,
+ r: 10,
+ fill: cfg.color,
+ opacity: 0.5,
+ },
+ });
+ const decorator3 = group.addShape('circle', {
+ attrs: {
+ x: point.x,
+ y: point.y,
+ r: 10,
+ fill: cfg.color,
+ opacity: 0.5,
+ },
+ });
+ decorator1.animate(
+ {
+ r: 20,
+ opacity: 0,
+ },
+ {
+ duration: 1800,
+ easing: 'easeLinear',
+ repeat: true,
+ }
+ );
+ decorator2.animate(
+ {
+ r: 20,
+ opacity: 0,
+ },
+ {
+ duration: 1800,
+ easing: 'easeLinear',
+ repeat: true,
+ delay: 600,
+ }
+ );
+ decorator3.animate(
+ {
+ r: 20,
+ opacity: 0,
+ },
+ {
+ duration: 1800,
+ easing: 'easeLinear',
+ repeat: true,
+ delay: 1200,
+ }
+ );
+ group.addShape('circle', {
+ attrs: {
+ x: point.x,
+ y: point.y,
+ r: 6,
+ fill: cfg.color,
+ opacity: 0.7,
+ },
+ });
+ group.addShape('circle', {
+ attrs: {
+ x: point.x,
+ y: point.y,
+ r: 1.5,
+ fill: cfg.color,
+ },
+ });
+ }
+
+ return group;
+ },
+});
+
+fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/cpu-data.json')
+ .then((res) => res.json())
+ .then((data) => {
+ const plot = new Line('container', {
+ autoFit: true,
+ height: 500,
+ data,
+ meta: {
+ cpu: {
+ time: { type: 'cat' },
+ max: 100,
+ min: 0,
+ },
+ },
+ xField: 'time',
+ yField: 'cpu',
+ seriesField: 'date',
+ tooltip: { showMarkers: false },
+ point: {
+ shape: 'breath-point',
+ },
+ });
+
+ plot.render();
+ });
diff --git a/examples/line/basic/demo/line.ts b/examples/line/basic/demo/line.ts
index 1f04fa0419..89e31c97b4 100644
--- a/examples/line/basic/demo/line.ts
+++ b/examples/line/basic/demo/line.ts
@@ -15,15 +15,4 @@ fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38cc
});
line.render();
- let cnt = 0;
- let smooth = false;
- const interval = setInterval(() => {
- if (cnt < 5) {
- smooth = !smooth;
- cnt += 1;
- line.update({ smooth });
- } else {
- clearInterval(interval);
- }
- }, 3000);
});
diff --git a/examples/line/basic/demo/meta.json b/examples/line/basic/demo/meta.json
index a3bca467ae..4435247f63 100644
--- a/examples/line/basic/demo/meta.json
+++ b/examples/line/basic/demo/meta.json
@@ -10,13 +10,21 @@
"zh": "基础折线图",
"en": "Basic line plot"
},
+ "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/aiERL4ey%24U/08d95f7b-46cb-4bfd-89b2-be36343d44a1.png"
+ },
+ {
+ "filename": "spline.ts",
+ "title": {
+ "zh": "基础曲线图",
+ "en": "Basic spline plot"
+ },
"screenshot": "https://gw.alipayobjects.com/mdn/rms_d314dd/afts/img/A*DRzUQ4UkxjMAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "line-point-style.ts",
"title": {
"zh": "配置折线数据点样式",
- "en": "Line plot data point style"
+ "en": "Set style of line plot point"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_d314dd/afts/img/A*VN5SQYsPOaIAAAAAAAAAAAAAARQnAQ"
},
@@ -28,11 +36,27 @@
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_d314dd/afts/img/A*r8MPQ4n9CIQAAAAAAAAAAAAAARQnAQ"
},
+ {
+ "filename": "dynamic-line.ts",
+ "title": {
+ "zh": "动态更新折线图",
+ "en": "Line plot updated dynamic"
+ },
+ "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/vOmMGBA1k6/dongtaigengxinzhexiantushuju2.gif"
+ },
+ {
+ "filename": "line-with-data-marker.ts",
+ "title": {
+ "zh": "带标注点的折线图",
+ "en": "Line plot with dataMarker"
+ },
+ "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/7jMv8M%26Dlh/dongtaigengxinzhexiantushuju.gif"
+ },
{
"filename": "line-annotation.ts",
"title": {
- "zh": "折线图带图表标注",
- "en": "Line plot with guide line"
+ "zh": "条件样式折线图",
+ "en": "Line plot with regionFilter"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_d314dd/afts/img/A*7V6nSpj64uYAAAAAAAAAAAAAARQnAQ"
}
diff --git a/examples/line/basic/demo/spline.ts b/examples/line/basic/demo/spline.ts
new file mode 100644
index 0000000000..24d6792fb1
--- /dev/null
+++ b/examples/line/basic/demo/spline.ts
@@ -0,0 +1,19 @@
+import { Line } from '@antv/g2plot';
+
+fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json')
+ .then((res) => res.json())
+ .then((data) => {
+ const line = new Line('container', {
+ data,
+ padding: 'auto',
+ xField: 'Date',
+ yField: 'scales',
+ xAxis: {
+ type: 'timeCat',
+ tickCount: 5,
+ },
+ smooth: true,
+ });
+
+ line.render();
+ });
diff --git a/examples/progress-plots/gauge/demo/basic.ts b/examples/progress-plots/gauge/demo/basic.ts
index f4dcae6a65..713eac1352 100644
--- a/examples/progress-plots/gauge/demo/basic.ts
+++ b/examples/progress-plots/gauge/demo/basic.ts
@@ -49,7 +49,8 @@ const interval = setInterval(() => {
if (data >= 0.85) {
clearInterval(interval);
} else {
- data += 0.095;
- gauge.update({ percent: data, range: { color: getColor(data) } });
+ data += 0.001;
+ gauge.changeData(data);
+ gauge.update({ range: { color: getColor(data) } });
}
-}, 500);
+}, 100);
diff --git a/examples/progress-plots/gauge/demo/complex.ts b/examples/progress-plots/gauge/demo/complex.ts
index 2b071a54e7..178c9a0728 100644
--- a/examples/progress-plots/gauge/demo/complex.ts
+++ b/examples/progress-plots/gauge/demo/complex.ts
@@ -56,6 +56,6 @@ const interval = setInterval(() => {
if (data >= 1) {
clearInterval(interval);
}
- data += 0.1;
+ data += 0.01;
gauge.changeData(data);
-}, 1000);
+}, 400);
diff --git a/src/core/plot.ts b/src/core/plot.ts
index dfe57f7a9d..c6dc923d5e 100644
--- a/src/core/plot.ts
+++ b/src/core/plot.ts
@@ -161,14 +161,22 @@ export abstract class Plot extends EE {
}
/**
- * 更新配置
+ * 更新: 更新配置且重新渲染
* @param options
*/
public update(options: Partial) {
- this.options = deepAssign({}, this.options, options);
+ this.updateOption(options);
this.render();
}
+ /**
+ * 更新配置
+ * @param options
+ */
+ protected updateOption(options: Partial) {
+ this.options = deepAssign({}, this.options, options);
+ }
+
/**
* 设置状态
* @param type 状态类型,支持 'active' | 'inactive' | 'selected' 三种
@@ -205,6 +213,7 @@ export abstract class Plot extends EE {
/**
* 更新数据
+ * @override
* @param options
*/
public changeData(data: any) {
diff --git a/src/plots/gauge/adaptor.ts b/src/plots/gauge/adaptor.ts
index cd80e498f0..101c54f365 100644
--- a/src/plots/gauge/adaptor.ts
+++ b/src/plots/gauge/adaptor.ts
@@ -1,12 +1,12 @@
-import { isString, clamp, size } from '@antv/util';
+import { isString } from '@antv/util';
import { interaction, animation, theme, scale } from '../../adaptor/common';
import { AXIS_META_CONFIG_KEYS } from '../../constant';
import { Params } from '../../core/adaptor';
import { Data } from '../../types';
import { deepAssign, flow, pick, renderGaugeStatistic } from '../../utils';
-import { RANGE_TYPE, RANGE_VALUE, PERCENT, DEFAULT_COLOR } from './constant';
+import { RANGE_TYPE, RANGE_VALUE, PERCENT, DEFAULT_COLOR, INDICATEOR_VIEW_ID, RANGE_VIEW_ID } from './constant';
import { GaugeOptions } from './types';
-import { processRangeData } from './utils';
+import { getIndicatorData, getRangeData } from './utils';
/**
* geometry 处理
@@ -15,15 +15,14 @@ import { processRangeData } from './utils';
function geometry(params: Params): Params {
const { chart, options } = params;
const { percent, range, radius, innerRadius, startAngle, endAngle, axis, indicator } = options;
- const { ticks, color } = range;
- const clampTicks = size(ticks) ? ticks : [0, clamp(percent, 0, 1), 1];
+ const { color } = range;
// 指标 & 指针
// 如果开启在应用
if (indicator) {
- const indicatorData = [{ [PERCENT]: clamp(percent, 0, 1) }];
+ const indicatorData = getIndicatorData(percent);
- const v1 = chart.createView();
+ const v1 = chart.createView({ id: INDICATEOR_VIEW_ID });
v1.data(indicatorData);
v1.point()
@@ -48,8 +47,8 @@ function geometry(params: Params): Params {
// 辅助 range
// [{ range: 1, type: '0' }]
- const rangeData: Data = processRangeData(clampTicks as number[]);
- const v2 = chart.createView();
+ const rangeData: Data = getRangeData(percent, options.range);
+ const v2 = chart.createView({ id: RANGE_VIEW_ID });
v2.data(rangeData);
const rangeColor = isString(color) ? [color, DEFAULT_COLOR] : color;
@@ -88,10 +87,12 @@ function meta(params: Params): Params {
* 统计指标文档
* @param params
*/
-function statistic(params: Params): Params {
+function statistic(params: Params, updated?: boolean): Params {
const { chart, options } = params;
const { statistic, percent } = options;
+ // 先清空标注,再重新渲染
+ chart.getController('annotation').clear(true);
if (statistic) {
const { content } = statistic;
let transformContent;
@@ -115,6 +116,10 @@ function statistic(params: Params): Params {
renderGaugeStatistic(chart, { statistic: { ...statistic, content: transformContent } }, { percent });
}
+ if (updated) {
+ chart.render(true);
+ }
+
return params;
}
@@ -131,6 +136,11 @@ function other(params: Params): Params {
return params;
}
+/**
+ * 对外暴露的 adaptor
+ */
+export { statistic };
+
/**
* 图适配器
* @param chart
diff --git a/src/plots/gauge/constant.ts b/src/plots/gauge/constant.ts
index 33d637f2b3..3a007c1ce1 100644
--- a/src/plots/gauge/constant.ts
+++ b/src/plots/gauge/constant.ts
@@ -3,3 +3,7 @@ export const RANGE_TYPE = 'type';
export const PERCENT = 'percent';
export const DEFAULT_COLOR = '#f0f0f0';
+
+/** 仪表盘由 指针和表盘 组成 */
+export const INDICATEOR_VIEW_ID = 'indicator-view';
+export const RANGE_VIEW_ID = 'range-view';
diff --git a/src/plots/gauge/index.ts b/src/plots/gauge/index.ts
index 2293e05a0c..61b771b2d0 100644
--- a/src/plots/gauge/index.ts
+++ b/src/plots/gauge/index.ts
@@ -1,8 +1,9 @@
import { Plot } from '../../core/plot';
import { Adaptor } from '../../core/adaptor';
import { GaugeOptions } from './types';
-import { adaptor } from './adaptor';
-import { RANGE_VALUE, PERCENT } from './constant';
+import { adaptor, statistic } from './adaptor';
+import { RANGE_VALUE, PERCENT, INDICATEOR_VIEW_ID, RANGE_VIEW_ID } from './constant';
+import { getIndicatorData, getRangeData } from './utils';
// 注册 shape
import './shapes/gauge';
@@ -81,9 +82,19 @@ export class Gauge extends Plot {
* @param percent
*/
public changeData(percent: number) {
- this.update({
- percent,
- });
+ this.updateOption({ percent });
+
+ const indicatorView = this.chart.views.find((v) => v.id === INDICATEOR_VIEW_ID);
+ if (indicatorView) {
+ indicatorView.data(getIndicatorData(percent));
+ }
+
+ const rangeView = this.chart.views.find((v) => v.id === RANGE_VIEW_ID);
+ if (rangeView) {
+ rangeView.data(getRangeData(percent, this.options.range));
+ }
+ // todo 后续让 G2 层在 afterrender 之后,来重绘 annotations
+ statistic({ chart: this.chart, options: this.options }, true);
}
/**
diff --git a/src/plots/gauge/utils.ts b/src/plots/gauge/utils.ts
index c07103e731..fae285bc69 100644
--- a/src/plots/gauge/utils.ts
+++ b/src/plots/gauge/utils.ts
@@ -1,5 +1,7 @@
+import { clamp, get, size } from '@antv/util';
import { Data, Datum } from '../../types';
-import { RANGE_VALUE, RANGE_TYPE } from './constant';
+import { RANGE_VALUE, RANGE_TYPE, PERCENT } from './constant';
+import { GaugeOptions } from './types';
/**
* 将 range 生成为 data 数据
@@ -17,3 +19,23 @@ export function processRangeData(range: number[]): Data {
.filter((d: Datum) => !!d[RANGE_VALUE])
);
}
+
+/**
+ * 获取 仪表盘 指针数据
+ * @param percent
+ */
+export function getIndicatorData(percent: GaugeOptions['percent']): Data {
+ return [{ [PERCENT]: clamp(percent, 0, 1) }];
+}
+
+/**
+ * 获取仪表盘 表盘弧形数据
+ * @param percent
+ * @param range
+ */
+export function getRangeData(percent: GaugeOptions['percent'], range?: GaugeOptions['range']): Data {
+ const ticks = get(range, ['ticks'], []);
+
+ const clampTicks = size(ticks) ? ticks : [0, clamp(percent, 0, 1), 1];
+ return processRangeData(clampTicks as number[]);
+}
diff --git a/src/plots/line/index.ts b/src/plots/line/index.ts
index 43ee5389e8..359a745313 100644
--- a/src/plots/line/index.ts
+++ b/src/plots/line/index.ts
@@ -12,6 +12,15 @@ export class Line extends Plot {
/** 图表类型 */
public type: string = 'line';
+ /**
+ * @override
+ * @param data
+ */
+ public changeData(data: LineOptions['data']) {
+ this.updateOption({ data });
+ this.chart.changeData(data);
+ }
+
/**
* 获取 折线图 默认配置
*/