123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- /*
- * 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.
- */
- /**
- * AUTO-GENERATED FILE. DO NOT MODIFY.
- */
- /*
- * 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.
- */
- // Universal transitions that can animate between any shapes(series) and any properties in any amounts.
- import { SERIES_UNIVERSAL_TRANSITION_PROP } from '../model/Series.js';
- import { createHashMap, each, map, filter, isArray, extend } from 'zrender/lib/core/util.js';
- import { applyMorphAnimation, getPathList } from './morphTransitionHelper.js';
- import Path from 'zrender/lib/graphic/Path.js';
- import { initProps } from '../util/graphic.js';
- import DataDiffer from '../data/DataDiffer.js';
- import { makeInner, normalizeToArray } from '../util/model.js';
- import { warn } from '../util/log.js';
- import { getAnimationConfig, getOldStyle } from './basicTransition.js';
- import Displayable from 'zrender/lib/graphic/Displayable.js';
- var DATA_COUNT_THRESHOLD = 1e4;
- ;
- var getUniversalTransitionGlobalStore = makeInner();
- function getGroupIdDimension(data) {
- var dimensions = data.dimensions;
- for (var i = 0; i < dimensions.length; i++) {
- var dimInfo = data.getDimensionInfo(dimensions[i]);
- if (dimInfo && dimInfo.otherDims.itemGroupId === 0) {
- return dimensions[i];
- }
- }
- }
- function flattenDataDiffItems(list) {
- var items = [];
- each(list, function (seriesInfo) {
- var data = seriesInfo.data;
- if (data.count() > DATA_COUNT_THRESHOLD) {
- if (process.env.NODE_ENV !== 'production') {
- warn('Universal transition is disabled on large data > 10k.');
- }
- return;
- }
- var indices = data.getIndices();
- var groupDim = getGroupIdDimension(data);
- for (var dataIndex = 0; dataIndex < indices.length; dataIndex++) {
- items.push({
- dataGroupId: seriesInfo.dataGroupId,
- data: data,
- dim: seriesInfo.dim || groupDim,
- divide: seriesInfo.divide,
- dataIndex: dataIndex
- });
- }
- });
- return items;
- }
- function fadeInElement(newEl, newSeries, newIndex) {
- newEl.traverse(function (el) {
- if (el instanceof Path) {
- // TODO use fade in animation for target element.
- initProps(el, {
- style: {
- opacity: 0
- }
- }, newSeries, {
- dataIndex: newIndex,
- isFrom: true
- });
- }
- });
- }
- function removeEl(el) {
- if (el.parent) {
- // Bake parent transform to element.
- // So it can still have proper transform to transition after it's removed.
- var computedTransform = el.getComputedTransform();
- el.setLocalTransform(computedTransform);
- el.parent.remove(el);
- }
- }
- function stopAnimation(el) {
- el.stopAnimation();
- if (el.isGroup) {
- el.traverse(function (child) {
- child.stopAnimation();
- });
- }
- }
- function animateElementStyles(el, dataIndex, seriesModel) {
- var animationConfig = getAnimationConfig('update', seriesModel, dataIndex);
- animationConfig && el.traverse(function (child) {
- if (child instanceof Displayable) {
- var oldStyle = getOldStyle(child);
- if (oldStyle) {
- child.animateFrom({
- style: oldStyle
- }, animationConfig);
- }
- }
- });
- }
- function isAllIdSame(oldDiffItems, newDiffItems) {
- var len = oldDiffItems.length;
- if (len !== newDiffItems.length) {
- return false;
- }
- for (var i = 0; i < len; i++) {
- var oldItem = oldDiffItems[i];
- var newItem = newDiffItems[i];
- if (oldItem.data.getId(oldItem.dataIndex) !== newItem.data.getId(newItem.dataIndex)) {
- return false;
- }
- }
- return true;
- }
- function transitionBetween(oldList, newList, api) {
- var oldDiffItems = flattenDataDiffItems(oldList);
- var newDiffItems = flattenDataDiffItems(newList);
- function updateMorphingPathProps(from, to, rawFrom, rawTo, animationCfg) {
- if (rawFrom || from) {
- to.animateFrom({
- style: rawFrom && rawFrom !== from ? // dividingMethod like clone may override the style(opacity)
- // So extend it to raw style.
- extend(extend({}, rawFrom.style), from.style) : from.style
- }, animationCfg);
- }
- }
- function findKeyDim(items) {
- for (var i = 0; i < items.length; i++) {
- if (items[i].dim) {
- return items[i].dim;
- }
- }
- }
- var oldKeyDim = findKeyDim(oldDiffItems);
- var newKeyDim = findKeyDim(newDiffItems);
- var hasMorphAnimation = false;
- function createKeyGetter(isOld, onlyGetId) {
- return function (diffItem) {
- var data = diffItem.data;
- var dataIndex = diffItem.dataIndex; // TODO if specified dim
- if (onlyGetId) {
- return data.getId(dataIndex);
- } // Use group id as transition key by default.
- // So we can achieve multiple to multiple animation like drilldown / up naturally.
- // If group id not exits. Use id instead. If so, only one to one transition will be applied.
- var dataGroupId = diffItem.dataGroupId; // If specified key dimension(itemGroupId by default). Use this same dimension from other data.
- // PENDING: If only use key dimension of newData.
- var keyDim = isOld ? oldKeyDim || newKeyDim : newKeyDim || oldKeyDim;
- var dimInfo = keyDim && data.getDimensionInfo(keyDim);
- var dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta;
- if (dimInfo) {
- // Get from encode.itemGroupId.
- var key = data.get(dimInfo.name, dataIndex);
- if (dimOrdinalMeta) {
- return dimOrdinalMeta.categories[key] || key + '';
- }
- return key + '';
- } // Get groupId from raw item. { groupId: '' }
- var itemVal = data.getRawDataItem(dataIndex);
- if (itemVal && itemVal.groupId) {
- return itemVal.groupId + '';
- }
- return dataGroupId || data.getId(dataIndex);
- };
- } // Use id if it's very likely to be an one to one animation
- // It's more robust than groupId
- // TODO Check if key dimension is specified.
- var useId = isAllIdSame(oldDiffItems, newDiffItems);
- var isElementStillInChart = {};
- if (!useId) {
- // We may have different diff strategy with basicTransition if we use other dimension as key.
- // If so, we can't simply check if oldEl is same with newEl. We need a map to check if oldEl is still being used in the new chart.
- // We can't use the elements that already being morphed. Let it keep it's original basic transition.
- for (var i = 0; i < newDiffItems.length; i++) {
- var newItem = newDiffItems[i];
- var el = newItem.data.getItemGraphicEl(newItem.dataIndex);
- if (el) {
- isElementStillInChart[el.id] = true;
- }
- }
- }
- function updateOneToOne(newIndex, oldIndex) {
- var oldItem = oldDiffItems[oldIndex];
- var newItem = newDiffItems[newIndex];
- var newSeries = newItem.data.hostModel; // TODO Mark this elements is morphed and don't morph them anymore
- var oldEl = oldItem.data.getItemGraphicEl(oldItem.dataIndex);
- var newEl = newItem.data.getItemGraphicEl(newItem.dataIndex); // Can't handle same elements.
- if (oldEl === newEl) {
- newEl && animateElementStyles(newEl, newItem.dataIndex, newSeries);
- return;
- }
- if ( // We can't use the elements that already being morphed
- oldEl && isElementStillInChart[oldEl.id]) {
- return;
- }
- if (newEl) {
- // TODO: If keep animating the group in case
- // some of the elements don't want to be morphed.
- // TODO Label?
- stopAnimation(newEl);
- if (oldEl) {
- stopAnimation(oldEl); // If old element is doing leaving animation. stop it and remove it immediately.
- removeEl(oldEl);
- hasMorphAnimation = true;
- applyMorphAnimation(getPathList(oldEl), getPathList(newEl), newItem.divide, newSeries, newIndex, updateMorphingPathProps);
- } else {
- fadeInElement(newEl, newSeries, newIndex);
- }
- } // else keep oldEl leaving animation.
- }
- new DataDiffer(oldDiffItems, newDiffItems, createKeyGetter(true, useId), createKeyGetter(false, useId), null, 'multiple').update(updateOneToOne).updateManyToOne(function (newIndex, oldIndices) {
- var newItem = newDiffItems[newIndex];
- var newData = newItem.data;
- var newSeries = newData.hostModel;
- var newEl = newData.getItemGraphicEl(newItem.dataIndex);
- var oldElsList = filter(map(oldIndices, function (idx) {
- return oldDiffItems[idx].data.getItemGraphicEl(oldDiffItems[idx].dataIndex);
- }), function (oldEl) {
- return oldEl && oldEl !== newEl && !isElementStillInChart[oldEl.id];
- });
- if (newEl) {
- stopAnimation(newEl);
- if (oldElsList.length) {
- // If old element is doing leaving animation. stop it and remove it immediately.
- each(oldElsList, function (oldEl) {
- stopAnimation(oldEl);
- removeEl(oldEl);
- });
- hasMorphAnimation = true;
- applyMorphAnimation(getPathList(oldElsList), getPathList(newEl), newItem.divide, newSeries, newIndex, updateMorphingPathProps);
- } else {
- fadeInElement(newEl, newSeries, newItem.dataIndex);
- }
- } // else keep oldEl leaving animation.
- }).updateOneToMany(function (newIndices, oldIndex) {
- var oldItem = oldDiffItems[oldIndex];
- var oldEl = oldItem.data.getItemGraphicEl(oldItem.dataIndex); // We can't use the elements that already being morphed
- if (oldEl && isElementStillInChart[oldEl.id]) {
- return;
- }
- var newElsList = filter(map(newIndices, function (idx) {
- return newDiffItems[idx].data.getItemGraphicEl(newDiffItems[idx].dataIndex);
- }), function (el) {
- return el && el !== oldEl;
- });
- var newSeris = newDiffItems[newIndices[0]].data.hostModel;
- if (newElsList.length) {
- each(newElsList, function (newEl) {
- return stopAnimation(newEl);
- });
- if (oldEl) {
- stopAnimation(oldEl); // If old element is doing leaving animation. stop it and remove it immediately.
- removeEl(oldEl);
- hasMorphAnimation = true;
- applyMorphAnimation(getPathList(oldEl), getPathList(newElsList), oldItem.divide, // Use divide on old.
- newSeris, newIndices[0], updateMorphingPathProps);
- } else {
- each(newElsList, function (newEl) {
- return fadeInElement(newEl, newSeris, newIndices[0]);
- });
- }
- } // else keep oldEl leaving animation.
- }).updateManyToMany(function (newIndices, oldIndices) {
- // If two data are same and both have groupId.
- // Normally they should be diff by id.
- new DataDiffer(oldIndices, newIndices, function (rawIdx) {
- return oldDiffItems[rawIdx].data.getId(oldDiffItems[rawIdx].dataIndex);
- }, function (rawIdx) {
- return newDiffItems[rawIdx].data.getId(newDiffItems[rawIdx].dataIndex);
- }).update(function (newIndex, oldIndex) {
- // Use the original index
- updateOneToOne(newIndices[newIndex], oldIndices[oldIndex]);
- }).execute();
- }).execute();
- if (hasMorphAnimation) {
- each(newList, function (_a) {
- var data = _a.data;
- var seriesModel = data.hostModel;
- var view = seriesModel && api.getViewOfSeriesModel(seriesModel);
- var animationCfg = getAnimationConfig('update', seriesModel, 0); // use 0 index.
- if (view && seriesModel.isAnimationEnabled() && animationCfg && animationCfg.duration > 0) {
- view.group.traverse(function (el) {
- if (el instanceof Path && !el.animators.length) {
- // We can't accept there still exists element that has no animation
- // if universalTransition is enabled
- el.animateFrom({
- style: {
- opacity: 0
- }
- }, animationCfg);
- }
- });
- }
- });
- }
- }
- function getSeriesTransitionKey(series) {
- var seriesKey = series.getModel('universalTransition').get('seriesKey');
- if (!seriesKey) {
- // Use series id by default.
- return series.id;
- }
- return seriesKey;
- }
- function convertArraySeriesKeyToString(seriesKey) {
- if (isArray(seriesKey)) {
- // Order independent.
- return seriesKey.sort().join(',');
- }
- return seriesKey;
- }
- function getDivideShapeFromData(data) {
- if (data.hostModel) {
- return data.hostModel.getModel('universalTransition').get('divideShape');
- }
- }
- function findTransitionSeriesBatches(globalStore, params) {
- var updateBatches = createHashMap();
- var oldDataMap = createHashMap(); // Map that only store key in array seriesKey.
- // Which is used to query the old data when transition from one to multiple series.
- var oldDataMapForSplit = createHashMap();
- each(globalStore.oldSeries, function (series, idx) {
- var oldDataGroupId = globalStore.oldDataGroupIds[idx];
- var oldData = globalStore.oldData[idx];
- var transitionKey = getSeriesTransitionKey(series);
- var transitionKeyStr = convertArraySeriesKeyToString(transitionKey);
- oldDataMap.set(transitionKeyStr, {
- dataGroupId: oldDataGroupId,
- data: oldData
- });
- if (isArray(transitionKey)) {
- // Same key can't in different array seriesKey.
- each(transitionKey, function (key) {
- oldDataMapForSplit.set(key, {
- key: transitionKeyStr,
- dataGroupId: oldDataGroupId,
- data: oldData
- });
- });
- }
- });
- function checkTransitionSeriesKeyDuplicated(transitionKeyStr) {
- if (updateBatches.get(transitionKeyStr)) {
- warn("Duplicated seriesKey in universalTransition " + transitionKeyStr);
- }
- }
- each(params.updatedSeries, function (series) {
- if (series.isUniversalTransitionEnabled() && series.isAnimationEnabled()) {
- var newDataGroupId = series.get('dataGroupId');
- var newData = series.getData();
- var transitionKey = getSeriesTransitionKey(series);
- var transitionKeyStr = convertArraySeriesKeyToString(transitionKey); // Only transition between series with same id.
- var oldData = oldDataMap.get(transitionKeyStr); // string transition key is the best match.
- if (oldData) {
- if (process.env.NODE_ENV !== 'production') {
- checkTransitionSeriesKeyDuplicated(transitionKeyStr);
- } // TODO check if data is same?
- updateBatches.set(transitionKeyStr, {
- oldSeries: [{
- dataGroupId: oldData.dataGroupId,
- divide: getDivideShapeFromData(oldData.data),
- data: oldData.data
- }],
- newSeries: [{
- dataGroupId: newDataGroupId,
- divide: getDivideShapeFromData(newData),
- data: newData
- }]
- });
- } else {
- // Transition from multiple series.
- if (isArray(transitionKey)) {
- if (process.env.NODE_ENV !== 'production') {
- checkTransitionSeriesKeyDuplicated(transitionKeyStr);
- }
- var oldSeries_1 = [];
- each(transitionKey, function (key) {
- var oldData = oldDataMap.get(key);
- if (oldData.data) {
- oldSeries_1.push({
- dataGroupId: oldData.dataGroupId,
- divide: getDivideShapeFromData(oldData.data),
- data: oldData.data
- });
- }
- });
- if (oldSeries_1.length) {
- updateBatches.set(transitionKeyStr, {
- oldSeries: oldSeries_1,
- newSeries: [{
- dataGroupId: newDataGroupId,
- data: newData,
- divide: getDivideShapeFromData(newData)
- }]
- });
- }
- } else {
- // Try transition to multiple series.
- var oldData_1 = oldDataMapForSplit.get(transitionKey);
- if (oldData_1) {
- var batch = updateBatches.get(oldData_1.key);
- if (!batch) {
- batch = {
- oldSeries: [{
- dataGroupId: oldData_1.dataGroupId,
- data: oldData_1.data,
- divide: getDivideShapeFromData(oldData_1.data)
- }],
- newSeries: []
- };
- updateBatches.set(oldData_1.key, batch);
- }
- batch.newSeries.push({
- dataGroupId: newDataGroupId,
- data: newData,
- divide: getDivideShapeFromData(newData)
- });
- }
- }
- }
- }
- });
- return updateBatches;
- }
- function querySeries(series, finder) {
- for (var i = 0; i < series.length; i++) {
- var found = finder.seriesIndex != null && finder.seriesIndex === series[i].seriesIndex || finder.seriesId != null && finder.seriesId === series[i].id;
- if (found) {
- return i;
- }
- }
- }
- function transitionSeriesFromOpt(transitionOpt, globalStore, params, api) {
- var from = [];
- var to = [];
- each(normalizeToArray(transitionOpt.from), function (finder) {
- var idx = querySeries(globalStore.oldSeries, finder);
- if (idx >= 0) {
- from.push({
- dataGroupId: globalStore.oldDataGroupIds[idx],
- data: globalStore.oldData[idx],
- // TODO can specify divideShape in transition.
- divide: getDivideShapeFromData(globalStore.oldData[idx]),
- dim: finder.dimension
- });
- }
- });
- each(normalizeToArray(transitionOpt.to), function (finder) {
- var idx = querySeries(params.updatedSeries, finder);
- if (idx >= 0) {
- var data = params.updatedSeries[idx].getData();
- to.push({
- dataGroupId: globalStore.oldDataGroupIds[idx],
- data: data,
- divide: getDivideShapeFromData(data),
- dim: finder.dimension
- });
- }
- });
- if (from.length > 0 && to.length > 0) {
- transitionBetween(from, to, api);
- }
- }
- export function installUniversalTransition(registers) {
- registers.registerUpdateLifecycle('series:beforeupdate', function (ecMOdel, api, params) {
- each(normalizeToArray(params.seriesTransition), function (transOpt) {
- each(normalizeToArray(transOpt.to), function (finder) {
- var series = params.updatedSeries;
- for (var i = 0; i < series.length; i++) {
- if (finder.seriesIndex != null && finder.seriesIndex === series[i].seriesIndex || finder.seriesId != null && finder.seriesId === series[i].id) {
- series[i][SERIES_UNIVERSAL_TRANSITION_PROP] = true;
- }
- }
- });
- });
- });
- registers.registerUpdateLifecycle('series:transition', function (ecModel, api, params) {
- // TODO api provide an namespace that can save stuff per instance
- var globalStore = getUniversalTransitionGlobalStore(api); // TODO multiple to multiple series.
- if (globalStore.oldSeries && params.updatedSeries && params.optionChanged) {
- // Use give transition config if its' give;
- var transitionOpt = params.seriesTransition;
- if (transitionOpt) {
- each(normalizeToArray(transitionOpt), function (opt) {
- transitionSeriesFromOpt(opt, globalStore, params, api);
- });
- } else {
- // Else guess from series based on transition series key.
- var updateBatches_1 = findTransitionSeriesBatches(globalStore, params);
- each(updateBatches_1.keys(), function (key) {
- var batch = updateBatches_1.get(key);
- transitionBetween(batch.oldSeries, batch.newSeries, api);
- });
- } // Reset
- each(params.updatedSeries, function (series) {
- // Reset;
- if (series[SERIES_UNIVERSAL_TRANSITION_PROP]) {
- series[SERIES_UNIVERSAL_TRANSITION_PROP] = false;
- }
- });
- } // Save all series of current update. Not only the updated one.
- var allSeries = ecModel.getSeries();
- var savedSeries = globalStore.oldSeries = [];
- var savedDataGroupIds = globalStore.oldDataGroupIds = [];
- var savedData = globalStore.oldData = [];
- for (var i = 0; i < allSeries.length; i++) {
- var data = allSeries[i].getData(); // Only save the data that can have transition.
- // Avoid large data costing too much extra memory
- if (data.count() < DATA_COUNT_THRESHOLD) {
- savedSeries.push(allSeries[i]);
- savedDataGroupIds.push(allSeries[i].get('dataGroupId'));
- savedData.push(data);
- }
- }
- });
- }
|