You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2021/06/10 14:12:12 UTC
[echarts] branch enhance-morph updated: feat: add universal
transition feature
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch enhance-morph
in repository https://gitbox.apache.org/repos/asf/echarts.git
The following commit(s) were added to refs/heads/enhance-morph by this push:
new 3112145 feat: add universal transition feature
3112145 is described below
commit 311214537e7cafb4b97bfe19483c1ea43602a13a
Author: pissang <bm...@gmail.com>
AuthorDate: Thu Jun 10 22:09:54 2021 +0800
feat: add universal transition feature
---
.gitignore | 2 +
build/pre-publish.js | 4 +-
.../template/features.d.ts | 4 +-
.../template/features.js | 4 +-
src/animation/morphTransitionHelper.ts | 6 +-
src/animation/universalTransition.ts | 85 ++++++++++-
src/chart/custom/CustomView.ts | 3 +-
src/core/echarts.ts | 165 ++++++++++++---------
src/echarts.all.ts | 14 +-
.../universalTransition.ts => export/features.ts} | 4 +-
src/model/Global.ts | 2 +-
src/util/types.ts | 13 +-
test/universalTransition.html | 163 ++++++++++++++++++++
13 files changed, 382 insertions(+), 87 deletions(-)
diff --git a/.gitignore b/.gitignore
index 5787067..ba75419 100644
--- a/.gitignore
+++ b/.gitignore
@@ -203,4 +203,6 @@ todo
/components.d.ts
/renderers.js
/renderers.d.ts
+/features.js
+/features.d.ts
*.tgz
diff --git a/build/pre-publish.js b/build/pre-publish.js
index 0c5e350..cca4b54 100644
--- a/build/pre-publish.js
+++ b/build/pre-publish.js
@@ -345,7 +345,7 @@ async function bundleDTS() {
// Bundle chunks.
const parts = [
- 'core', 'charts', 'components', 'renderers', 'option'
+ 'core', 'charts', 'components', 'renderers', 'option', 'features'
];
const inputs = {};
parts.forEach(partName => {
@@ -387,7 +387,7 @@ function readTSConfig() {
function generateEntries() {
- ['charts', 'components', 'renderers', 'core'].forEach(entryName => {
+ ['charts', 'components', 'renderers', 'core', 'features'].forEach(entryName => {
if (entryName !== 'option') {
const jsCode = fs.readFileSync(nodePath.join(__dirname, `template/${entryName}.js`), 'utf-8');
fs.writeFileSync(nodePath.join(__dirname, `../${entryName}.js`), jsCode, 'utf-8');
diff --git a/src/animation/universalTransition.ts b/build/template/features.d.ts
similarity index 88%
copy from src/animation/universalTransition.ts
copy to build/template/features.d.ts
index af2cfa0..0e9a6fc 100644
--- a/src/animation/universalTransition.ts
+++ b/build/template/features.d.ts
@@ -17,6 +17,4 @@
* under the License.
*/
-// Universal transitions that can animate between any shapes and any properties in any amounts.
-
-
+export * from './types/dist/features';
\ No newline at end of file
diff --git a/src/animation/universalTransition.ts b/build/template/features.js
similarity index 88%
copy from src/animation/universalTransition.ts
copy to build/template/features.js
index af2cfa0..862d600 100644
--- a/src/animation/universalTransition.ts
+++ b/build/template/features.js
@@ -17,6 +17,4 @@
* under the License.
*/
-// Universal transitions that can animate between any shapes and any properties in any amounts.
-
-
+export * from './lib/export/features';
\ No newline at end of file
diff --git a/src/animation/morphTransitionHelper.ts b/src/animation/morphTransitionHelper.ts
index 50e057b..a0993b7 100644
--- a/src/animation/morphTransitionHelper.ts
+++ b/src/animation/morphTransitionHelper.ts
@@ -93,7 +93,7 @@ export function applyMorphAnimation(
to: DescendentPaths | DescendentPaths[],
seriesModel: SeriesModel,
dataIndex: number,
- updateOtherProps: (fromIndividual: Path, toIndividual: Path, rawFrom: Path, rawTo: Path) => void
+ animateOtherProps: (fromIndividual: Path, toIndividual: Path, rawFrom: Path, rawTo: Path) => void
) {
if (!from.length || !to.length) {
return;
@@ -136,7 +136,7 @@ export function applyMorphAnimation(
}
else {
morphPath(batchFrom, batchTo, animationCfg);
- updateOtherProps(batchFrom, batchTo, batchFrom, batchTo);
+ animateOtherProps(batchFrom, batchTo, batchFrom, batchTo);
}
}
else {
@@ -148,7 +148,7 @@ export function applyMorphAnimation(
: separateMorph(batchOne, batchMany, animationCfgWithSplitPath);
for (let k = 0; k < fromIndividuals.length; k++) {
- updateOtherProps(
+ animateOtherProps(
fromIndividuals[k],
toIndividuals[k],
fromIsMany ? batchMany[k] : batch.one,
diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts
index af2cfa0..6d96f4e 100644
--- a/src/animation/universalTransition.ts
+++ b/src/animation/universalTransition.ts
@@ -17,6 +17,89 @@
* under the License.
*/
-// Universal transitions that can animate between any shapes and any properties in any amounts.
+import ExtensionAPI from '../core/ExtensionAPI';
+import SeriesModel from '../model/Series';
+import {createHashMap, each, filter} from 'zrender/src/core/util';
+import Element from 'zrender/src/Element';
+import { applyMorphAnimation, getPathList } from './morphTransitionHelper';
+import { getECData } from '../util/innerStore';
+import Path from 'zrender/src/graphic/Path';
+import { EChartsExtensionInstallRegisters } from '../extension';
+// Universal transitions that can animate between any shapes(series) and any properties in any amounts.
+export function transitionBetweenSeries(
+ oldSeriesModel: SeriesModel,
+ newSeriesModel: SeriesModel,
+ api: ExtensionAPI
+) {
+ const oldData = oldSeriesModel.getData();
+ const newData = newSeriesModel.getData();
+
+ // No data or data are in the same series.
+ if (!oldData || !newData || oldData === newData) {
+ return;
+ }
+
+ let sourceElements = oldData.mapArray(idx => {
+ return oldData.getItemGraphicEl(idx);
+ });
+
+ let targetElements = newData.mapArray(idx => {
+ return newData.getItemGraphicEl(idx);
+ });
+
+ // Align the two arrays.
+ function alignNullElements(arr1: unknown[], arr2: unknown[]) {
+ for (let i = 0; i < arr1.length; i++) {
+ if (!arr2[i]) {
+ arr1[i] = null;
+ }
+ }
+ }
+ alignNullElements(sourceElements, targetElements);
+ alignNullElements(targetElements, sourceElements);
+
+ sourceElements = filter(sourceElements, el => !!el);
+ targetElements = filter(targetElements, el => !!el);
+
+ function updateMorphingPathProps(
+ from: Path, to: Path,
+ rawFrom: Path, rawTo: Path
+ ) {
+ // TODO
+ }
+
+ for (let i = 0; i < sourceElements.length; i++) {
+ const dataIndex = getECData(targetElements[i]).dataIndex;
+ sourceElements[i].traverse(el => el.stopAnimation());
+ targetElements[i].traverse(el => el.stopAnimation());
+ applyMorphAnimation(
+ getPathList(sourceElements[i]),
+ getPathList(targetElements[i]),
+ newSeriesModel,
+ dataIndex,
+ updateMorphingPathProps
+ );
+ }
+}
+
+export function installUniversalTransition(registers: EChartsExtensionInstallRegisters) {
+ registers.registerPostUpdate((ecModel, api, params) => {
+ if (params.oldSeries && params.newSeries) {
+ const oldSeriesMap = createHashMap<SeriesModel>();
+ each(params.oldSeries, series => {
+ oldSeriesMap.set(series.id, series);
+ });
+ each(params.newSeries, series => {
+ if (series.get(['universalAnimation', 'enabled'])) {
+ // Only transition between series with same id.
+ const oldSeries = oldSeriesMap.get(series.id);
+ if (oldSeries) {
+ transitionBetweenSeries(oldSeries, series, api);
+ }
+ }
+ });
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/chart/custom/CustomView.ts b/src/chart/custom/CustomView.ts
index 335e8b0..31372f4 100644
--- a/src/chart/custom/CustomView.ts
+++ b/src/chart/custom/CustomView.ts
@@ -212,7 +212,8 @@ export default class CustomChartView extends ChartView {
function updateMorphingPathProps(
dataIndex: number,
- from: graphicUtil.Path, to: graphicUtil.Path, rawFrom: graphicUtil.Path, rawTo: graphicUtil.Path
+ from: graphicUtil.Path, to: graphicUtil.Path,
+ rawFrom: graphicUtil.Path, rawTo: graphicUtil.Path
) {
// element has been updated if rawTo is same with to.
const elOption = customInnerStore(rawTo).option;
diff --git a/src/core/echarts.ts b/src/core/echarts.ts
index beb395d..92eed07 100644
--- a/src/core/echarts.ts
+++ b/src/core/echarts.ts
@@ -17,7 +17,26 @@
* under the License.
*/
import * as zrender from 'zrender/src/zrender';
-import * as zrUtil from 'zrender/src/core/util';
+import {
+ assert,
+ each,
+ isFunction,
+ isObject,
+ indexOf,
+ bind,
+ clone,
+ setAsPrimitive,
+ createCanvas,
+ extend,
+ HashMap,
+ createHashMap,
+ map,
+ defaults,
+ isDom,
+ isArray,
+ $override,
+ noop
+} from 'zrender/src/core/util';
import * as colorTool from 'zrender/src/tool/color';
import env from 'zrender/src/core/env';
import timsort from 'zrender/src/core/timsort';
@@ -90,7 +109,8 @@ import {
ScaleDataValue,
ZRElementEventName,
ECElementEvent,
- AnimationOption
+ AnimationOption,
+ PostUpdateParams
} from '../util/types';
import Displayable from 'zrender/src/graphic/Displayable';
import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';
@@ -114,12 +134,6 @@ declare let global: any;
type ModelFinder = modelUtil.ModelFinder;
-const assert = zrUtil.assert;
-const each = zrUtil.each;
-const isFunction = zrUtil.isFunction;
-const isObject = zrUtil.isObject;
-const indexOf = zrUtil.indexOf;
-
const hasWindow = typeof window !== 'undefined';
export const version = '5.1.1';
@@ -182,7 +196,7 @@ export const PRIORITY = {
// This flag is used to carry out this rule.
// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
const IN_MAIN_PROCESS_KEY = '__flagInMainProcess' as const;
-const OPTION_UPDATED_KEY = '__optionUpdated' as const;
+const PENDING_UPDATE = '__pendingUpdate' as const;
const STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus' as const;
const ACTION_REG = /^[a-zA-Z0-9_]+$/;
@@ -264,10 +278,10 @@ let prepareView: (ecIns: ECharts, isComponent: boolean) => void;
let updateDirectly: (
ecIns: ECharts, method: string, payload: Payload, mainType: ComponentMainType, subType?: ComponentSubType
) => void;
-type UpdateMethod = (this: ECharts, payload?: Payload) => void;
+type UpdateMethod = (this: ECharts, payload?: Payload, postUpdateParams?: PostUpdateParams) => void;
let updateMethods: {
prepareAndUpdate: UpdateMethod,
- update: UpdateMethod,
+ update: (this: ECharts, payload: Payload, postUpdateParams: PostUpdateParams) => void,
updateTransform: UpdateMethod,
updateView: UpdateMethod,
updateVisual: UpdateMethod,
@@ -297,7 +311,7 @@ let renderSeries: (
payload: Payload | 'remain',
dirtyMap?: {[uid: string]: any}
) => void;
-let performPostUpdateFuncs: (ecModel: GlobalModel, api: ExtensionAPI) => void;
+let performPostUpdateFuncs: (ecModel: GlobalModel, api: ExtensionAPI, params: PostUpdateParams) => void;
let createExtensionAPI: (ecIns: ECharts) => ExtensionAPI;
let enableConnect: (ecIns: ECharts) => void;
let setTransitionOpt: (
@@ -372,7 +386,10 @@ class ECharts extends Eventful<ECEventDefinition> {
private _labelManager: LabelManager;
- private [OPTION_UPDATED_KEY]: boolean | {silent: boolean};
+ private [PENDING_UPDATE]: {
+ silent: boolean
+ postUpdateParams: PostUpdateParams
+ };
private [IN_MAIN_PROCESS_KEY]: boolean;
private [CONNECT_STATUS_KEY]: ConnectStatus;
private [STATUS_NEEDS_UPDATE_KEY]: boolean;
@@ -426,9 +443,9 @@ class ECharts extends Eventful<ECEventDefinition> {
});
// Expect 60 fps.
- this._throttledZrFlush = throttle(zrUtil.bind(zr.flush, zr), 17);
+ this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);
- theme = zrUtil.clone(theme);
+ theme = clone(theme);
theme && backwardCompat(theme as ECUnitOption, true);
this._theme = theme;
@@ -456,7 +473,7 @@ class ECharts extends Eventful<ECEventDefinition> {
this._initEvents();
// In case some people write `window.onresize = chart.resize`
- this.resize = zrUtil.bind(this.resize, this);
+ this.resize = bind(this.resize, this);
zr.animation.on('frame', this._onframe, this);
@@ -465,7 +482,7 @@ class ECharts extends Eventful<ECEventDefinition> {
bindMouseEvent(zr, this);
// ECharts instance can be used as value.
- zrUtil.setAsPrimitive(this);
+ setAsPrimitive(this);
}
private _onframe(): void {
@@ -478,13 +495,13 @@ class ECharts extends Eventful<ECEventDefinition> {
const scheduler = this._scheduler;
// Lazy update
- if (this[OPTION_UPDATED_KEY]) {
- const silent = (this[OPTION_UPDATED_KEY] as any).silent;
+ if (this[PENDING_UPDATE]) {
+ const silent = (this[PENDING_UPDATE] as any).silent;
this[IN_MAIN_PROCESS_KEY] = true;
prepare(this);
- updateMethods.update.call(this);
+ updateMethods.update.call(this, null, this[PENDING_UPDATE].postUpdateParams);
// At present, in each frame, zrender performs:
// (1) animation step forward.
@@ -496,7 +513,7 @@ class ECharts extends Eventful<ECEventDefinition> {
this[IN_MAIN_PROCESS_KEY] = false;
- this[OPTION_UPDATED_KEY] = false;
+ this[PENDING_UPDATE] = null;
flushPendingActions.call(this, silent);
@@ -596,6 +613,8 @@ class ECharts extends Eventful<ECEventDefinition> {
this[IN_MAIN_PROCESS_KEY] = true;
+ // Try getting from old model if notMerge is enabled.
+ let oldSeriesModels = this._model && this._model.getSeries();
if (!this._model || notMerge) {
const optionManager = new OptionManager(this._api);
const theme = this._theme;
@@ -603,13 +622,25 @@ class ECharts extends Eventful<ECEventDefinition> {
ecModel.scheduler = this._scheduler;
ecModel.init(null, null, null, theme, this._locale, optionManager);
}
+ else {
+ oldSeriesModels = this._model.getSeries();
+ }
this._model.setOption(option as ECBasicOption, { replaceMerge }, optionPreprocessorFuncs);
+ const newSeriesModels = this._model.getSeries();
+
+ const postUpdateParams = {
+ oldSeries: oldSeriesModels,
+ newSeries: newSeriesModels
+ };
setTransitionOpt(this, transitionOpt);
if (lazyUpdate) {
- this[OPTION_UPDATED_KEY] = {silent: silent};
+ this[PENDING_UPDATE] = {
+ silent: silent,
+ postUpdateParams
+ };
this[IN_MAIN_PROCESS_KEY] = false;
// `setOption(option, {lazyMode: true})` may be called when zrender has been slept.
@@ -619,13 +650,13 @@ class ECharts extends Eventful<ECEventDefinition> {
else {
prepare(this);
- updateMethods.update.call(this);
+ updateMethods.update.call(this, null, postUpdateParams);
// Ensure zr refresh sychronously, and then pixel in canvas can be
// fetched after `setOption`.
this._zr.flush();
- this[OPTION_UPDATED_KEY] = false;
+ this[PENDING_UPDATE] = null;
this[IN_MAIN_PROCESS_KEY] = false;
flushPendingActions.call(this, silent);
@@ -691,7 +722,7 @@ class ECharts extends Eventful<ECEventDefinition> {
const zr = this._zr;
const list = zr.storage.getDisplayList();
// Stop animations
- zrUtil.each(list, function (el: Element) {
+ each(list, function (el: Element) {
el.stopAnimation(null, true);
});
@@ -771,11 +802,11 @@ class ECharts extends Eventful<ECEventDefinition> {
const canvasList: {dom: HTMLCanvasElement | string, left: number, top: number}[] = [];
const dpr = (opts && opts.pixelRatio) || this.getDevicePixelRatio();
- zrUtil.each(instances, function (chart, id) {
+ each(instances, function (chart, id) {
if (chart.group === groupId) {
const canvas = isSvg
? (chart.getZr().painter as SVGPainter).getSvgDom().innerHTML
- : chart.getRenderedCanvas(zrUtil.clone(opts));
+ : chart.getRenderedCanvas(clone(opts));
const boundingRect = chart.getDom().getBoundingClientRect();
left = mathMin(boundingRect.left, left);
top = mathMin(boundingRect.top, top);
@@ -795,7 +826,7 @@ class ECharts extends Eventful<ECEventDefinition> {
bottom *= dpr;
const width = right - left;
const height = bottom - top;
- const targetCanvas = zrUtil.createCanvas();
+ const targetCanvas = createCanvas();
const zr = zrender.init(targetCanvas, {
renderer: isSvg ? 'svg' : 'canvas'
});
@@ -893,8 +924,8 @@ class ECharts extends Eventful<ECEventDefinition> {
const findResult = modelUtil.parseFinder(ecModel, finder);
- zrUtil.each(findResult, function (models, key) {
- key.indexOf('Models') >= 0 && zrUtil.each(models as ComponentModel[], function (model) {
+ each(findResult, function (models, key) {
+ key.indexOf('Models') >= 0 && each(models as ComponentModel[], function (model) {
const coordSys = (model as CoordinateSystemHostModel).coordinateSystem;
if (coordSys && coordSys.containPoint) {
result = result || !!coordSys.containPoint(value);
@@ -1005,7 +1036,7 @@ class ECharts extends Eventful<ECEventDefinition> {
}
// If element has custom eventData of components
else if (ecData.eventData) {
- params = zrUtil.extend({}, ecData.eventData) as ECElementEvent;
+ params = extend({}, ecData.eventData) as ECElementEvent;
return true;
}
}, true);
@@ -1158,12 +1189,12 @@ class ECharts extends Eventful<ECEventDefinition> {
// There is some real cases that:
// chart.setOption(option, { lazyUpdate: true });
// chart.resize();
- if (this[OPTION_UPDATED_KEY]) {
+ if (this[PENDING_UPDATE]) {
if (silent == null) {
- silent = (this[OPTION_UPDATED_KEY] as any).silent;
+ silent = (this[PENDING_UPDATE] as any).silent;
}
needPrepare = true;
- this[OPTION_UPDATED_KEY] = false;
+ this[PENDING_UPDATE] = null;
}
this[IN_MAIN_PROCESS_KEY] = true;
@@ -1172,11 +1203,11 @@ class ECharts extends Eventful<ECEventDefinition> {
updateMethods.update.call(this, {
type: 'resize',
- animation: zrUtil.extend({
+ animation: extend({
// Disable animation
duration: 0
}, opts && opts.animation)
- });
+ }, {});
this[IN_MAIN_PROCESS_KEY] = false;
@@ -1232,7 +1263,7 @@ class ECharts extends Eventful<ECEventDefinition> {
}
makeActionFromEvent(eventObj: ECActionEvent): Payload {
- const payload = zrUtil.extend({}, eventObj) as Payload;
+ const payload = extend({}, eventObj) as Payload;
payload.type = eventActionMap[eventObj.type];
return payload;
}
@@ -1471,9 +1502,9 @@ class ECharts extends Eventful<ECEventDefinition> {
subType && (condition.subType = subType); // subType may be '' by parseClassType;
const excludeSeriesId = payload.excludeSeriesId;
- let excludeSeriesIdMap: zrUtil.HashMap<true, string>;
+ let excludeSeriesIdMap: HashMap<true, string>;
if (excludeSeriesId != null) {
- excludeSeriesIdMap = zrUtil.createHashMap();
+ excludeSeriesIdMap = createHashMap();
each(modelUtil.normalizeToArray(excludeSeriesId), id => {
const modelId = modelUtil.convertOptionIdName(id, null);
if (modelId != null) {
@@ -1541,12 +1572,10 @@ class ECharts extends Eventful<ECEventDefinition> {
prepareAndUpdate(this: ECharts, payload: Payload): void {
prepare(this);
- updateMethods.update.call(this, payload);
+ updateMethods.update.call(this, payload, {});
},
- update(this: ECharts, payload: Payload): void {
- // console.profile && console.profile('update');
-
+ update(this: ECharts, payload: Payload, postUpdateParams: PostUpdateParams): void {
const ecModel = this._model;
const api = this._api;
const zr = this._zr;
@@ -1611,9 +1640,7 @@ class ECharts extends Eventful<ECEventDefinition> {
}
}
- performPostUpdateFuncs(ecModel, api);
-
- // console.profile && console.profileEnd('update');
+ performPostUpdateFuncs(ecModel, api, postUpdateParams);
},
updateTransform(this: ECharts, payload: Payload): void {
@@ -1647,7 +1674,7 @@ class ECharts extends Eventful<ECEventDefinition> {
}
});
- const seriesDirtyMap = zrUtil.createHashMap();
+ const seriesDirtyMap = createHashMap();
ecModel.eachSeries((seriesModel) => {
const chartView = this._chartsMap[seriesModel.__viewId];
if (chartView.updateTransform) {
@@ -1670,7 +1697,7 @@ class ECharts extends Eventful<ECEventDefinition> {
// renderComponents(ecIns, ecModel, api, payload, componentDirtyList);
renderSeries(this, ecModel, api, payload, seriesDirtyMap);
- performPostUpdateFuncs(ecModel, this._api);
+ performPostUpdateFuncs(ecModel, this._api, {});
},
updateView(this: ECharts, payload: Payload): void {
@@ -1692,7 +1719,7 @@ class ECharts extends Eventful<ECEventDefinition> {
render(this, this._model, this._api, payload);
- performPostUpdateFuncs(ecModel, this._api);
+ performPostUpdateFuncs(ecModel, this._api, {});
},
updateVisual(this: ECharts, payload: Payload): void {
@@ -1733,11 +1760,11 @@ class ECharts extends Eventful<ECEventDefinition> {
chartView.updateVisual(seriesModel, ecModel, this._api, payload);
});
- performPostUpdateFuncs(ecModel, this._api);
+ performPostUpdateFuncs(ecModel, this._api, {});
},
updateLayout(this: ECharts, payload: Payload): void {
- updateMethods.update.call(this, payload);
+ updateMethods.update.call(this, payload, {});
}
};
@@ -1799,8 +1826,8 @@ class ECharts extends Eventful<ECEventDefinition> {
// Batch action
if (payload.batch) {
batched = true;
- payloads = zrUtil.map<Payload['batch'][0], Payload, unknown>(payload.batch, function (item) {
- item = zrUtil.defaults(zrUtil.extend({}, item), payload);
+ payloads = map<Payload['batch'][0], Payload, unknown>(payload.batch, function (item) {
+ item = defaults(extend({}, item), payload);
item.batch = null;
return item as Payload;
});
@@ -1816,7 +1843,7 @@ class ECharts extends Eventful<ECEventDefinition> {
// Action can specify the event by return it.
eventObj = actionWrap.action(batchItem, this._model, this._api) as ECActionEvent;
// Emit event outside
- eventObj = eventObj || zrUtil.extend({} as ECActionEvent, batchItem);
+ eventObj = eventObj || extend({} as ECActionEvent, batchItem);
// Convert type to eventType
eventObj.type = actionInfo.event || eventObj.type;
eventObjBatch.push(eventObj);
@@ -1841,10 +1868,10 @@ class ECharts extends Eventful<ECEventDefinition> {
if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) {
// Still dirty
- if (this[OPTION_UPDATED_KEY]) {
+ if (this[PENDING_UPDATE]) {
prepare(this);
- updateMethods.update.call(this, payload);
- this[OPTION_UPDATED_KEY] = false;
+ updateMethods.update.call(this, payload, {});
+ this[PENDING_UPDATE] = null;
}
else {
updateMethods[updateMethod as keyof typeof updateMethods].call(this, payload);
@@ -1921,7 +1948,7 @@ class ECharts extends Eventful<ECEventDefinition> {
// and this checking is called on frame, we also check
// animation finished for robustness.
zr.animation.isFinished()
- && !ecIns[OPTION_UPDATED_KEY]
+ && !ecIns[PENDING_UPDATE]
&& !ecIns._scheduler.unfinished
&& !ecIns._pendingActions.length
) {
@@ -2075,9 +2102,9 @@ class ECharts extends Eventful<ECEventDefinition> {
updateHoverLayerStatus(ecIns, ecModel);
};
- performPostUpdateFuncs = function (ecModel: GlobalModel, api: ExtensionAPI): void {
+ performPostUpdateFuncs = function (ecModel: GlobalModel, api: ExtensionAPI, params: PostUpdateParams): void {
each(postUpdateFuncs, function (func) {
- func(ecModel, api);
+ func(ecModel, api, params);
});
};
@@ -2411,7 +2438,7 @@ class ECharts extends Eventful<ECEventDefinition> {
): void {
const ecModel = chart._model;
- zrUtil.each(modelUtil.normalizeToArray(transitionOpt), transOpt => {
+ each(modelUtil.normalizeToArray(transitionOpt), transOpt => {
let errMsg;
const fromOpt = transOpt.from;
const toOpt = transOpt.to;
@@ -2583,7 +2610,7 @@ export function init(
}
if (__DEV__) {
- if (zrUtil.isDom(dom)
+ if (isDom(dom)
&& dom.nodeName.toUpperCase() !== 'CANVAS'
&& (
(!dom.clientWidth && (!opts || opts.width == null))
@@ -2631,7 +2658,7 @@ export function init(
*/
export function connect(groupId: string | EChartsType[]): string {
// Is array of charts
- if (zrUtil.isArray(groupId)) {
+ if (isArray(groupId)) {
const charts = groupId;
groupId = null;
// If any chart has group
@@ -2891,7 +2918,7 @@ export function registerLoading(
* });
*/
export function setCanvasCreator(creator: () => HTMLCanvasElement): void {
- zrUtil.$override('createCanvas', creator);
+ $override('createCanvas', creator);
}
/**
@@ -2948,31 +2975,31 @@ registerAction({
type: HIGHLIGHT_ACTION_TYPE,
event: HIGHLIGHT_ACTION_TYPE,
update: HIGHLIGHT_ACTION_TYPE
-}, zrUtil.noop);
+}, noop);
registerAction({
type: DOWNPLAY_ACTION_TYPE,
event: DOWNPLAY_ACTION_TYPE,
update: DOWNPLAY_ACTION_TYPE
-}, zrUtil.noop);
+}, noop);
registerAction({
type: SELECT_ACTION_TYPE,
event: SELECT_ACTION_TYPE,
update: SELECT_ACTION_TYPE
-}, zrUtil.noop);
+}, noop);
registerAction({
type: UNSELECT_ACTION_TYPE,
event: UNSELECT_ACTION_TYPE,
update: UNSELECT_ACTION_TYPE
-}, zrUtil.noop);
+}, noop);
registerAction({
type: TOGGLE_SELECT_ACTION_TYPE,
event: TOGGLE_SELECT_ACTION_TYPE,
update: TOGGLE_SELECT_ACTION_TYPE
-}, zrUtil.noop);
+}, noop);
// Default theme
registerTheme('light', lightTheme);
diff --git a/src/echarts.all.ts b/src/echarts.all.ts
index e66f8b9..95ab6d7 100644
--- a/src/echarts.all.ts
+++ b/src/echarts.all.ts
@@ -87,6 +87,10 @@ import {
TransformComponent
} from './export/components';
+import {
+ UniversalTransition
+} from './export/features';
+
// -----------------
// Render engines
@@ -332,4 +336,12 @@ use(AriaComponent);
// });
use(TransformComponent);
-use(DatasetComponent);
\ No newline at end of file
+use(DatasetComponent);
+
+// universal transition
+// chart.setOption({
+// series: {
+// universalAnimation: { enabled: true }
+// }
+// })
+use(UniversalTransition);
\ No newline at end of file
diff --git a/src/animation/universalTransition.ts b/src/export/features.ts
similarity index 84%
copy from src/animation/universalTransition.ts
copy to src/export/features.ts
index af2cfa0..b9b3c45 100644
--- a/src/animation/universalTransition.ts
+++ b/src/export/features.ts
@@ -17,6 +17,6 @@
* under the License.
*/
-// Universal transitions that can animate between any shapes and any properties in any amounts.
-
+// Module that exports complex but fancy features.
+export {installUniversalTransition as UniversalTransition} from '../animation/universalTransition';
\ No newline at end of file
diff --git a/src/model/Global.ts b/src/model/Global.ts
index 0a06d5b..32582b0 100644
--- a/src/model/Global.ts
+++ b/src/model/Global.ts
@@ -758,7 +758,7 @@ echarts.use([${seriesImportName}]);`);
*/
getSeries(): SeriesModel[] {
return filter(
- this._componentsMap.get('series').slice() as SeriesModel[],
+ this._componentsMap.get('series') as SeriesModel[],
oneSeries => !!oneSeries
);
}
diff --git a/src/util/types.ts b/src/util/types.ts
index 1d11e52..6dd0e3a 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -233,8 +233,12 @@ export interface OptionPreprocessor {
(option: ECUnitOption, isTheme: boolean): void
}
+export interface PostUpdateParams {
+ oldSeries?: SeriesModel[]
+ newSeries?: SeriesModel[]
+}
export interface PostUpdater {
- (ecModel: GlobalModel, api: ExtensionAPI): void;
+ (ecModel: GlobalModel, api: ExtensionAPI, params: PostUpdateParams): void;
}
export interface StageHandlerReset {
@@ -1594,6 +1598,13 @@ export interface SeriesOption<
stateAnimation?: AnimationOption
/**
+ * If enabled universal animation cross series.
+ */
+ universalAnimation?: {
+ enabled: boolean
+ }
+
+ /**
* Map of selected data
* key is name or index of data.
*/
diff --git a/test/universalTransition.html b/test/universalTransition.html
new file mode 100644
index 0000000..00386e6
--- /dev/null
+++ b/test/universalTransition.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <script src="lib/simpleRequire.js"></script>
+ <script src="lib/config.js"></script>
+ <script src="lib/jquery.min.js"></script>
+ <script src="lib/facePrint.js"></script>
+ <script src="lib/testHelper.js"></script>
+ <!-- <script src="ut/lib/canteen.js"></script> -->
+ <link rel="stylesheet" href="lib/reset.css" />
+ </head>
+ <body>
+ <style>
+ </style>
+
+
+
+ <div id="main0"></div>
+
+
+
+
+
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+ var option;
+
+ option = {
+ title: {
+ text: 'Bar'
+ },
+ dataset: [{
+ dimensions: ['name', 'age', 'profession', 'score', 'date'],
+ source: [
+ ['Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+ ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+ ['Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+ ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+ ['Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+ ['Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+ ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+ ['Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+ ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12'],
+ ]
+ }, {
+ transform: {
+ type: 'sort',
+ config: { dimension: 'score', order: 'desc' }
+ }
+ }],
+ xAxis: {
+ type: 'category',
+ axisLabel: { interval: 0, rotate: 30 },
+ },
+ yAxis: {},
+ series: {
+ type: 'bar',
+ id: 'main',
+ encode: { x: 'name', y: 'score', itemName: 'name' },
+ datasetIndex: 1
+ }
+ };
+
+ var chart = testHelper.create(echarts, 'main0', {
+ title: [
+ 'Convert between pie, bar, scatter, line'
+ ],
+ // height: 300,
+ buttons: [{
+ text: 'Pie',
+ onclick: function () {
+ chart.setOption({
+ title: {
+ text: 'Bar'
+ },
+ dataset: [{
+ dimensions: ['name', 'age', 'profession', 'score', 'date'],
+ source: [
+ ['Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
+ ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
+ ['Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
+ ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
+ ['Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
+ ['Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
+ ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
+ ['Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
+ ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12'],
+ ]
+ }, {
+ transform: {
+ type: 'sort',
+ config: { dimension: 'score', order: 'desc' }
+ }
+ }],
+ series: {
+ id: 'main',
+ type: 'pie',
+ encode: { x: 'name', y: 'score', itemName: 'name' },
+ datasetIndex: 1,
+ universalAnimation: {
+ enabled: true
+ }
+ }
+ }, true);
+ }
+ }, {
+ text: 'Scatter',
+ onclick: function () {
+ chart.setOption({
+ title: { text: 'Scatter' },
+ xAxis: {
+ show: true
+ },
+ yAxis: {
+ show: true
+ },
+ series: {
+ id: 'main',
+ type: 'scatter',
+ symbolSize: 30,
+ encode: { x: 'name', y: 'score', itemName: 'name' },
+ datasetIndex: 1,
+ universalAnimation: {
+ enabled: true
+ }
+ }
+ }, true);
+ }
+ }],
+ option: option
+ });
+ });
+ </script>
+
+
+ </body>
+</html>
+
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org