This is an automated email from the ASF dual-hosted git repository. sushuang pushed a commit to branch remove-component in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit f5a9667d8e234299b5eef35089015200d0456fdb Author: 100pah <sushuang0...@gmail.com> AuthorDate: Thu Jul 16 19:00:06 2020 +0800 fix: (1) Inside dataZoom can not dispose when grid removed. (2) uniform the reference between components. --- src/chart/themeRiver/ThemeRiverSeries.ts | 8 +- src/component/dataZoom/AxisProxy.ts | 18 +- src/component/dataZoom/DataZoomModel.ts | 15 +- src/component/dataZoom/DataZoomView.ts | 70 -------- src/component/dataZoom/InsideZoomView.ts | 128 +++++++------- src/component/dataZoom/SliderZoomView.ts | 91 ++++------ src/component/dataZoom/helper.ts | 88 ++++++++-- src/component/dataZoom/roams.ts | 265 +++++++++++++++++------------ src/component/toolbox/feature/DataZoom.ts | 6 +- src/component/toolbox/feature/MagicType.ts | 7 +- src/coord/axisModelCommonMixin.ts | 1 - src/coord/cartesian/AxisModel.ts | 7 +- src/coord/cartesian/Grid.ts | 6 +- src/coord/cartesian/cartesianAxisHelper.ts | 5 +- src/coord/geo/Geo.ts | 6 +- src/coord/parallel/parallelCreator.ts | 9 +- src/coord/polar/AxisModel.ts | 7 +- src/coord/polar/polarCreator.ts | 9 +- src/coord/single/singleCreator.ts | 9 +- src/model/Component.ts | 6 +- src/model/referHelper.ts | 11 +- src/util/model.ts | 38 +++-- test/dataZoom-feature.html | 2 +- test/option-replaceMerge.html | 123 +++++++------ 24 files changed, 494 insertions(+), 441 deletions(-) diff --git a/src/chart/themeRiver/ThemeRiverSeries.ts b/src/chart/themeRiver/ThemeRiverSeries.ts index 3f0cc49..50c310b 100644 --- a/src/chart/themeRiver/ThemeRiverSeries.ts +++ b/src/chart/themeRiver/ThemeRiverSeries.ts @@ -22,7 +22,7 @@ import createDimensions from '../../data/helper/createDimensions'; import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper'; import List from '../../data/List'; import * as zrUtil from 'zrender/src/core/util'; -import {groupData} from '../../util/model'; +import {groupData, SINGLE_REFERRING} from '../../util/model'; import {encodeHTML} from '../../util/format'; import LegendVisualProvider from '../../visual/LegendVisualProvider'; import { @@ -172,11 +172,7 @@ class ThemeRiverSeriesModel extends SeriesModel<ThemeRiverSeriesOption> { */ getInitialData(option: ThemeRiverSeriesOption, ecModel: GlobalModel): List { - const singleAxisModel = ecModel.queryComponents({ - mainType: 'singleAxis', - index: this.get('singleAxisIndex'), - id: this.get('singleAxisId') - })[0]; + const singleAxisModel = this.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; const axisType = singleAxisModel.get('type'); diff --git a/src/component/dataZoom/AxisProxy.ts b/src/component/dataZoom/AxisProxy.ts index 196c71d..f34a08b 100644 --- a/src/component/dataZoom/AxisProxy.ts +++ b/src/component/dataZoom/AxisProxy.ts @@ -19,7 +19,6 @@ import * as zrUtil from 'zrender/src/core/util'; import * as numberUtil from '../../util/number'; -import * as helper from './helper'; import sliderMove from '../helper/sliderMove'; import GlobalModel from '../../model/Global'; import SeriesModel from '../../model/Series'; @@ -30,6 +29,8 @@ import DataZoomModel from './DataZoomModel'; import { AxisBaseModel } from '../../coord/AxisBaseModel'; import { unionAxisExtentFromData } from '../../coord/axisHelper'; import { ensureScaleRawExtentInfo } from '../../coord/scaleRawExtentInfo'; +import { getAxisMainType, isCoordSupported, DataZoomAxisDimension } from './helper'; +import { SINGLE_REFERRING } from '../../util/model'; const each = zrUtil.each; const asc = numberUtil.asc; @@ -54,7 +55,7 @@ class AxisProxy { ecModel: GlobalModel; - private _dimName: string; + private _dimName: DataZoomAxisDimension; private _axisIndex: number; private _valueWindow: [number, number]; @@ -66,7 +67,12 @@ class AxisProxy { private _dataZoomModel: DataZoomModel; - constructor(dimName: string, axisIndex: number, dataZoomModel: DataZoomModel, ecModel: GlobalModel) { + constructor( + dimName: DataZoomAxisDimension, + axisIndex: number, + dataZoomModel: DataZoomModel, + ecModel: GlobalModel + ) { this._dimName = dimName; this._axisIndex = axisIndex; @@ -107,9 +113,9 @@ class AxisProxy { const seriesModels: SeriesModel[] = []; this.ecModel.eachSeries(function (seriesModel) { - if (helper.isCoordSupported(seriesModel.get('coordinateSystem'))) { - const axisMainType = helper.getAxisMainType(this._dimName); - const axisModel = seriesModel.getReferringComponents(axisMainType, true).models[0]; + if (isCoordSupported(seriesModel)) { + const axisMainType = getAxisMainType(this._dimName); + const axisModel = seriesModel.getReferringComponents(axisMainType, SINGLE_REFERRING).models[0]; if (axisModel && this._axisIndex === axisModel.componentIndex) { seriesModels.push(seriesModel); } diff --git a/src/component/dataZoom/DataZoomModel.ts b/src/component/dataZoom/DataZoomModel.ts index db5c440..38aa4e7 100644 --- a/src/component/dataZoom/DataZoomModel.ts +++ b/src/component/dataZoom/DataZoomModel.ts @@ -34,6 +34,7 @@ import { } from './helper'; import SingleAxisModel from '../../coord/single/AxisModel'; import { __DEV__ } from '../../config'; +import { MULTIPLE_REFERRING, SINGLE_REFERRING } from '../../util/model'; export interface DataZoomOption extends ComponentOption { @@ -170,6 +171,8 @@ class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends Compon private _targetAxisInfoMap: DataZoomTargetAxisInfoMap; + private _noTarget: boolean; + /** * It is `[rangeModeForMin, rangeModeForMax]`. * The optional values for `rangeMode`: @@ -274,13 +277,15 @@ class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends Compon this._orient = optionOrient || 'horizontal'; this._fillAutoTargetAxisByOrient(targetAxisIndexMap, this._orient); } + + this._noTarget = !targetAxisIndexMap.keys().length; } private _fillSpecifiedTargetAxis(targetAxisIndexMap: DataZoomTargetAxisInfoMap): boolean { let hasAxisSpecified = false; each(DATA_ZOOM_AXIS_DIMENSIONS, function (axisDim) { - const refering = this.getReferringComponents(getAxisMainType(axisDim), false); + const refering = this.getReferringComponents(getAxisMainType(axisDim), MULTIPLE_REFERRING); // When user set axisIndex as a empty array, we think that user specify axisIndex // but do not want use auto mode. Because empty array may be encountered when // some error occured. @@ -331,10 +336,10 @@ class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends Compon // Find parallel axes in the same grid. if (axisDim === 'x' || axisDim === 'y') { - const gridModel = axisModel.getReferringComponents('grid', true).models[0]; + const gridModel = axisModel.getReferringComponents('grid', SINGLE_REFERRING).models[0]; gridModel && each(axisModels, function (axModel) { if (axisModel.componentIndex !== axModel.componentIndex - && gridModel === axModel.getReferringComponents('grid', true).models[0] + && gridModel === axModel.getReferringComponents('grid', SINGLE_REFERRING).models[0] ) { axisInfo.add(axModel.componentIndex); } @@ -408,6 +413,10 @@ class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends Compon }); } + noTarget(): boolean { + return this._noTarget; + } + getFirstTargetAxisModel(): AxisBaseModel { let firstAxisModel: AxisBaseModel; this.eachTargetAxis(function (axisDim, axisIndex) { diff --git a/src/component/dataZoom/DataZoomView.ts b/src/component/dataZoom/DataZoomView.ts index 8f9b285..2a96a35 100644 --- a/src/component/dataZoom/DataZoomView.ts +++ b/src/component/dataZoom/DataZoomView.ts @@ -21,16 +21,7 @@ import ComponentView from '../../view/Component'; import DataZoomModel from './DataZoomModel'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../ExtensionAPI'; -import { AxisBaseModel } from '../../coord/AxisBaseModel'; -import { Dictionary } from '../../util/types'; -import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem'; -import { getAxisMainType } from './helper'; -export interface CoordInfo { - model: CoordinateSystemHostModel - axisModels: AxisBaseModel[] - coordIndex: number -} class DataZoomView extends ComponentView { static type = 'dataZoom'; @@ -46,67 +37,6 @@ class DataZoomView extends ComponentView { this.api = api; } - /** - * Find the first target coordinate system. - * - * @protected - * @return {Object} { - * grid: [ - * {model: coord0, axisModels: [axis1, axis3], coordIndex: 1}, - * {model: coord1, axisModels: [axis0, axis2], coordIndex: 0}, - * ... - * ], // cartesians must not be null/undefined. - * polar: [ - * {model: coord0, axisModels: [axis4], coordIndex: 0}, - * ... - * ], // polars must not be null/undefined. - * singleAxis: [ - * {model: coord0, axisModels: [], coordIndex: 0} - * ] - */ - getTargetCoordInfo() { - const dataZoomModel = this.dataZoomModel; - const ecModel = this.ecModel; - const coordSysLists: Dictionary<CoordInfo[]> = {}; - - dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { - const axisModel = ecModel.getComponent(getAxisMainType(axisDim), axisIndex) as AxisBaseModel; - if (axisModel) { - const coordModel = axisModel.getCoordSysModel(); - coordModel && save( - coordModel, - axisModel, - coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []), - coordModel.componentIndex - ); - } - }, this); - - function save( - coordModel: CoordinateSystemHostModel, - axisModel: AxisBaseModel, - store: CoordInfo[], - coordIndex: number - ) { - let item; - for (let i = 0; i < store.length; i++) { - if (store[i].model === coordModel) { - item = store[i]; - break; - } - } - if (!item) { - store.push(item = { - model: coordModel, - axisModels: [], - coordIndex: coordIndex - }); - } - item.axisModels.push(axisModel); - } - - return coordSysLists; - } } ComponentView.registerClass(DataZoomView); diff --git a/src/component/dataZoom/InsideZoomView.ts b/src/component/dataZoom/InsideZoomView.ts index 41f99e7..878fef2 100644 --- a/src/component/dataZoom/InsideZoomView.ts +++ b/src/component/dataZoom/InsideZoomView.ts @@ -17,22 +17,21 @@ * under the License. */ -import DataZoomView, {CoordInfo} from './DataZoomView'; +import DataZoomView from './DataZoomView'; import sliderMove from '../helper/sliderMove'; import * as roams from './roams'; import InsideZoomModel from './InsideZoomModel'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../ExtensionAPI'; import ComponentView from '../../view/Component'; -import { each, map, bind } from 'zrender/src/core/util'; +import { bind } from 'zrender/src/core/util'; import RoamController, {RoamEventParams} from '../helper/RoamController'; import { AxisBaseModel } from '../../coord/AxisBaseModel'; import Polar from '../../coord/polar/Polar'; import SingleAxis from '../../coord/single/SingleAxis'; +import { DataZoomCoordSysMainType, DataZoomReferCoordSysInfo } from './helper'; -type SupportedCoordSysName = 'polar' | 'grid' | 'singleAxis'; - class InsideZoomView extends DataZoomView { static type = 'dataZoom.inside'; type = 'dataZoom.inside'; @@ -43,86 +42,71 @@ class InsideZoomView extends DataZoomView { */ range: number[]; - /** - * @override - */ - render(dataZoomModel: InsideZoomModel, ecModel: GlobalModel, api: ExtensionAPI, payload: any) { + render(dataZoomModel: InsideZoomModel, ecModel: GlobalModel, api: ExtensionAPI) { super.render.apply(this, arguments as any); + if (dataZoomModel.noTarget()) { + this._clear(); + return; + } + // Hence the `throttle` util ensures to preserve command order, // here simply updating range all the time will not cause missing // any of the the roam change. this.range = dataZoomModel.getPercentRange(); // Reset controllers. - each(this.getTargetCoordInfo(), function (coordInfoList, coordSysName: SupportedCoordSysName) { - - const allCoordIds = map(coordInfoList, function (coordInfo) { - return roams.generateCoordId(coordInfo.model); - }); - - each(coordInfoList, function (coordInfo) { - const coordModel = coordInfo.model; - - roams.register( - api, - { - coordId: roams.generateCoordId(coordModel), - allCoordIds: allCoordIds, - containsPoint(e, x, y) { - return coordModel.coordinateSystem.containPoint([x, y]); - }, - dataZoomId: dataZoomModel.id, - dataZoomModel: dataZoomModel, - getRange: { - pan: bind(roamHandlers.pan, this, coordInfo, coordSysName), - zoom: bind(roamHandlers.zoom, this, coordInfo, coordSysName), - scrollMove: bind(roamHandlers.scrollMove, this, coordInfo, coordSysName) - } - } - ); - }, this); - - }, this); + roams.setViewInfoToCoordSysRecord( + api, + dataZoomModel, + { + pan: bind(getRangeHandlers.pan, this), + zoom: bind(getRangeHandlers.zoom, this), + scrollMove: bind(getRangeHandlers.scrollMove, this) + } + ); } - /** - * @override - */ dispose() { - roams.unregister(this.api, this.dataZoomModel.id); + this._clear(); super.dispose.apply(this, arguments as any); + } + + private _clear() { + roams.disposeCoordSysRecordIfNeeded(this.api, this.dataZoomModel as InsideZoomModel); this.range = null; } } -interface RoamHandler<T extends RoamEventParams['zoom'] | RoamEventParams['scrollMove'] | RoamEventParams['pan']> { +interface DataZoomGetRangeHandler< + T extends RoamEventParams['zoom'] | RoamEventParams['scrollMove'] | RoamEventParams['pan'] +> { ( - coordInfo: CoordInfo, - coordSysName: SupportedCoordSysName, + coordSysInfo: DataZoomReferCoordSysInfo, + coordSysMainType: DataZoomCoordSysMainType, controller: RoamController, e: T ): [number, number] } -const roamHandlers: { - pan: RoamHandler<RoamEventParams['pan']> - zoom: RoamHandler<RoamEventParams['zoom']> - scrollMove: RoamHandler<RoamEventParams['scrollMove']> +const getRangeHandlers: { + pan: DataZoomGetRangeHandler<RoamEventParams['pan']> + zoom: DataZoomGetRangeHandler<RoamEventParams['zoom']> + scrollMove: DataZoomGetRangeHandler<RoamEventParams['scrollMove']> } & ThisType<InsideZoomView> = { - zoom(coordInfo, coordSysName, controller, e: RoamEventParams['zoom']) { + zoom(coordSysInfo, coordSysMainType, controller, e: RoamEventParams['zoom']) { const lastRange = this.range; const range = lastRange.slice() as [number, number]; // Calculate transform by the first axis. - const axisModel = coordInfo.axisModels[0]; + const axisModel = coordSysInfo.axisModels[0]; if (!axisModel) { return; } - const directionInfo = getDirectionInfo[coordSysName]( - null, [e.originX, e.originY], axisModel, controller, coordInfo + const directionInfo = getDirectionInfo[coordSysMainType]( + null, [e.originX, e.originY], axisModel, controller, coordSysInfo ); const percentPoint = ( directionInfo.signal > 0 @@ -146,9 +130,9 @@ const roamHandlers: { } }, - pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e: RoamEventParams['pan']) { - const directionInfo = getDirectionInfo[coordSysName]( - [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo + pan: makeMover(function (range, axisModel, coordSysInfo, coordSysMainType, controller, e: RoamEventParams['pan']) { + const directionInfo = getDirectionInfo[coordSysMainType]( + [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordSysInfo ); return directionInfo.signal @@ -157,29 +141,31 @@ const roamHandlers: { }), scrollMove: makeMover( - function (range, axisModel, coordInfo, coordSysName, controller, e: RoamEventParams['scrollMove'] + function (range, axisModel, coordSysInfo, coordSysMainType, controller, e: RoamEventParams['scrollMove'] ) { - const directionInfo = getDirectionInfo[coordSysName]( - [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo + const directionInfo = getDirectionInfo[coordSysMainType]( + [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordSysInfo ); return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta; }) }; +export type DataZoomGetRangeHandlers = typeof getRangeHandlers; + function makeMover( getPercentDelta: ( range: [number, number], axisModel: AxisBaseModel, - coordInfo: CoordInfo, - coordSysName: SupportedCoordSysName, + coordSysInfo: DataZoomReferCoordSysInfo, + coordSysMainType: DataZoomCoordSysMainType, controller: RoamController, e: RoamEventParams['scrollMove']| RoamEventParams['pan'] ) => number ) { return function ( this: InsideZoomView, - coordInfo: CoordInfo, - coordSysName: SupportedCoordSysName, + coordSysInfo: DataZoomReferCoordSysInfo, + coordSysMainType: DataZoomCoordSysMainType, controller: RoamController, e: RoamEventParams['scrollMove']| RoamEventParams['pan'] ): [number, number] { @@ -187,13 +173,13 @@ function makeMover( const range = lastRange.slice() as [number, number]; // Calculate transform by the first axis. - const axisModel = coordInfo.axisModels[0]; + const axisModel = coordSysInfo.axisModels[0]; if (!axisModel) { return; } const percentDelta = getPercentDelta( - range, axisModel, coordInfo, coordSysName, controller, e + range, axisModel, coordSysInfo, coordSysMainType, controller, e ); sliderMove(percentDelta, range, [0, 100], 'all'); @@ -218,16 +204,16 @@ interface GetDirectionInfo { newPoint: number[], axisModel: AxisBaseModel, controller: RoamController, - coordInfo: CoordInfo + coordSysInfo: DataZoomReferCoordSysInfo ): DirectionInfo } const getDirectionInfo: Record<'grid' | 'polar' | 'singleAxis', GetDirectionInfo> = { - grid(oldPoint, newPoint, axisModel, controller, coordInfo) { + grid(oldPoint, newPoint, axisModel, controller, coordSysInfo) { const axis = axisModel.axis; const ret = {} as DirectionInfo; - const rect = coordInfo.model.coordinateSystem.getRect(); + const rect = coordSysInfo.model.coordinateSystem.getRect(); oldPoint = oldPoint || [0, 0]; if (axis.dim === 'x') { @@ -246,10 +232,10 @@ const getDirectionInfo: Record<'grid' | 'polar' | 'singleAxis', GetDirectionInfo return ret; }, - polar(oldPoint, newPoint, axisModel, controller, coordInfo) { + polar(oldPoint, newPoint, axisModel, controller, coordSysInfo) { const axis = axisModel.axis; const ret = {} as DirectionInfo; - const polar = coordInfo.model.coordinateSystem as Polar; + const polar = coordSysInfo.model.coordinateSystem as Polar; const radiusExtent = polar.getRadiusAxis().getExtent(); const angleExtent = polar.getAngleAxis().getExtent(); @@ -276,9 +262,9 @@ const getDirectionInfo: Record<'grid' | 'polar' | 'singleAxis', GetDirectionInfo return ret; }, - singleAxis(oldPoint, newPoint, axisModel, controller, coordInfo) { + singleAxis(oldPoint, newPoint, axisModel, controller, coordSysInfo) { const axis = axisModel.axis as SingleAxis; - const rect = coordInfo.model.coordinateSystem.getRect(); + const rect = coordSysInfo.model.coordinateSystem.getRect(); const ret = {} as DirectionInfo; oldPoint = oldPoint || [0, 0]; diff --git a/src/component/dataZoom/SliderZoomView.ts b/src/component/dataZoom/SliderZoomView.ts index 1b47172..addd2c5 100644 --- a/src/component/dataZoom/SliderZoomView.ts +++ b/src/component/dataZoom/SliderZoomView.ts @@ -36,7 +36,7 @@ import { RectLike } from 'zrender/src/core/BoundingRect'; import Axis from '../../coord/Axis'; import SeriesModel from '../../model/Series'; import { AxisBaseModel } from '../../coord/AxisBaseModel'; -import { getAxisMainType } from './helper'; +import { getAxisMainType, collectReferCoordSysModelInfo } from './helper'; const Rect = graphic.Rect; @@ -99,10 +99,6 @@ class SliderZoomView extends DataZoomView { this.api = api; } - - /** - * @override - */ render( dataZoomModel: SliderZoomModel, ecModel: GlobalModel, @@ -117,13 +113,19 @@ class SliderZoomView extends DataZoomView { throttle.createOrUpdate( this, '_dispatchZoomAction', - this.dataZoomModel.get('throttle'), + dataZoomModel.get('throttle'), 'fixRate' ); this._orient = dataZoomModel.getOrient(); - if (this.dataZoomModel.get('show') === false) { + if (dataZoomModel.get('show') === false) { + this.group.removeAll(); + return; + } + + if (dataZoomModel.noTarget()) { + this._clear(); this.group.removeAll(); return; } @@ -138,22 +140,16 @@ class SliderZoomView extends DataZoomView { this._updateView(); } - /** - * @override - */ - remove() { - throttle.clear(this, '_dispatchZoomAction'); - } - - /** - * @override - */ dispose() { + this._clear(); super.dispose.apply(this, arguments as any); + } + + private _clear() { throttle.clear(this, '_dispatchZoomAction'); } - _buildView() { + private _buildView() { const thisGroup = this.group; thisGroup.removeAll(); @@ -174,10 +170,7 @@ class SliderZoomView extends DataZoomView { this._positionGroup(); } - /** - * @private - */ - _resetLocation() { + private _resetLocation() { const dataZoomModel = this.dataZoomModel; const api = this.api; @@ -223,10 +216,7 @@ class SliderZoomView extends DataZoomView { this._orient === VERTICAL && this._size.reverse(); } - /** - * @private - */ - _positionGroup() { + private _positionGroup() { const thisGroup = this.group; const location = this._location; const orient = this._orient; @@ -257,14 +247,11 @@ class SliderZoomView extends DataZoomView { thisGroup.markRedraw(); } - /** - * @private - */ - _getViewExtent() { + private _getViewExtent() { return [0, this._size[0]]; } - _renderBackground() { + private _renderBackground() { const dataZoomModel = this.dataZoomModel; const size = this._size; const barGroup = this._displayables.barGroup; @@ -293,7 +280,7 @@ class SliderZoomView extends DataZoomView { })); } - _renderDataShadow() { + private _renderDataShadow() { const info = this._dataShadowInfo = this._prepareDataShadowInfo(); if (!info) { @@ -383,7 +370,7 @@ class SliderZoomView extends DataZoomView { })); } - _prepareDataShadowInfo() { + private _prepareDataShadowInfo() { const dataZoomModel = this.dataZoomModel; const showDataShadow = dataZoomModel.get('showDataShadow'); @@ -440,7 +427,7 @@ class SliderZoomView extends DataZoomView { return result; } - _renderHandle() { + private _renderHandle() { const displaybles = this._displayables; const handles: [graphic.Path, graphic.Path] = displaybles.handles = [null, null]; const handleLabels: [graphic.Text, graphic.Text] = displaybles.handleLabels = [null, null]; @@ -594,10 +581,7 @@ class SliderZoomView extends DataZoomView { this._updateDataInfo(nonRealtime); } - /** - * @private - */ - _updateDataInfo(nonRealtime?: boolean) { + private _updateDataInfo(nonRealtime?: boolean) { const dataZoomModel = this.dataZoomModel; const displaybles = this._displayables; const handleLabels = displaybles.handleLabels; @@ -660,7 +644,7 @@ class SliderZoomView extends DataZoomView { } } - _formatLabel(value: ParsedValue, axis: Axis) { + private _formatLabel(value: ParsedValue, axis: Axis) { const dataZoomModel = this.dataZoomModel; const labelFormatter = dataZoomModel.get('labelFormatter'); @@ -685,10 +669,9 @@ class SliderZoomView extends DataZoomView { } /** - * @private * @param showOrHide true: show, false: hide */ - _showDataInfo(showOrHide?: boolean) { + private _showDataInfo(showOrHide?: boolean) { // Always show when drgging. showOrHide = this._dragging || showOrHide; @@ -697,7 +680,7 @@ class SliderZoomView extends DataZoomView { handleLabels[1].attr('invisible', !showOrHide); } - _onDragMove(handleIndex: 0 | 1 | 'all', dx: number, dy: number, event: ZRElementEvent) { + private _onDragMove(handleIndex: 0 | 1 | 'all', dx: number, dy: number, event: ZRElementEvent) { this._dragging = true; // For mobile device, prevent screen slider on the button. @@ -718,7 +701,7 @@ class SliderZoomView extends DataZoomView { changed && realtime && this._dispatchZoomAction(); } - _onDragEnd() { + private _onDragEnd() { this._dragging = false; this._showDataInfo(false); @@ -728,7 +711,7 @@ class SliderZoomView extends DataZoomView { !realtime && this._dispatchZoomAction(); } - _onClickPanelClick(e: ZRElementEvent) { + private _onClickPanelClick(e: ZRElementEvent) { const size = this._size; const localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY); @@ -747,8 +730,8 @@ class SliderZoomView extends DataZoomView { } /** - * This action will be throttled. * @private + * This action will be throttled. */ _dispatchZoomAction() { const range = this._range; @@ -762,18 +745,16 @@ class SliderZoomView extends DataZoomView { }); } - /** - * @private - */ - _findCoordRect() { + private _findCoordRect() { // Find the grid coresponding to the first axis referred by dataZoom. let rect: RectLike; - each(this.getTargetCoordInfo(), function (coordInfoList) { - if (!rect && coordInfoList.length) { - const coordSys = coordInfoList[0].model.coordinateSystem; - rect = coordSys.getRect && coordSys.getRect(); - } - }); + const coordSysInfoList = collectReferCoordSysModelInfo(this.dataZoomModel).infoList; + + if (!rect && coordSysInfoList.length) { + const coordSys = coordSysInfoList[0].model.coordinateSystem; + rect = coordSys.getRect && coordSys.getRect(); + } + if (!rect) { const width = this.api.getWidth(); const height = this.api.getHeight(); diff --git a/src/component/dataZoom/helper.ts b/src/component/dataZoom/helper.ts index 7def11e..ef739b1 100644 --- a/src/component/dataZoom/helper.ts +++ b/src/component/dataZoom/helper.ts @@ -17,19 +17,31 @@ * under the License. */ -import { Payload, DimensionName } from '../../util/types'; +import { Payload } from '../../util/types'; import GlobalModel from '../../model/Global'; import DataZoomModel from './DataZoomModel'; -import { indexOf, createHashMap, assert } from 'zrender/src/core/util'; +import { indexOf, createHashMap, assert, HashMap } from 'zrender/src/core/util'; import { __DEV__ } from '../../config'; +import SeriesModel from '../../model/Series'; +import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem'; +import { AxisBaseModel } from '../../coord/AxisBaseModel'; export interface DataZoomPayloadBatchItem { - dataZoomId: string - start?: number - end?: number - startValue?: number - endValue?: number + dataZoomId: string; + start?: number; + end?: number; + startValue?: number; + endValue?: number; +} + +export interface DataZoomReferCoordSysInfo { + model: CoordinateSystemHostModel; + // Notice: if two dataZooms refer the same coordinamte system model, + // (1) The axis they refered may different + // (2) The sequence the axisModels matters, may different in + // different dataZooms. + axisModels: AxisBaseModel[]; } export const DATA_ZOOM_AXIS_DIMENSIONS = [ @@ -43,13 +55,15 @@ type DataZoomAxisIndexPropName = 'xAxisIndex' | 'yAxisIndex' | 'radiusAxisIndex' | 'angleAxisIndex' | 'singleAxisIndex'; type DataZoomAxisIdPropName = 'xAxisId' | 'yAxisId' | 'radiusAxisId' | 'angleAxisId' | 'singleAxisId'; +export type DataZoomCoordSysMainType = 'polar' | 'grid' | 'singleAxis'; // Supported coords. // FIXME: polar has been broken (but rarely used). -const COORDS = ['cartesian2d', 'polar', 'singleAxis'] as const; +const SERIES_COORDS = ['cartesian2d', 'polar', 'singleAxis'] as const; -export function isCoordSupported(coordType: string) { - return indexOf(COORDS, coordType) >= 0; +export function isCoordSupported(seriesModel: SeriesModel): boolean { + const coordType = seriesModel.get('coordinateSystem'); + return indexOf(SERIES_COORDS, coordType) >= 0; } export function getAxisMainType(axisDim: DataZoomAxisDimension): DataZoomAxisMainType { @@ -138,3 +152,57 @@ export function findEffectedDataZooms(ecModel: GlobalModel, payload: Payload): D return effectedModels; } + +/** + * Find the first target coordinate system. + * Available after model built. + * + * @return Like { + * grid: [ + * {model: coord0, axisModels: [axis1, axis3], coordIndex: 1}, + * {model: coord1, axisModels: [axis0, axis2], coordIndex: 0}, + * ... + * ], // cartesians must not be null/undefined. + * polar: [ + * {model: coord0, axisModels: [axis4], coordIndex: 0}, + * ... + * ], // polars must not be null/undefined. + * singleAxis: [ + * {model: coord0, axisModels: [], coordIndex: 0} + * ] + * } + */ +export function collectReferCoordSysModelInfo(dataZoomModel: DataZoomModel): { + infoList: DataZoomReferCoordSysInfo[]; + // Key: coordSysModel.uid + infoMap: HashMap<DataZoomReferCoordSysInfo, string>; +} { + const ecModel = dataZoomModel.ecModel; + const coordSysInfoWrap = { + infoList: [] as DataZoomReferCoordSysInfo[], + infoMap: createHashMap<DataZoomReferCoordSysInfo, string>() + }; + + dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) { + const axisModel = ecModel.getComponent(getAxisMainType(axisDim), axisIndex) as AxisBaseModel; + if (!axisModel) { + return; + } + const coordSysModel = axisModel.getCoordSysModel(); + if (!coordSysModel) { + return; + } + + const coordSysUid = coordSysModel.uid; + let coordSysInfo = coordSysInfoWrap.infoMap.get(coordSysUid); + if (!coordSysInfo) { + coordSysInfo = { model: coordSysModel, axisModels: [] }; + coordSysInfoWrap.infoList.push(coordSysInfo); + coordSysInfoWrap.infoMap.set(coordSysUid, coordSysInfo); + } + + coordSysInfo.axisModels.push(axisModel); + }); + + return coordSysInfoWrap; +} diff --git a/src/component/dataZoom/roams.ts b/src/component/dataZoom/roams.ts index 05524c9..7686d56 100644 --- a/src/component/dataZoom/roams.ts +++ b/src/component/dataZoom/roams.ts @@ -23,156 +23,205 @@ // pan or zoom, only dispatch one action for those data zoom // components. -import RoamController, { RoamType, RoamEventParams } from '../../component/helper/RoamController'; +import * as echarts from '../../echarts'; +import RoamController, { RoamType } from '../../component/helper/RoamController'; import * as throttleUtil from '../../util/throttle'; import { makeInner } from '../../util/model'; import { Dictionary, ZRElementEvent } from '../../util/types'; import ExtensionAPI from '../../ExtensionAPI'; import InsideZoomModel from './InsideZoomModel'; -import { each, indexOf, curry, Curry1 } from 'zrender/src/core/util'; -import ComponentModel from '../../model/Component'; -import { DataZoomPayloadBatchItem } from './helper'; +import { each, curry, Curry1, HashMap, createHashMap } from 'zrender/src/core/util'; +import { + DataZoomPayloadBatchItem, collectReferCoordSysModelInfo, + DataZoomCoordSysMainType, DataZoomReferCoordSysInfo +} from './helper'; +import GlobalModel from '../../model/Global'; +import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem'; +import { DataZoomGetRangeHandlers } from './InsideZoomView'; + interface DataZoomInfo { - coordId: string - containsPoint: (e: ZRElementEvent, x: number, y: number) => boolean - allCoordIds: string[] - dataZoomId: string - getRange: { - pan: (controller: RoamController, e: RoamEventParams['pan']) => [number, number] - zoom: (controller: RoamController, e: RoamEventParams['zoom']) => [number, number] - scrollMove: (controller: RoamController, e: RoamEventParams['scrollMove']) => [number, number] - } - dataZoomModel: InsideZoomModel -} -interface Record { - // key is dataZoomId - dataZoomInfos: Dictionary<DataZoomInfo> - count: number - coordId: string - controller: RoamController - dispatchAction: Curry1<typeof dispatchAction, ExtensionAPI> + getRange: DataZoomGetRangeHandlers; + model: InsideZoomModel; + dzReferCoordSysInfo: DataZoomReferCoordSysInfo } -interface PayloadBatch { - dataZoomId: string +interface CoordSysRecord { + // key: dataZoom.uid + dataZoomInfoMap: HashMap<DataZoomInfo, string>; + model: CoordinateSystemHostModel, + // count: number + // coordId: string + controller: RoamController; + containsPoint: (e: ZRElementEvent, x: number, y: number) => boolean; + dispatchAction: Curry1<typeof dispatchAction, ExtensionAPI>; } -type Store = Dictionary<Record>; -const inner = makeInner<Store, ExtensionAPI>(); +const inner = makeInner<{ + // key: coordSysModel.uid + coordSysRecordMap: HashMap<CoordSysRecord, string>; +}, ExtensionAPI>(); -export function register(api: ExtensionAPI, dataZoomInfo: DataZoomInfo) { - const store = inner(api); - const theDataZoomId = dataZoomInfo.dataZoomId; - const theCoordId = dataZoomInfo.coordId; - // Do clean when a dataZoom changes its target coordnate system. - // Avoid memory leak, dispose all not-used-registered. - each(store, function (record, coordId) { - const dataZoomInfos = record.dataZoomInfos; - if (dataZoomInfos[theDataZoomId] - && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0 - ) { - delete dataZoomInfos[theDataZoomId]; - record.count--; - } - }); +echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, function (ecModel: GlobalModel, api: ExtensionAPI): void { + const apiInner = inner(api); + const coordSysRecordMap = apiInner.coordSysRecordMap + || (apiInner.coordSysRecordMap = createHashMap<CoordSysRecord, string>()); - cleanStore(store); - - let record = store[theCoordId]; - // Create if needed. - if (!record) { - record = store[theCoordId] = { - coordId: theCoordId, - dataZoomInfos: {}, - count: 0, - controller: null, - dispatchAction: curry(dispatchAction, api) - }; - record.controller = createController(api, record); - } + coordSysRecordMap.each(function (coordSysRecord) { + // `coordSysRecordMap` always exists (becuase it hold the `roam controller`, which should + // better not re-create each time), but clear `dataZoomInfoMap` each round of the workflow. + coordSysRecord.dataZoomInfoMap = null; + }); - // Update reference of dataZoom. - !(record.dataZoomInfos[theDataZoomId]) && record.count++; - record.dataZoomInfos[theDataZoomId] = dataZoomInfo; + ecModel.eachComponent( + { mainType: 'dataZoom', subType: 'inside' }, + function (dataZoomModel: InsideZoomModel) { + const dzReferCoordSysWrap = collectReferCoordSysModelInfo(dataZoomModel); - const controllerParams = mergeControllerParams(record.dataZoomInfos); - record.controller.enable(controllerParams.controlType, controllerParams.opt); + each(dzReferCoordSysWrap.infoList, function (dzCoordSysInfo) { - // Consider resize, area should be always updated. - record.controller.setPointerChecker(dataZoomInfo.containsPoint); + const coordSysUid = dzCoordSysInfo.model.uid; + const coordSysRecord = coordSysRecordMap.get(coordSysUid) + || coordSysRecordMap.set(coordSysUid, createCoordSysRecord(api, dzCoordSysInfo.model)); - // Update throttle. - throttleUtil.createOrUpdate( - record, - 'dispatchAction', - dataZoomInfo.dataZoomModel.get('throttle', true), - 'fixRate' + const dataZoomInfoMap = coordSysRecord.dataZoomInfoMap + || (coordSysRecord.dataZoomInfoMap = createHashMap<DataZoomInfo, string>()); + // Notice these props might be changed each time for a single dataZoomModel. + dataZoomInfoMap.set(dataZoomModel.uid, { + dzReferCoordSysInfo: dzCoordSysInfo, + model: dataZoomModel, + getRange: null + }); + }); + } ); -} -export function unregister(api: ExtensionAPI, dataZoomId: string) { - const store = inner(api); + // (1) Merge dataZoom settings for each coord sys and set to the roam controller. + // (2) Clear coord sys if not refered by any dataZoom. + coordSysRecordMap.each(function (coordSysRecord) { + const controller = coordSysRecord.controller; + let firstDzInfo: DataZoomInfo; + const dataZoomInfoMap = coordSysRecord.dataZoomInfoMap; + + if (dataZoomInfoMap) { + const firstDzKey = dataZoomInfoMap.keys()[0]; + if (firstDzKey != null) { + firstDzInfo = dataZoomInfoMap.get(firstDzKey); + } + } + + if (!firstDzInfo) { + disposeCoordSysRecord(coordSysRecordMap, coordSysRecord); + return; + } + + const controllerParams = mergeControllerParams(dataZoomInfoMap); + controller.enable(controllerParams.controlType, controllerParams.opt); + + controller.setPointerChecker(coordSysRecord.containsPoint); + + throttleUtil.createOrUpdate( + coordSysRecord, + 'dispatchAction', + firstDzInfo.model.get('throttle', true), + 'fixRate' + ); + }); + +}); + - each(store, function (record) { - record.controller.dispose(); - const dataZoomInfos = record.dataZoomInfos; - if (dataZoomInfos[dataZoomId]) { - delete dataZoomInfos[dataZoomId]; - record.count--; +export function setViewInfoToCoordSysRecord( + api: ExtensionAPI, + dataZoomModel: InsideZoomModel, + getRange: DataZoomGetRangeHandlers +): void { + inner(api).coordSysRecordMap.each(function (coordSysRecord) { + const dzInfo = coordSysRecord.dataZoomInfoMap.get(dataZoomModel.uid); + if (dzInfo) { + dzInfo.getRange = getRange; } }); +} - cleanStore(store); +export function disposeCoordSysRecordIfNeeded(api: ExtensionAPI, dataZoomModel: InsideZoomModel) { + const coordSysRecordMap = inner(api).coordSysRecordMap; + const coordSysKeyArr = coordSysRecordMap.keys(); + for (let i = 0; i < coordSysKeyArr.length; i++) { + const coordSysKey = coordSysKeyArr[i]; + const coordSysRecord = coordSysRecordMap.get(coordSysKey); + const dataZoomInfoMap = coordSysRecord.dataZoomInfoMap; + if (dataZoomInfoMap) { + const dzUid = dataZoomModel.uid; + const dzInfo = dataZoomInfoMap.get(dzUid); + if (dzInfo) { + dataZoomInfoMap.removeKey(dzUid); + if (!dataZoomInfoMap.keys().length) { + disposeCoordSysRecord(coordSysRecordMap, coordSysRecord); + } + } + } + } } -/** - * @public - */ -export function generateCoordId(coordModel: ComponentModel) { - return coordModel.type + '\0_' + coordModel.id; +function disposeCoordSysRecord( + coordSysRecordMap: HashMap<CoordSysRecord, string>, + coordSysRecord: CoordSysRecord +): void { + if (coordSysRecord) { + coordSysRecordMap.removeKey(coordSysRecord.model.uid); + const controller = coordSysRecord.controller; + controller && controller.dispose(); + } } -function createController(api: ExtensionAPI, newRecord: Record) { - const controller = new RoamController(api.getZr()); +function createCoordSysRecord(api: ExtensionAPI, coordSysModel: CoordinateSystemHostModel): CoordSysRecord { + // These init props will never change after record created. + const coordSysRecord: CoordSysRecord = { + model: coordSysModel, + containsPoint: curry(containsPoint, coordSysModel), + dispatchAction: curry(dispatchAction, api), + dataZoomInfoMap: null, + controller: null + }; + + // Must not do anything depends on coordSysRecord outside the event handler here, + // because coordSysRecord not completed yet. + const controller = coordSysRecord.controller = new RoamController(api.getZr()); each(['pan', 'zoom', 'scrollMove'] as const, function (eventName) { controller.on(eventName, function (event) { const batch: DataZoomPayloadBatchItem[] = []; - each(newRecord.dataZoomInfos, function (info) { + coordSysRecord.dataZoomInfoMap.each(function (dzInfo) { // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove, // moveOnMouseWheel, ...) enabled. - if (!event.isAvailableBehavior(info.dataZoomModel.option)) { + if (!event.isAvailableBehavior(dzInfo.model.option)) { return; } - const method = (info.getRange || {} as DataZoomInfo['getRange'])[eventName]; - const range = method && method(newRecord.controller, event as any); + const method = (dzInfo.getRange || {} as DataZoomGetRangeHandlers)[eventName]; + const range = method && method( + dzInfo.dzReferCoordSysInfo, + coordSysRecord.model.mainType as DataZoomCoordSysMainType, + coordSysRecord.controller, + event as any + ); - !(info.dataZoomModel as InsideZoomModel).get('disabled', true) && range && batch.push({ - dataZoomId: info.dataZoomId, + !dzInfo.model.get('disabled', true) && range && batch.push({ + dataZoomId: dzInfo.model.id, start: range[0], end: range[1] }); }); - batch.length && newRecord.dispatchAction(batch); + batch.length && coordSysRecord.dispatchAction(batch); }); }); - return controller; -} - -function cleanStore(store: Store) { - each(store, function (record, coordId) { - if (!record.count) { - record.controller.dispose(); - delete store[coordId]; - } - }); + return coordSysRecord; } /** @@ -185,10 +234,16 @@ function dispatchAction(api: ExtensionAPI, batch: DataZoomPayloadBatchItem[]) { }); } +function containsPoint( + coordSysModel: CoordinateSystemHostModel, e: ZRElementEvent, x: number, y: number +): boolean { + return coordSysModel.coordinateSystem.containPoint([x, y]); +} + /** * Merge roamController settings when multiple dataZooms share one roamController. */ -function mergeControllerParams(dataZoomInfos: Dictionary<DataZoomInfo>) { +function mergeControllerParams(dataZoomInfoMap: HashMap<{ model: InsideZoomModel }>) { let controlType: RoamType; // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated // as string, it is probably revert to reserved word by compress tool. See #7411. @@ -201,8 +256,8 @@ function mergeControllerParams(dataZoomInfos: Dictionary<DataZoomInfo>) { }; let preventDefaultMouseMove = true; - each(dataZoomInfos, function (dataZoomInfo) { - const dataZoomModel = dataZoomInfo.dataZoomModel as InsideZoomModel; + dataZoomInfoMap.each(function (dataZoomInfo) { + const dataZoomModel = dataZoomInfo.model; const oneType = dataZoomModel.get('disabled', true) ? false : dataZoomModel.get('zoomLock', true) diff --git a/src/component/toolbox/feature/DataZoom.ts b/src/component/toolbox/feature/DataZoom.ts index 1e11ed2..a69b92f 100644 --- a/src/component/toolbox/feature/DataZoom.ts +++ b/src/component/toolbox/feature/DataZoom.ts @@ -40,16 +40,14 @@ import Cartesian2D from '../../../coord/cartesian/Cartesian2D'; import CartesianAxisModel from '../../../coord/cartesian/AxisModel'; import DataZoomModel from '../../dataZoom/DataZoomModel'; import { - DataZoomPayloadBatchItem, DataZoomAxisDimension, getAxisIndexPropName, - getAxisIdPropName, getAxisMainType + DataZoomPayloadBatchItem, DataZoomAxisDimension } from '../../dataZoom/helper'; import { ModelFinderObject, ModelFinderIndexQuery, makeInternalComponentId, - queryReferringComponents, ModelFinderIdQuery, parseFinder + ModelFinderIdQuery, parseFinder } from '../../../util/model'; import ToolboxModel from '../ToolboxModel'; import { registerInternalOptionCreator } from '../../../model/internalComponentCreator'; -import Model from '../../../model/Model'; import ComponentModel from '../../../model/Component'; diff --git a/src/component/toolbox/feature/MagicType.ts b/src/component/toolbox/feature/MagicType.ts index 2dfd038..b5b3e0f 100644 --- a/src/component/toolbox/feature/MagicType.ts +++ b/src/component/toolbox/feature/MagicType.ts @@ -25,6 +25,7 @@ import { SeriesOption, ECUnitOption } from '../../../util/types'; import GlobalModel from '../../../model/Global'; import ExtensionAPI from '../../../ExtensionAPI'; import SeriesModel from '../../../model/Series'; +import { SINGLE_REFERRING } from '../../../util/model'; const magicTypeLang = lang.toolbox.magicType; const INNER_STACK_KEYWORD = '__ec_magicType_stack__' as const; @@ -117,11 +118,7 @@ class MagicType extends ToolboxFeature<ToolboxMagicTypeFeatureOption> { if (categoryAxis) { const axisDim = categoryAxis.dim; const axisType = axisDim + 'Axis'; - const axisModel = ecModel.queryComponents({ - mainType: axisType, - index: seriesModel.get(name + 'Index' as any), - id: seriesModel.get(name + 'Id' as any) - })[0]; + const axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0]; const axisIndex = axisModel.componentIndex; newOption[axisType] = newOption[axisType] || []; diff --git a/src/coord/axisModelCommonMixin.ts b/src/coord/axisModelCommonMixin.ts index c1c458f..4550618 100644 --- a/src/coord/axisModelCommonMixin.ts +++ b/src/coord/axisModelCommonMixin.ts @@ -17,7 +17,6 @@ * under the License. */ -import * as zrUtil from 'zrender/src/core/util'; import Model from '../model/Model'; import Axis from './Axis'; import { AxisBaseOption } from './axisCommonTypes'; diff --git a/src/coord/cartesian/AxisModel.ts b/src/coord/cartesian/AxisModel.ts index 1d4a6d0..9a21401 100644 --- a/src/coord/cartesian/AxisModel.ts +++ b/src/coord/cartesian/AxisModel.ts @@ -26,6 +26,7 @@ import { AxisBaseOption } from '../axisCommonTypes'; import GridModel from './GridModel'; import { AxisBaseModel } from '../AxisBaseModel'; import {OrdinalSortInfo} from '../../util/types'; +import { SINGLE_REFERRING } from '../../util/model'; export type CartesianAxisPosition = 'top' | 'bottom' | 'left' | 'right'; @@ -50,11 +51,7 @@ class CartesianAxisModel extends ComponentModel<CartesianAxisOption> axis: Axis2D; getCoordSysModel(): GridModel { - return this.ecModel.queryComponents({ - mainType: 'grid', - index: this.option.gridIndex, - id: this.option.gridId - })[0] as GridModel; + return this.getReferringComponents('grid', SINGLE_REFERRING).models[0] as GridModel; } } diff --git a/src/coord/cartesian/Grid.ts b/src/coord/cartesian/Grid.ts index 91e540b..ceb2787 100644 --- a/src/coord/cartesian/Grid.ts +++ b/src/coord/cartesian/Grid.ts @@ -36,7 +36,7 @@ import { import Cartesian2D, {cartesian2DDimensions} from './Cartesian2D'; import Axis2D from './Axis2D'; import CoordinateSystemManager from '../../CoordinateSystem'; -import {ParsedModelFinder} from '../../util/model'; +import {ParsedModelFinder, SINGLE_REFERRING} from '../../util/model'; // Depends on GridModel, AxisModel, which performs preprocess. import GridModel from './GridModel'; @@ -254,9 +254,9 @@ class Grid implements CoordinateSystemMaster { } { const seriesModel = finder.seriesModel; const xAxisModel = finder.xAxisModel - || (seriesModel && seriesModel.getReferringComponents('xAxis', true).models[0]); + || (seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]); const yAxisModel = finder.yAxisModel - || (seriesModel && seriesModel.getReferringComponents('yAxis', true).models[0]); + || (seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]); const gridModel = finder.gridModel; const coordsList = this._coordsList; let cartesian: Cartesian2D; diff --git a/src/coord/cartesian/cartesianAxisHelper.ts b/src/coord/cartesian/cartesianAxisHelper.ts index badc476..1d66179 100644 --- a/src/coord/cartesian/cartesianAxisHelper.ts +++ b/src/coord/cartesian/cartesianAxisHelper.ts @@ -23,6 +23,7 @@ import GridModel from './GridModel'; import CartesianAxisModel from './AxisModel'; import SeriesModel from '../../model/Series'; import { __DEV__ } from '../../config'; +import { SINGLE_REFERRING } from '../../util/model'; interface CartesianAxisLayout { position: [number, number]; @@ -112,7 +113,9 @@ export function findAxisModels(seriesModel: SeriesModel): { } as ReturnType<typeof findAxisModels>; zrUtil.each(axisModelMap, function (v, key) { const axisType = key.replace(/Model$/, ''); - const axisModel = seriesModel.getReferringComponents(axisType, true).models[0] as CartesianAxisModel; + const axisModel = seriesModel.getReferringComponents( + axisType, SINGLE_REFERRING + ).models[0] as CartesianAxisModel; if (__DEV__) { if (!axisModel) { diff --git a/src/coord/geo/Geo.ts b/src/coord/geo/Geo.ts index df84083..c5e0630 100644 --- a/src/coord/geo/Geo.ts +++ b/src/coord/geo/Geo.ts @@ -24,7 +24,7 @@ import geoSourceManager from './geoSourceManager'; import Region from './Region'; import { NameMap } from './geoTypes'; import GlobalModel from '../../model/Global'; -import { ParsedModelFinder } from '../../util/model'; +import { ParsedModelFinder, SINGLE_REFERRING } from '../../util/model'; import GeoModel from './GeoModel'; import { resizeGeoType } from './geoCreator'; @@ -173,7 +173,9 @@ function getCoordSys(finder: ParsedModelFinder): Geo { : seriesModel ? ( seriesModel.coordinateSystem as Geo // For map series. - || ((seriesModel.getReferringComponents('geo', true).models[0] || {}) as GeoModel).coordinateSystem + || ( + (seriesModel.getReferringComponents('geo', SINGLE_REFERRING).models[0] || {} + ) as GeoModel).coordinateSystem ) : null; } diff --git a/src/coord/parallel/parallelCreator.ts b/src/coord/parallel/parallelCreator.ts index b2c9e78..ba747ad 100644 --- a/src/coord/parallel/parallelCreator.ts +++ b/src/coord/parallel/parallelCreator.ts @@ -29,6 +29,7 @@ import ParallelModel from './ParallelModel'; import { CoordinateSystemMaster } from '../CoordinateSystem'; import ParallelSeriesModel from '../../chart/parallel/ParallelSeries'; import CoordinateSystemManager from '../../CoordinateSystem'; +import { SINGLE_REFERRING } from '../../util/model'; function create(ecModel: GlobalModel, api: ExtensionAPI): CoordinateSystemMaster[] { const coordSysList: CoordinateSystemMaster[] = []; @@ -48,11 +49,9 @@ function create(ecModel: GlobalModel, api: ExtensionAPI): CoordinateSystemMaster // Inject the coordinateSystems into seriesModel ecModel.eachSeries(function (seriesModel) { if ((seriesModel as ParallelSeriesModel).get('coordinateSystem') === 'parallel') { - const parallelModel = ecModel.queryComponents({ - mainType: 'parallel', - index: (seriesModel as ParallelSeriesModel).get('parallelIndex'), - id: (seriesModel as ParallelSeriesModel).get('parallelId') - })[0] as ParallelModel; + const parallelModel = seriesModel.getReferringComponents( + 'parallel', SINGLE_REFERRING + ).models[0] as ParallelModel; seriesModel.coordinateSystem = parallelModel.coordinateSystem; } }); diff --git a/src/coord/polar/AxisModel.ts b/src/coord/polar/AxisModel.ts index 84efdd4..d2acf4d 100644 --- a/src/coord/polar/AxisModel.ts +++ b/src/coord/polar/AxisModel.ts @@ -25,6 +25,7 @@ import { AxisBaseOption } from '../axisCommonTypes'; import AngleAxis from './AngleAxis'; import RadiusAxis from './RadiusAxis'; import { AxisBaseModel } from '../AxisBaseModel'; +import { SINGLE_REFERRING } from '../../util/model'; export interface AngleAxisOption extends AxisBaseOption { /** @@ -66,11 +67,7 @@ class PolarAxisModel<T extends PolarAxisOption = PolarAxisOption> extends Compon axis: AngleAxis | RadiusAxis; getCoordSysModel(): ComponentModel { - return this.ecModel.queryComponents({ - mainType: 'polar', - index: this.option.polarIndex, - id: this.option.polarId - })[0]; + return this.getReferringComponents('polar', SINGLE_REFERRING).models[0]; } } diff --git a/src/coord/polar/polarCreator.ts b/src/coord/polar/polarCreator.ts index 04789dd..4c807c3 100644 --- a/src/coord/polar/polarCreator.ts +++ b/src/coord/polar/polarCreator.ts @@ -39,6 +39,7 @@ import AngleAxis from './AngleAxis'; import { PolarAxisModel, AngleAxisModel, RadiusAxisModel } from './AxisModel'; import SeriesModel from '../../model/Series'; import { SeriesOption } from '../../util/types'; +import { SINGLE_REFERRING } from '../../util/model'; /** * Resize method bound to the polar @@ -164,11 +165,9 @@ const polarCreator = { polarId?: string }>) { if (seriesModel.get('coordinateSystem') === 'polar') { - const polarModel = ecModel.queryComponents({ - mainType: 'polar', - index: seriesModel.get('polarIndex'), - id: seriesModel.get('polarId') - })[0] as PolarModel; + const polarModel = seriesModel.getReferringComponents( + 'polar', SINGLE_REFERRING + ).models[0] as PolarModel; if (__DEV__) { if (!polarModel) { diff --git a/src/coord/single/singleCreator.ts b/src/coord/single/singleCreator.ts index 6f58e1f..ba432cf 100644 --- a/src/coord/single/singleCreator.ts +++ b/src/coord/single/singleCreator.ts @@ -28,6 +28,7 @@ import ExtensionAPI from '../../ExtensionAPI'; import SingleAxisModel from './AxisModel'; import SeriesModel from '../../model/Series'; import { SeriesOption } from '../../util/types'; +import { SINGLE_REFERRING } from '../../util/model'; /** * Create single coordinate system and inject it into seriesModel. @@ -50,11 +51,9 @@ function create(ecModel: GlobalModel, api: ExtensionAPI) { singleAxisId?: string }>) { if (seriesModel.get('coordinateSystem') === 'singleAxis') { - const singleAxisModel = ecModel.queryComponents({ - mainType: 'singleAxis', - index: seriesModel.get('singleAxisIndex'), - id: seriesModel.get('singleAxisId') - })[0] as SingleAxisModel; + const singleAxisModel = seriesModel.getReferringComponents( + 'singleAxis', SINGLE_REFERRING + ).models[0] as SingleAxisModel; seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem; } }); diff --git a/src/model/Component.ts b/src/model/Component.ts index f3bfc6d..f03a0e5 100644 --- a/src/model/Component.ts +++ b/src/model/Component.ts @@ -29,7 +29,7 @@ import { ClassManager, mountExtend } from '../util/clazz'; -import {makeInner, ModelFinderIndexQuery, queryReferringComponents, ModelFinderIdQuery} from '../util/model'; +import {makeInner, ModelFinderIndexQuery, queryReferringComponents, ModelFinderIdQuery, QueryReferringOpt} from '../util/model'; import * as layout from '../util/layout'; import GlobalModel from './Global'; import { @@ -276,7 +276,7 @@ class ComponentModel<Opt extends ComponentOption = ComponentOption> extends Mode * If axis index / axis id not specified, use the first target as default. * In other cases like dataZoom refer axis, if not specified, measn no refer. */ - getReferringComponents(mainType: ComponentMainType, useDefault: boolean): { + getReferringComponents(mainType: ComponentMainType, opt: QueryReferringOpt): { // Always be array rather than null/undefined, which is convenient to use. models: ComponentModel[]; // Whether target compoent specified @@ -292,7 +292,7 @@ class ComponentModel<Opt extends ComponentOption = ComponentOption> extends Mode index: this.get(indexKey, true) as unknown as ModelFinderIndexQuery, id: this.get(idKey, true) as unknown as ModelFinderIdQuery }, - useDefault + opt ); } diff --git a/src/model/referHelper.ts b/src/model/referHelper.ts index 0f6d46c..03500f9 100644 --- a/src/model/referHelper.ts +++ b/src/model/referHelper.ts @@ -32,6 +32,7 @@ import SeriesModel from './Series'; import type PolarModel from '../coord/polar/PolarModel'; import type { SeriesOption, SeriesOnCartesianOptionMixin } from '../util/types'; import type { AxisBaseModel } from '../coord/AxisBaseModel'; +import { SINGLE_REFERRING } from '../util/model'; /** * @class @@ -94,8 +95,8 @@ const fetchers: Record<SupportedCoordSys, Fetcher> = { cartesian2d: function ( seriesModel: SeriesModel<SeriesOption & SeriesOnCartesianOptionMixin>, result, axisMap, categoryAxisMap ) { - const xAxisModel = seriesModel.getReferringComponents('xAxis', true).models[0] as AxisBaseModel; - const yAxisModel = seriesModel.getReferringComponents('yAxis', true).models[0] as AxisBaseModel; + const xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0] as AxisBaseModel; + const yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0] as AxisBaseModel; if (__DEV__) { if (!xAxisModel) { @@ -129,7 +130,9 @@ const fetchers: Record<SupportedCoordSys, Fetcher> = { }, singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) { - const singleAxisModel = seriesModel.getReferringComponents('singleAxis', true).models[0] as AxisBaseModel; + const singleAxisModel = seriesModel.getReferringComponents( + 'singleAxis', SINGLE_REFERRING + ).models[0] as AxisBaseModel; if (__DEV__) { if (!singleAxisModel) { @@ -147,7 +150,7 @@ const fetchers: Record<SupportedCoordSys, Fetcher> = { }, polar: function (seriesModel, result, axisMap, categoryAxisMap) { - const polarModel = seriesModel.getReferringComponents('polar', true).models[0] as PolarModel; + const polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0] as PolarModel; const radiusAxisModel = polarModel.findAxisModel('radiusAxis'); const angleAxisModel = polarModel.findAxisModel('angleAxis'); diff --git a/src/util/model.ts b/src/util/model.ts index 8247a49..6225339 100644 --- a/src/util/model.ts +++ b/src/util/model.ts @@ -744,7 +744,7 @@ export function parseFinder( } const defaultMainType = opt ? opt.defaultMainType : null; - const queryOptionMap = createHashMap<QueryReferringComponentsOption, ComponentMainType>(); + const queryOptionMap = createHashMap<QueryReferringOption, ComponentMainType>(); const result = {} as ParsedModelFinder; each(finder, function (value, key) { @@ -756,7 +756,7 @@ export function parseFinder( const parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; const mainType = parsedKey[1]; - const queryType = (parsedKey[2] || '').toLowerCase() as keyof QueryReferringComponentsOption; + const queryType = (parsedKey[2] || '').toLowerCase() as keyof QueryReferringOption; if ( !mainType @@ -776,7 +776,11 @@ export function parseFinder( ecModel, mainType, queryOption, - mainType === defaultMainType + { + useDefault: mainType === defaultMainType, + enableAll: true, + enableNone: true + } ); result[mainType + 'Models'] = queryResult.models; result[mainType + 'Model'] = queryResult.models[0]; @@ -785,26 +789,38 @@ export function parseFinder( return result; } -type QueryReferringComponentsOption = { +type QueryReferringOption = { index?: ModelFinderIndexQuery, id?: ModelFinderIdQuery, name?: ModelFinderNameQuery, }; +export const SINGLE_REFERRING: QueryReferringOpt = { useDefault: true, enableAll: false, enableNone: false }; +export const MULTIPLE_REFERRING: QueryReferringOpt = { useDefault: false, enableAll: true, enableNone: true }; + +export type QueryReferringOpt = { + // Whether to use the first componet as the default if none of index/id/name are specified. + useDefault: boolean; + // Whether to enable `'all'` on index option. + enableAll: boolean; + // Whether to enable `'none'`/`false` on index option. + enableNone: boolean; +}; + export function queryReferringComponents( ecModel: GlobalModel, mainType: ComponentMainType, - option: QueryReferringComponentsOption, - useDefault?: boolean + userOption: QueryReferringOption, + opt: QueryReferringOpt ): { // Always be array rather than null/undefined, which is convenient to use. models: ComponentModel[]; // Whether there is indexOption/id/name specified specified: boolean; } { - let indexOption = option.index; - let idOption = option.id; - let nameOption = option.name; + let indexOption = userOption.index; + let idOption = userOption.id; + let nameOption = userOption.name; const result = { models: null as ComponentModel[], @@ -815,12 +831,13 @@ export function queryReferringComponents( // Use the first as default if `useDefault`. let firstCmpt; result.models = ( - useDefault && (firstCmpt = ecModel.getComponent(mainType)) + opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ) ? [firstCmpt] : []; return result; } if (indexOption === 'none' || indexOption === false) { + assert(opt.enableNone, '`"none"` or `false` is not a valid value on index option.'); result.models = []; return result; } @@ -828,6 +845,7 @@ export function queryReferringComponents( // `queryComponents` will return all components if // both all of index/id/name are null/undefined. if (indexOption === 'all') { + assert(opt.enableAll, '`"all"` is not a valid value on index option.'); indexOption = idOption = nameOption = null; } result.models = ecModel.queryComponents({ diff --git a/test/dataZoom-feature.html b/test/dataZoom-feature.html index 520ce6e..9d42ccc 100644 --- a/test/dataZoom-feature.html +++ b/test/dataZoom-feature.html @@ -93,7 +93,7 @@ under the License. var chart = testHelper.create(echarts, 'refer_by_id', { title: [ 'refer axis by id', - 'Two grids, dataZoom should refer to the second grid', + 'Two grids, dataZoom should **only refer to the bottom grid**', ], option: option, height: 300, diff --git a/test/option-replaceMerge.html b/test/option-replaceMerge.html index 1c8ff5f..0ed8388 100644 --- a/test/option-replaceMerge.html +++ b/test/option-replaceMerge.html @@ -920,72 +920,78 @@ under the License. <script> require(['echarts'], function (echarts) { - var option; + function makePartialOption() { + return { + grid: [{ + bottom: '60%' + }, { + id: 'gb', + top: '60%' + }], + xAxis: [{ + type: 'category' + }, { + type: 'category' + }, { + id: 'xb0', + type: 'category', + gridIndex: 1 + }, { + id: 'xb1', + type: 'category', + gridIndex: 1 + }], + yAxis: [{ - option = { - // toolbox: { - // left: 'center', - // feature: { - // dataZoom: {} - // } - // }, - grid: [{ - bottom: '60%' - }, { - id: 'gb', - top: '60%' - }], - xAxis: [{ - type: 'category' - }, { - type: 'category' - }, { - id: 'xb0', - type: 'category', - gridIndex: 1 - }, { - id: 'xb1', - type: 'category', - gridIndex: 1 - }], - yAxis: [{ + }, { + id: 'yb', + gridIndex: 1 + }], + series: [{ + type: 'line', + data: [[11, 22], [33, 44]] + }, { + type: 'line', + xAxisIndex: 1, + data: [[11111, 52], [21133, 74]] + }, { + id: 'sb0', + type: 'line', + xAxisIndex: 2, + yAxisIndex: 1, + data: [[23, 432], [54, 552]] + }, { + id: 'sb1', + type: 'line', + xAxisIndex: 3, + yAxisIndex: 1, + data: [[222233, 1432], [111154, 1552]] + }] + }; + } - }, { - id: 'yb', - gridIndex: 1 - }], + var option = echarts.util.extend(makePartialOption(), { + toolbox: { + left: 'center', + feature: { + dataZoom: {} + } + }, dataZoom: [{ - type: 'slider' - }, { - type: 'inside' - }], - series: [{ - type: 'line', - data: [[11, 22], [33, 44]] - }, { - type: 'line', - xAxisIndex: 1, - data: [[11111, 52], [21133, 74]] - }, { - id: 'sb0', - type: 'line', - xAxisIndex: 2, - yAxisIndex: 1, - data: [[23, 432], [54, 552]] + type: 'slider', + xAxisIndex: 'all' }, { - id: 'sb1', - type: 'line', - xAxisIndex: 3, - yAxisIndex: 1, - data: [[222233, 1432], [111154, 1552]] + type: 'inside', + xAxisIndex: 'all' }] - }; + }); var chart = testHelper.create(echarts, 'main_replaceMerge_if_not_declared_in_option', { title: [ + 'DataZoom controlls all of the axes.', 'Click btn "remove all grids".', 'Should no error.', - 'Click btn "addback the first grid".', + 'Click btn "addback".', 'Functionalities should be OK.' ], option: option, @@ -997,6 +1003,11 @@ under the License. // Not declared in option }, { replaceMerge: ['grid', 'xAxis', 'yAxis', 'series'] }); } + }, { + text: 'addback', + onclick: function () { + chart.setOption(makePartialOption()); + } }] }); }); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org