Skip to content

Commit

Permalink
Merge branch 'master' into module_default_esm
Browse files Browse the repository at this point in the history
  • Loading branch information
100pah committed Jan 22, 2024
2 parents abe29f0 + 2438562 commit 80172d6
Show file tree
Hide file tree
Showing 10 changed files with 981 additions and 55 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/npm-debug.log
/benchmark
/src
/ssr/client/src
.DS_Store
Thumbs.db
Desktop.ini
Expand Down
174 changes: 126 additions & 48 deletions src/animation/universalTransition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ import { EChartsExtensionInstallRegisters } from '../extension';
import { initProps } from '../util/graphic';
import DataDiffer from '../data/DataDiffer';
import SeriesData from '../data/SeriesData';
import { Dictionary, DimensionLoose, OptionDataItemObject, UniversalTransitionOption } from '../util/types';
import {
Dictionary,
DimensionLoose,
DimensionName,
DataVisualDimensions,
OptionDataItemObject,
UniversalTransitionOption
} from '../util/types';
import {
UpdateLifecycleParams,
UpdateLifecycleTransitionItem,
Expand All @@ -42,52 +49,91 @@ import Model from '../model/Model';
import Displayable from 'zrender/src/graphic/Displayable';

const DATA_COUNT_THRESHOLD = 1e4;
const TRANSITION_NONE = 0;
const TRANSITION_P2C = 1;
const TRANSITION_C2P = 2;

interface GlobalStore { oldSeries: SeriesModel[], oldDataGroupIds: string[], oldData: SeriesData[] };
const getUniversalTransitionGlobalStore = makeInner<GlobalStore, ExtensionAPI>();

interface DiffItem {
dataGroupId: string
data: SeriesData
dim: DimensionLoose
groupId: string
childGroupId: string
divide: UniversalTransitionOption['divideShape']
dataIndex: number
}
interface TransitionSeries {
dataGroupId: string
data: SeriesData
divide: UniversalTransitionOption['divideShape']
dim?: DimensionLoose
groupIdDim?: DimensionLoose
}

function getGroupIdDimension(data: SeriesData) {
function getDimension(data: SeriesData, visualDimension: string) {
const dimensions = data.dimensions;
for (let i = 0; i < dimensions.length; i++) {
const dimInfo = data.getDimensionInfo(dimensions[i]);
if (dimInfo && dimInfo.otherDims.itemGroupId === 0) {
if (dimInfo && dimInfo.otherDims[visualDimension as keyof DataVisualDimensions] === 0) {
return dimensions[i];
}
}
}

// get value by dimension. (only get value of itemGroupId or childGroupId, so convert it to string)
function getValueByDimension(data: SeriesData, dataIndex: number, dimension: DimensionName) {
const dimInfo = data.getDimensionInfo(dimension);
const dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta;
if (dimInfo) {
const value = data.get(dimInfo.name, dataIndex);
if (dimOrdinalMeta) {
return (dimOrdinalMeta.categories[value as number] as string) || value + '';
}
return value + '';
}
}

function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string, isChild: boolean) {
// try to get groupId from encode
const visualDimension = isChild ? 'itemChildGroupId' : 'itemGroupId';
const groupIdDim = getDimension(data, visualDimension);
if (groupIdDim) {
const groupId = getValueByDimension(data, dataIndex, groupIdDim);
return groupId;
}
// try to get groupId from raw data item
const rawDataItem = data.getRawDataItem(dataIndex) as OptionDataItemObject<unknown>;
const property = isChild ? 'childGroupId' : 'groupId';
if (rawDataItem && rawDataItem[property]) {
return rawDataItem[property] + '';
}
// fallback
if (isChild) {
return;
}
// try to use series.dataGroupId as groupId, otherwise use dataItem's id as groupId
return (dataGroupId || data.getId(dataIndex));
}

// flatten all data items from different serieses into one arrary
function flattenDataDiffItems(list: TransitionSeries[]) {
const items: DiffItem[] = [];

each(list, seriesInfo => {
const data = seriesInfo.data;
const dataGroupId = seriesInfo.dataGroupId;
if (data.count() > DATA_COUNT_THRESHOLD) {
if (__DEV__) {
warn('Universal transition is disabled on large data > 10k.');
}
return;
}
const indices = data.getIndices();
const groupDim = getGroupIdDimension(data);
for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) {
items.push({
dataGroupId: seriesInfo.dataGroupId,
data,
dim: seriesInfo.dim || groupDim,
groupId: getGroupId(data, dataIndex, dataGroupId, false), // either of groupId or childGroupId will be used as diffItem's key,
childGroupId: getGroupId(data, dataIndex, dataGroupId, true), // depending on the transition direction (see below)
divide: seriesInfo.divide,
dataIndex
});
Expand Down Expand Up @@ -185,18 +231,71 @@ function transitionBetween(
}
}

let hasMorphAnimation = false;

function findKeyDim(items: DiffItem[]) {
for (let i = 0; i < items.length; i++) {
if (items[i].dim) {
return items[i].dim;
}
/**
* With groupId and childGroupId, we can build parent-child relationships between dataItems.
* However, we should mind the parent-child "direction" between old and new options.
*
* For example, suppose we have two dataItems from two series.data:
*
* dataA: [ dataB: [
* { {
* value: 5, value: 3,
* groupId: 'creatures', groupId: 'animals',
* childGroupId: 'animals' childGroupId: 'dogs'
* }, },
* ... ...
* ] ]
*
* where dataA is belong to optionA and dataB is belong to optionB.
*
* When we `setOption(optionB)` from optionA, we choose childGroupId of dataItemA and groupId of
* dataItemB as keys so the two keys are matched (both are 'animals'), then universalTransition
* will work. This derection is "parent -> child".
*
* If we `setOption(optionA)` from optionB, we also choose groupId of dataItemB and childGroupId
* of dataItemA as keys and universalTransition will work. This derection is "child -> parent".
*
* If there is no childGroupId specified, which means no multiLevelDrillDown/Up is needed and no
* parent-child relationship exists. This direction is "none".
*
* So we need to know whether to use groupId or childGroupId as the key when we call the keyGetter
* functions. Thus, we need to decide the direction first.
*
* The rule is:
*
* if (all childGroupIds in oldDiffItems and all groupIds in newDiffItems have common value) {
* direction = 'parent -> child';
* } else if (all groupIds in oldDiffItems and all childGroupIds in newDiffItems have common value) {
* direction = 'child -> parent';
* } else {
* direction = 'none';
* }
*/
let direction = TRANSITION_NONE;

// find all groupIds and childGroupIds from oldDiffItems
const oldGroupIds = createHashMap();
const oldChildGroupIds = createHashMap();
oldDiffItems.forEach((item) => {
item.groupId && oldGroupIds.set(item.groupId, true);
item.childGroupId && oldChildGroupIds.set(item.childGroupId, true);

});
// traverse newDiffItems and decide the direction according to the rule
for (let i = 0; i < newDiffItems.length; i++) {
const newGroupId = newDiffItems[i].groupId;
if (oldChildGroupIds.get(newGroupId)) {
direction = TRANSITION_P2C;
break;
}
const newChildGroupId = newDiffItems[i].childGroupId;
if (newChildGroupId && oldGroupIds.get(newChildGroupId)) {
direction = TRANSITION_C2P;
break;
}
}
const oldKeyDim = findKeyDim(oldDiffItems);
const newKeyDim = findKeyDim(newDiffItems);

let hasMorphAnimation = false;

function createKeyGetter(isOld: boolean, onlyGetId: boolean) {
return function (diffItem: DiffItem): string {
Expand All @@ -206,36 +305,12 @@ function transitionBetween(
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.
const 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.
const keyDim = isOld
? (oldKeyDim || newKeyDim)
: (newKeyDim || oldKeyDim);

const dimInfo = keyDim && data.getDimensionInfo(keyDim);
const dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta;

if (dimInfo) {
// Get from encode.itemGroupId.
const key = data.get(dimInfo.name, dataIndex);
if (dimOrdinalMeta) {
return dimOrdinalMeta.categories[key as number] as string || (key + '');
}
return key + '';
if (isOld) {
return direction === TRANSITION_P2C ? diffItem.childGroupId : diffItem.groupId;
}

// Get groupId from raw item. { groupId: '' }
const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject<unknown>;
if (itemVal && itemVal.groupId) {
return itemVal.groupId + '';
else {
return direction === TRANSITION_C2P ? diffItem.childGroupId : diffItem.groupId;
}
return (dataGroupId || data.getId(dataIndex));
};
}

Expand Down Expand Up @@ -541,6 +616,7 @@ function findTransitionSeriesBatches(
}
else {
// Transition from multiple series.
// e.g. 'female', 'male' -> ['female', 'male']
if (isArray(transitionKey)) {
if (__DEV__) {
checkTransitionSeriesKeyDuplicated(transitionKeyStr);
Expand Down Expand Up @@ -569,6 +645,7 @@ function findTransitionSeriesBatches(
}
else {
// Try transition to multiple series.
// e.g. ['female', 'male'] -> 'female', 'male'
const oldData = oldDataMapForSplit.get(transitionKey);
if (oldData) {
let batch = updateBatches.get(oldData.key);
Expand Down Expand Up @@ -623,7 +700,7 @@ function transitionSeriesFromOpt(
data: globalStore.oldData[idx],
// TODO can specify divideShape in transition.
divide: getDivideShapeFromData(globalStore.oldData[idx]),
dim: finder.dimension
groupIdDim: finder.dimension
});
}
});
Expand All @@ -635,7 +712,7 @@ function transitionSeriesFromOpt(
dataGroupId: globalStore.oldDataGroupIds[idx],
data,
divide: getDivideShapeFromData(data),
dim: finder.dimension
groupIdDim: finder.dimension
});
}
});
Expand Down Expand Up @@ -665,6 +742,7 @@ export function installUniversalTransition(registers: EChartsExtensionInstallReg

// TODO multiple to multiple series.
if (globalStore.oldSeries && params.updatedSeries && params.optionChanged) {
// TODO transitionOpt was used in an old implementation and can be removed now
// Use give transition config if its' give;
const transitionOpt = params.seriesTransition;
if (transitionOpt) {
Expand Down
3 changes: 2 additions & 1 deletion src/chart/bar/BaseBarSeries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,12 @@ class BaseBarSeriesModel<Opts extends BaseBarSeriesOption<unknown> = BaseBarSeri
// If axis type is category, use tick coords instead
if (axis.type === 'category' && dims != null) {
const tickCoords = axis.getTicksCoords();
const alignTicksWithLabel = axis.getTickModel().get('alignWithLabel');

let targetTickId = clampData[idx];
// The index of rightmost tick of markArea is 1 larger than x1/y1 index
const isEnd = dims[idx] === 'x1' || dims[idx] === 'y1';
if (isEnd) {
if (isEnd && !alignTicksWithLabel) {
targetTickId += 1;
}

Expand Down
8 changes: 7 additions & 1 deletion src/chart/graph/GraphView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class GraphView extends ChartView {
}

dispose() {
this.remove();

this._controller && this._controller.dispose();
this._controllerHost = null;
}
Expand Down Expand Up @@ -300,7 +302,11 @@ class GraphView extends ChartView {
this._lineDraw.updateLayout();
}

remove(ecModel: GlobalModel, api: ExtensionAPI) {
remove() {
clearTimeout(this._layoutTimeout);
this._layouting = false;
this._layoutTimeout = null;

this._symbolDraw && this._symbolDraw.remove();
this._lineDraw && this._lineDraw.remove();
}
Expand Down
5 changes: 4 additions & 1 deletion src/util/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ export type DimensionLoose = DimensionName | DimensionIndexLoose;
export type DimensionType = DataStoreDimensionType;

export const VISUAL_DIMENSIONS = createHashMap<number, keyof DataVisualDimensions>([
'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'seriesName'
'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'itemChildGroupId', 'seriesName'
]);
// The key is VISUAL_DIMENSIONS
export interface DataVisualDimensions {
Expand All @@ -444,6 +444,7 @@ export interface DataVisualDimensions {
itemName?: DimensionIndex;
itemId?: DimensionIndex;
itemGroupId?: DimensionIndex;
itemChildGroupId?: DimensionIndex;
seriesName?: DimensionIndex;
}

Expand Down Expand Up @@ -618,6 +619,7 @@ export type OptionDataItemObject<T> = {
id?: OptionId;
name?: OptionName;
groupId?: OptionId;
childGroupId?: OptionId;
value?: T[] | T;
selected?: boolean;
};
Expand Down Expand Up @@ -667,6 +669,7 @@ export interface OptionEncodeVisualDimensions {
// Which is useful in prepresenting the transition key of drilldown/up animation.
// Or hover linking.
itemGroupId?: OptionEncodeValue;
childGroupdId?: OptionEncodeValue;
}
export interface OptionEncode extends OptionEncodeVisualDimensions {
[coordDim: string]: OptionEncodeValue | undefined
Expand Down
Loading

0 comments on commit 80172d6

Please sign in to comment.