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); + } + /** * 获取 折线图 默认配置 */