From 6f500be79c77d1b726aa127b490917f52071e33c Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 6 Aug 2022 00:27:24 +0800 Subject: [PATCH 01/24] test(universalTransition): a possible test file --- ...iversalTransition-multiLevelDrillDown.html | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 test/universalTransition-multiLevelDrillDown.html diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html new file mode 100644 index 0000000000..951278fb93 --- /dev/null +++ b/test/universalTransition-multiLevelDrillDown.html @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + +
+ + + + + + From 0f850296ac34f01a10457bc927eb907527ff1917 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 6 Aug 2022 00:29:12 +0800 Subject: [PATCH 02/24] wip: successfully get childGroupId (a possible new interface) --- src/animation/universalTransition.ts | 51 ++++++++++++++++++++++++++-- src/util/types.ts | 5 ++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index dabd7ee3ec..7344fab446 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -49,6 +49,7 @@ const getUniversalTransitionGlobalStore = makeInner() interface DiffItem { data: SeriesData dim: DimensionLoose + childGroupDim: DimensionLoose divide: UniversalTransitionOption['divideShape'] dataIndex: number } @@ -68,6 +69,16 @@ function getGroupIdDimension(data: SeriesData) { } } +function getChildGroupIdDimension(data: SeriesData) { + const dimensions = data.dimensions; + for (let i = 0; i < dimensions.length; i++) { + const dimInfo = data.getDimensionInfo(dimensions[i]); + if (dimInfo && dimInfo.otherDims.childGroupId === 0) { + return dimensions[i]; + } + } +} + function flattenDataDiffItems(list: TransitionSeries[]) { const items: DiffItem[] = []; @@ -81,10 +92,12 @@ function flattenDataDiffItems(list: TransitionSeries[]) { } const indices = data.getIndices(); const groupDim = getGroupIdDimension(data); + const childGroupDim = getChildGroupIdDimension(data); for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ data, dim: seriesInfo.dim || groupDim, + childGroupDim, divide: seriesInfo.divide, dataIndex }); @@ -190,9 +203,21 @@ function transitionBetween( } } } + + function findChildGroupDim(items: DiffItem[]) { + for (let i = 0; i < items.length; i++) { + if (items[i].childGroupDim) { + return items[i].childGroupDim; + } + } + } + const oldKeyDim = findKeyDim(oldDiffItems); const newKeyDim = findKeyDim(newDiffItems); + const oldChildGroupDim = findChildGroupDim(oldDiffItems); + const newChildGroupDim = findChildGroupDim(newDiffItems); + let hasMorphAnimation = false; function createKeyGetter(isOld: boolean, onlyGetId: boolean) { @@ -200,7 +225,7 @@ function transitionBetween( const data = diffItem.data; const dataIndex = diffItem.dataIndex; // TODO if specified dim - if (onlyGetId) { + if (onlyGetId) { // 猜测之前所有需要key的地方用的其实就是dataItem.id, onlyGetId若为true其实就是之前的情况 return data.getId(dataIndex); } @@ -227,10 +252,30 @@ function transitionBetween( return key + ''; } + const childGroupDim = isOld + ? (oldChildGroupDim || newChildGroupDim) + : (newChildGroupDim || oldChildGroupDim); + + const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); + const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + + if (childGroupDimInfo) { + // Get from encode.childGroupId. + const key = data.get(childGroupDimInfo.name, dataIndex); + if (childGroupDimOrdinalMeta) { + return childGroupDimOrdinalMeta.categories[key as number] as string || (key + ''); + } + //console.log(key); + return key + ''; + } + // Get groupId from raw item. { groupId: '' } const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; if (itemVal && itemVal.groupId) { - return itemVal.groupId + ''; + if (itemVal.childGroupId) { + //console.log(itemVal.childGroupId); + } + return itemVal.groupId + ''; // 注意这个item的return --tyn } return (dataGroupId || data.getId(dataIndex)); }; @@ -682,4 +727,4 @@ export function installUniversalTransition(registers: EChartsExtensionInstallReg } } }); -} \ No newline at end of file +} diff --git a/src/util/types.ts b/src/util/types.ts index 3e9eb31cf5..862797c2e4 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -430,7 +430,7 @@ export type DimensionLoose = DimensionName | DimensionIndexLoose; export type DimensionType = DataStoreDimensionType; export const VISUAL_DIMENSIONS = createHashMap([ - 'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'seriesName' + 'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'childGroupId', 'seriesName' ]); // The key is VISUAL_DIMENSIONS export interface DataVisualDimensions { @@ -442,6 +442,7 @@ export interface DataVisualDimensions { itemName?: DimensionIndex; itemId?: DimensionIndex; itemGroupId?: DimensionIndex; + childGroupId?: DimensionIndex; seriesName?: DimensionIndex; } @@ -616,6 +617,7 @@ export type OptionDataItemObject = { id?: OptionId; name?: OptionName; groupId?: OptionId; + childGroupId?: OptionId; value?: T[] | T; selected?: boolean; }; @@ -665,6 +667,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 From 4d4634fd47fad8a2245ddb3db3f67d69c0285038 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 6 Aug 2022 13:50:40 +0800 Subject: [PATCH 03/24] wip: can decide "parent2child" or "child2parent" --- src/animation/universalTransition.ts | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 7344fab446..06b8a153a5 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -220,6 +220,45 @@ function transitionBetween( let hasMorphAnimation = false; + // 在createKeyGetter之前先要确定"父->子"还是"子->父" + const oldGroupIds: string[] = []; + const oldChildGroupIds: string[] = []; + + oldDiffItems.forEach((item) => { + item.dim && oldGroupIds.push('' + item.data.get(item.data.getDimensionInfo(item.dim).name, item.dataIndex)); + item.childGroupDim + && oldChildGroupIds.push( + '' + item.data.get(item.data.getDimensionInfo(item.childGroupDim).name, item.dataIndex) + ); + }); + + // 若o.childGroupIds中的任意一个等于n.groupIds中的任意一个,则判断为“父->子”方向 + // 若o.groupIds中的任意一个等于n.childGroupIds的任意一个,则判断为“子->父”方向 + + let direction = 'whatever'; + for (let i = 0; i < newDiffItems.length; i++) { + const newGroupId = + newDiffItems[i].data.get( + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].dim).name, + newDiffItems[i].dataIndex + ) + ''; + if (oldChildGroupIds.includes(newGroupId)) { + direction = 'parent2child'; + break; + } + const newChildGroupId = + newDiffItems[i].data.get( + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupDim).name, + newDiffItems[i].dataIndex + ) + ''; + if (oldGroupIds.includes(newChildGroupId)) { + direction = 'child2parent'; + break; + } + } + + // console.log(direction); + function createKeyGetter(isOld: boolean, onlyGetId: boolean) { return function (diffItem: DiffItem): string { const data = diffItem.data; From a4cf7f9f22c33de0ea0b0e8ba61eb5d16bd175a4 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 6 Aug 2022 14:21:07 +0800 Subject: [PATCH 04/24] wip: new createKeyGetters that suppot multi-drill (but only get key from dim) --- src/animation/universalTransition.ts | 117 ++++++++++++++++++++------- 1 file changed, 89 insertions(+), 28 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 06b8a153a5..dc98121391 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -259,7 +259,7 @@ function transitionBetween( // console.log(direction); - function createKeyGetter(isOld: boolean, onlyGetId: boolean) { + function createKeyGetterForNew(onlyGetId: boolean) { return function (diffItem: DiffItem): string { const data = diffItem.data; const dataIndex = diffItem.dataIndex; @@ -273,39 +273,100 @@ function transitionBetween( // If group id not exits. Use id instead. If so, only one to one transition will be applied. const dataGroupId = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; - // 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); + if (direction === 'parent2child') { + // If specified key dimension(itemGroupId by default). Use this same dimension from other data. + // PENDING: If only use key dimension of newData. + const keyDim = newKeyDim || oldKeyDim; - const dimInfo = keyDim && data.getDimensionInfo(keyDim); - const dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta; + 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 + ''); + 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 + ''; } - return key + ''; } - const childGroupDim = isOld - ? (oldChildGroupDim || newChildGroupDim) - : (newChildGroupDim || oldChildGroupDim); + if (direction === 'child2parent') { + const childGroupDim = newChildGroupDim || oldChildGroupDim; + + const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); + const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + + if (childGroupDimInfo) { + // Get from encode.childGroupId. + const key = data.get(childGroupDimInfo.name, dataIndex); + if (childGroupDimOrdinalMeta) { + return (childGroupDimOrdinalMeta.categories[key as number] as string) || key + ''; + } + //console.log(key); + return key + ''; + } + } - const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); - const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + // Get groupId from raw item. { groupId: '' } + const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; + if (itemVal && itemVal.groupId) { + if (itemVal.childGroupId) { + //console.log(itemVal.childGroupId); + } + return itemVal.groupId + ''; // 注意这个item的return --tyn + } + return (dataGroupId || data.getId(dataIndex)); + }; + } - if (childGroupDimInfo) { - // Get from encode.childGroupId. - const key = data.get(childGroupDimInfo.name, dataIndex); - if (childGroupDimOrdinalMeta) { - return childGroupDimOrdinalMeta.categories[key as number] as string || (key + ''); + function createKeyGetterForOld(onlyGetId: boolean) { + return function (diffItem: DiffItem): string { + const data = diffItem.data; + const dataIndex = diffItem.dataIndex; + // TODO if specified dim + if (onlyGetId) { // 猜测之前所有需要key的地方用的其实就是dataItem.id, onlyGetId若为true其实就是之前的情况 + 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 = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; + + if (direction === 'child2parent') { + // If specified key dimension(itemGroupId by default). Use this same dimension from other data. + // PENDING: If only use key dimension of newData. + const keyDim = oldKeyDim || newKeyDim; + + 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 (direction === 'parent2child') { + const childGroupDim = oldChildGroupDim || newChildGroupDim; + + const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); + const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + + if (childGroupDimInfo) { + // Get from encode.childGroupId. + const key = data.get(childGroupDimInfo.name, dataIndex); + if (childGroupDimOrdinalMeta) { + return (childGroupDimOrdinalMeta.categories[key as number] as string) || key + ''; + } + //console.log(key); + return key + ''; } - //console.log(key); - return key + ''; } // Get groupId from raw item. { groupId: '' } @@ -395,8 +456,8 @@ function transitionBetween( (new DataDiffer( oldDiffItems, newDiffItems, - createKeyGetter(true, useId), - createKeyGetter(false, useId), + createKeyGetterForOld(useId), + createKeyGetterForNew(useId), null, 'multiple' )) From 788daecc1b3328f6bc29ce28f0b9988fda408eee Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 6 Aug 2022 14:56:53 +0800 Subject: [PATCH 05/24] wip: should consider getting direction from more ways & using groupId only when direction is 'nodirection' --- src/animation/universalTransition.ts | 63 +++++++++++++++------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index dc98121391..cc309c177e 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -224,41 +224,44 @@ function transitionBetween( const oldGroupIds: string[] = []; const oldChildGroupIds: string[] = []; - oldDiffItems.forEach((item) => { - item.dim && oldGroupIds.push('' + item.data.get(item.data.getDimensionInfo(item.dim).name, item.dataIndex)); - item.childGroupDim - && oldChildGroupIds.push( - '' + item.data.get(item.data.getDimensionInfo(item.childGroupDim).name, item.dataIndex) - ); - }); + if (oldKeyDim || oldChildGroupDim) { + oldDiffItems.forEach((item) => { + item.dim && oldGroupIds.push('' + item.data.get(item.data.getDimensionInfo(item.dim).name, item.dataIndex)); + item.childGroupDim + && oldChildGroupIds.push( + '' + item.data.get(item.data.getDimensionInfo(item.childGroupDim).name, item.dataIndex) + ); + }); + } // 若o.childGroupIds中的任意一个等于n.groupIds中的任意一个,则判断为“父->子”方向 // 若o.groupIds中的任意一个等于n.childGroupIds的任意一个,则判断为“子->父”方向 - let direction = 'whatever'; - for (let i = 0; i < newDiffItems.length; i++) { - const newGroupId = - newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].dim).name, - newDiffItems[i].dataIndex - ) + ''; - if (oldChildGroupIds.includes(newGroupId)) { - direction = 'parent2child'; - break; - } - const newChildGroupId = - newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupDim).name, - newDiffItems[i].dataIndex - ) + ''; - if (oldGroupIds.includes(newChildGroupId)) { - direction = 'child2parent'; - break; + let direction = 'nodirection'; + + if (newKeyDim || newChildGroupDim) { + for (let i = 0; i < newDiffItems.length; i++) { + const newGroupId = + newDiffItems[i].data.get( + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].dim).name, + newDiffItems[i].dataIndex + ) + ''; + if (oldChildGroupIds.includes(newGroupId)) { + direction = 'parent2child'; + break; + } + const newChildGroupId = + newDiffItems[i].data.get( + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupDim).name, + newDiffItems[i].dataIndex + ) + ''; + if (oldGroupIds.includes(newChildGroupId)) { + direction = 'child2parent'; + break; + } } } - // console.log(direction); - function createKeyGetterForNew(onlyGetId: boolean) { return function (diffItem: DiffItem): string { const data = diffItem.data; @@ -273,7 +276,7 @@ function transitionBetween( // If group id not exits. Use id instead. If so, only one to one transition will be applied. const dataGroupId = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; - if (direction === 'parent2child') { + if (direction === 'parent2child' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. // PENDING: If only use key dimension of newData. const keyDim = newKeyDim || oldKeyDim; @@ -334,7 +337,7 @@ function transitionBetween( // If group id not exits. Use id instead. If so, only one to one transition will be applied. const dataGroupId = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; - if (direction === 'child2parent') { + if (direction === 'child2parent' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. // PENDING: If only use key dimension of newData. const keyDim = oldKeyDim || newKeyDim; From 5063c519f273d877d1f3b27fa134cec702598a8e Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Wed, 31 Aug 2022 15:49:35 +0800 Subject: [PATCH 06/24] refactor: rename "KeyDim" to "GroupIdDim" --- src/animation/universalTransition.ts | 94 +++++++++++++++------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index cc309c177e..20957d117c 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -48,15 +48,15 @@ const getUniversalTransitionGlobalStore = makeInner() interface DiffItem { data: SeriesData - dim: DimensionLoose - childGroupDim: DimensionLoose + groupIdDim: DimensionLoose + childGroupIdDim: DimensionLoose divide: UniversalTransitionOption['divideShape'] dataIndex: number } interface TransitionSeries { data: SeriesData divide: UniversalTransitionOption['divideShape'] - dim?: DimensionLoose + groupIdDim?: DimensionLoose } function getGroupIdDimension(data: SeriesData) { @@ -91,13 +91,13 @@ function flattenDataDiffItems(list: TransitionSeries[]) { return; } const indices = data.getIndices(); - const groupDim = getGroupIdDimension(data); - const childGroupDim = getChildGroupIdDimension(data); + const groupIdDim = getGroupIdDimension(data); + const childGroupIdDim = getChildGroupIdDimension(data); for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ data, - dim: seriesInfo.dim || groupDim, - childGroupDim, + groupIdDim: seriesInfo.groupIdDim || groupIdDim, + childGroupIdDim, divide: seriesInfo.divide, dataIndex }); @@ -196,27 +196,27 @@ function transitionBetween( } - function findKeyDim(items: DiffItem[]) { + function findGroupIdDim(items: DiffItem[]) { for (let i = 0; i < items.length; i++) { - if (items[i].dim) { - return items[i].dim; + if (items[i].groupIdDim) { + return items[i].groupIdDim; } } } - function findChildGroupDim(items: DiffItem[]) { + function findChildGroupIdDim(items: DiffItem[]) { for (let i = 0; i < items.length; i++) { - if (items[i].childGroupDim) { - return items[i].childGroupDim; + if (items[i].childGroupIdDim) { + return items[i].childGroupIdDim; } } } - const oldKeyDim = findKeyDim(oldDiffItems); - const newKeyDim = findKeyDim(newDiffItems); + const oldGroupIdDim = findGroupIdDim(oldDiffItems); + const newGroupIdDim = findGroupIdDim(newDiffItems); - const oldChildGroupDim = findChildGroupDim(oldDiffItems); - const newChildGroupDim = findChildGroupDim(newDiffItems); + const oldChildGroupIdDim = findChildGroupIdDim(oldDiffItems); + const newChildGroupIdDim = findChildGroupIdDim(newDiffItems); let hasMorphAnimation = false; @@ -224,12 +224,15 @@ function transitionBetween( const oldGroupIds: string[] = []; const oldChildGroupIds: string[] = []; - if (oldKeyDim || oldChildGroupDim) { + if (oldGroupIdDim || oldChildGroupIdDim) { oldDiffItems.forEach((item) => { - item.dim && oldGroupIds.push('' + item.data.get(item.data.getDimensionInfo(item.dim).name, item.dataIndex)); - item.childGroupDim + item.groupIdDim + && oldGroupIds.push( + '' + item.data.get(item.data.getDimensionInfo(item.groupIdDim).name, item.dataIndex) + ); + item.childGroupIdDim && oldChildGroupIds.push( - '' + item.data.get(item.data.getDimensionInfo(item.childGroupDim).name, item.dataIndex) + '' + item.data.get(item.data.getDimensionInfo(item.childGroupIdDim).name, item.dataIndex) ); }); } @@ -239,11 +242,13 @@ function transitionBetween( let direction = 'nodirection'; - if (newKeyDim || newChildGroupDim) { + // TODO 下面的判断方向没有考虑itemGroupId缺失,需要dataGroupId作为groupId的情形 + // 同时也没有考虑没有encode,而是从rawItem拿到groupId和childGroupId的情况 + if (newGroupIdDim || newChildGroupIdDim) { for (let i = 0; i < newDiffItems.length; i++) { const newGroupId = newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].dim).name, + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].groupIdDim).name, newDiffItems[i].dataIndex ) + ''; if (oldChildGroupIds.includes(newGroupId)) { @@ -252,7 +257,7 @@ function transitionBetween( } const newChildGroupId = newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupDim).name, + newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupIdDim).name, newDiffItems[i].dataIndex ) + ''; if (oldGroupIds.includes(newChildGroupId)) { @@ -279,9 +284,9 @@ function transitionBetween( if (direction === 'parent2child' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. // PENDING: If only use key dimension of newData. - const keyDim = newKeyDim || oldKeyDim; + const groupIdDim = newGroupIdDim || oldGroupIdDim; - const dimInfo = keyDim && data.getDimensionInfo(keyDim); + const dimInfo = groupIdDim && data.getDimensionInfo(groupIdDim); const dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta; if (dimInfo) { @@ -295,16 +300,16 @@ function transitionBetween( } if (direction === 'child2parent') { - const childGroupDim = newChildGroupDim || oldChildGroupDim; + const childGroupIdDim = newChildGroupIdDim || oldChildGroupIdDim; - const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); - const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + const childGroupIdDimInfo = childGroupIdDim && data.getDimensionInfo(childGroupIdDim); + const childGroupIdDimOrdinalMeta = childGroupIdDimInfo && childGroupIdDimInfo.ordinalMeta; - if (childGroupDimInfo) { + if (childGroupIdDimInfo) { // Get from encode.childGroupId. - const key = data.get(childGroupDimInfo.name, dataIndex); - if (childGroupDimOrdinalMeta) { - return (childGroupDimOrdinalMeta.categories[key as number] as string) || key + ''; + const key = data.get(childGroupIdDimInfo.name, dataIndex); + if (childGroupIdDimOrdinalMeta) { + return (childGroupIdDimOrdinalMeta.categories[key as number] as string) || key + ''; } //console.log(key); return key + ''; @@ -340,9 +345,9 @@ function transitionBetween( if (direction === 'child2parent' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. // PENDING: If only use key dimension of newData. - const keyDim = oldKeyDim || newKeyDim; + const groupIdDim = oldGroupIdDim || newGroupIdDim; - const dimInfo = keyDim && data.getDimensionInfo(keyDim); + const dimInfo = groupIdDim && data.getDimensionInfo(groupIdDim); const dimOrdinalMeta = dimInfo && dimInfo.ordinalMeta; if (dimInfo) { @@ -356,16 +361,16 @@ function transitionBetween( } if (direction === 'parent2child') { - const childGroupDim = oldChildGroupDim || newChildGroupDim; + const childGroupIdDim = oldChildGroupIdDim || newChildGroupIdDim; - const childGroupDimInfo = childGroupDim && data.getDimensionInfo(childGroupDim); - const childGroupDimOrdinalMeta = childGroupDimInfo && childGroupDimInfo.ordinalMeta; + const childGroupIdDimInfo = childGroupIdDim && data.getDimensionInfo(childGroupIdDim); + const childGroupIdDimOrdinalMeta = childGroupIdDimInfo && childGroupIdDimInfo.ordinalMeta; - if (childGroupDimInfo) { + if (childGroupIdDimInfo) { // Get from encode.childGroupId. - const key = data.get(childGroupDimInfo.name, dataIndex); - if (childGroupDimOrdinalMeta) { - return (childGroupDimOrdinalMeta.categories[key as number] as string) || key + ''; + const key = data.get(childGroupIdDimInfo.name, dataIndex); + if (childGroupIdDimOrdinalMeta) { + return (childGroupIdDimOrdinalMeta.categories[key as number] as string) || key + ''; } //console.log(key); return key + ''; @@ -751,7 +756,7 @@ function transitionSeriesFromOpt( data: globalStore.oldData[idx], // TODO can specify divideShape in transition. divide: getDivideShapeFromData(globalStore.oldData[idx]), - dim: finder.dimension + groupIdDim: finder.dimension }); } }); @@ -762,7 +767,7 @@ function transitionSeriesFromOpt( to.push({ data, divide: getDivideShapeFromData(data), - dim: finder.dimension + groupIdDim: finder.dimension }); } }); @@ -792,6 +797,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) { From 01ba523a7d1080258d03bbb7b78233f29592fafc Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Thu, 1 Sep 2022 16:58:48 +0800 Subject: [PATCH 07/24] learning: add some comments --- src/animation/universalTransition.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 20957d117c..fbf12aa859 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -79,6 +79,7 @@ function getChildGroupIdDimension(data: SeriesData) { } } +// flatten all data items from different serieses into one arrary function flattenDataDiffItems(list: TransitionSeries[]) { const items: DiffItem[] = []; @@ -244,6 +245,7 @@ function transitionBetween( // TODO 下面的判断方向没有考虑itemGroupId缺失,需要dataGroupId作为groupId的情形 // 同时也没有考虑没有encode,而是从rawItem拿到groupId和childGroupId的情况 + // 还没考虑nodirection也就是没有childGroupId的情况(undefined) if (newGroupIdDim || newChildGroupIdDim) { for (let i = 0; i < newDiffItems.length; i++) { const newGroupId = @@ -631,6 +633,7 @@ function findTransitionSeriesBatches( data: SeriesData }>(); + // 处理oldSerieses each(globalStore.oldSeries, (series, idx) => { const oldData = globalStore.oldData[idx]; const transitionKey = getSeriesTransitionKey(series); @@ -653,12 +656,14 @@ function findTransitionSeriesBatches( warn(`Duplicated seriesKey in universalTransition ${transitionKeyStr}`); } } + // 处理newSerieses each(params.updatedSeries, series => { if (series.isUniversalTransitionEnabled() && series.isAnimationEnabled()) { const newData = series.getData(); + // TODO rename "transitionKey" to "seriesKey" const transitionKey = getSeriesTransitionKey(series); const transitionKeyStr = convertArraySeriesKeyToString(transitionKey); - // Only transition between series with same id. + // Only transition between series with same seriesKey. const oldData = oldDataMap.get(transitionKeyStr); // string transition key is the best match. if (oldData) { @@ -679,6 +684,7 @@ function findTransitionSeriesBatches( } else { // Transition from multiple series. + // e.g. 'female', 'male' -> ['female', 'male'] if (isArray(transitionKey)) { if (__DEV__) { checkTransitionSeriesKeyDuplicated(transitionKeyStr); @@ -705,6 +711,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); From 5e475a20805af4cca0c8b401081dc84001652b4b Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Tue, 23 Aug 2022 22:12:37 +0800 Subject: [PATCH 08/24] fix: incorrect dataGroupId for old data items in universalTransition --- src/animation/universalTransition.ts | 49 ++++++++++++++++++++-------- test/universalTransition2.html | 2 +- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index fbf12aa859..74686d190e 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -43,10 +43,11 @@ import Displayable from 'zrender/src/graphic/Displayable'; const DATA_COUNT_THRESHOLD = 1e4; -interface GlobalStore { oldSeries: SeriesModel[], oldData: SeriesData[] }; +interface GlobalStore { oldSeries: SeriesModel[], oldDataGroupIds: string[], oldData: SeriesData[] }; const getUniversalTransitionGlobalStore = makeInner(); interface DiffItem { + dataGroupId: string data: SeriesData groupIdDim: DimensionLoose childGroupIdDim: DimensionLoose @@ -54,6 +55,7 @@ interface DiffItem { dataIndex: number } interface TransitionSeries { + dataGroupId: string data: SeriesData divide: UniversalTransitionOption['divideShape'] groupIdDim?: DimensionLoose @@ -96,6 +98,7 @@ function flattenDataDiffItems(list: TransitionSeries[]) { const childGroupIdDim = getChildGroupIdDimension(data); for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ + dataGroupId: seriesInfo.dataGroupId, data, groupIdDim: seriesInfo.groupIdDim || groupIdDim, childGroupIdDim, @@ -281,7 +284,7 @@ function transitionBetween( // 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 = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; + const dataGroupId = diffItem.dataGroupId; if (direction === 'parent2child' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. @@ -342,7 +345,7 @@ function transitionBetween( // 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 = data.hostModel && (data.hostModel as SeriesModel).get('dataGroupId') as string; + const dataGroupId = diffItem.dataGroupId; if (direction === 'child2parent' || direction === 'nodirection') { // If specified key dimension(itemGroupId by default). Use this same dimension from other data. @@ -625,27 +628,36 @@ function findTransitionSeriesBatches( ) { const updateBatches = createHashMap(); - const oldDataMap = createHashMap(); + const oldDataMap = createHashMap<{ + dataGroupId: string, + data: SeriesData + }>(); // Map that only store key in array seriesKey. // Which is used to query the old data when transition from one to multiple series. const oldDataMapForSplit = createHashMap<{ key: string, + dataGroupId: string, data: SeriesData }>(); // 处理oldSerieses each(globalStore.oldSeries, (series, idx) => { + const oldDataGroupId = globalStore.oldDataGroupIds[idx] as string; const oldData = globalStore.oldData[idx]; const transitionKey = getSeriesTransitionKey(series); const transitionKeyStr = convertArraySeriesKeyToString(transitionKey); - oldDataMap.set(transitionKeyStr, oldData); + oldDataMap.set(transitionKeyStr, { + dataGroupId: oldDataGroupId, + data: oldData + }); if (isArray(transitionKey)) { // Same key can't in different array seriesKey. each(transitionKey, key => { oldDataMapForSplit.set(key, { - data: oldData, - key: transitionKeyStr + key: transitionKeyStr, + dataGroupId: oldDataGroupId, + data: oldData }); }); } @@ -659,6 +671,7 @@ function findTransitionSeriesBatches( // 处理newSerieses each(params.updatedSeries, series => { if (series.isUniversalTransitionEnabled() && series.isAnimationEnabled()) { + const newDataGroupId = series.get('dataGroupId') as string; const newData = series.getData(); // TODO rename "transitionKey" to "seriesKey" const transitionKey = getSeriesTransitionKey(series); @@ -673,16 +686,18 @@ function findTransitionSeriesBatches( // TODO check if data is same? updateBatches.set(transitionKeyStr, { oldSeries: [{ - divide: getDivideShapeFromData(oldData), - data: oldData + dataGroupId: oldData.dataGroupId, + divide: getDivideShapeFromData(oldData.data), + data: oldData.data }], newSeries: [{ + dataGroupId: newDataGroupId, divide: getDivideShapeFromData(newData), data: newData }] }); } - else { + else { // Transition from multiple series. // e.g. 'female', 'male' -> ['female', 'male'] if (isArray(transitionKey)) { @@ -692,10 +707,11 @@ function findTransitionSeriesBatches( const oldSeries: TransitionSeries[] = []; each(transitionKey, key => { const oldData = oldDataMap.get(key); - if (oldData) { + if (oldData.data) { oldSeries.push({ - divide: getDivideShapeFromData(oldData), - data: oldData + dataGroupId: oldData.dataGroupId, + divide: getDivideShapeFromData(oldData.data), + data: oldData.data }); } }); @@ -703,6 +719,7 @@ function findTransitionSeriesBatches( updateBatches.set(transitionKeyStr, { oldSeries, newSeries: [{ + dataGroupId: newDataGroupId, data: newData, divide: getDivideShapeFromData(newData) }] @@ -718,6 +735,7 @@ function findTransitionSeriesBatches( if (!batch) { batch = { oldSeries: [{ + dataGroupId: oldData.dataGroupId, data: oldData.data, divide: getDivideShapeFromData(oldData.data) }], @@ -726,6 +744,7 @@ function findTransitionSeriesBatches( updateBatches.set(oldData.key, batch); } batch.newSeries.push({ + dataGroupId: newDataGroupId, data: newData, divide: getDivideShapeFromData(newData) }); @@ -760,6 +779,7 @@ function transitionSeriesFromOpt( const 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]), @@ -772,6 +792,7 @@ function transitionSeriesFromOpt( if (idx >= 0) { const data = params.updatedSeries[idx].getData(); to.push({ + dataGroupId: globalStore.oldDataGroupIds[idx], data, divide: getDivideShapeFromData(data), groupIdDim: finder.dimension @@ -832,6 +853,7 @@ export function installUniversalTransition(registers: EChartsExtensionInstallReg // Save all series of current update. Not only the updated one. const allSeries = ecModel.getSeries(); const savedSeries: SeriesModel[] = globalStore.oldSeries = []; + const savedDataGroupIds: string[] = globalStore.oldDataGroupIds = []; const savedData: SeriesData[] = globalStore.oldData = []; for (let i = 0; i < allSeries.length; i++) { const data = allSeries[i].getData(); @@ -839,6 +861,7 @@ export function installUniversalTransition(registers: EChartsExtensionInstallReg // Avoid large data costing too much extra memory if (data.count() < DATA_COUNT_THRESHOLD) { savedSeries.push(allSeries[i]); + savedDataGroupIds.push(allSeries[i].get('dataGroupId') as string); savedData.push(data); } } diff --git a/test/universalTransition2.html b/test/universalTransition2.html index ef3a998a13..33023a0e47 100644 --- a/test/universalTransition2.html +++ b/test/universalTransition2.html @@ -62,9 +62,9 @@ data: ['Animals', 'Fruits', 'Cars'] }, yAxis: {}, - dataGroupId: '', animationDurationUpdate: ANIMATION_DURATION_UPDATE, series: { + dataGroupId: '', type: 'bar', id: 'main', data: [{ From 6e555b7544486c73fffce9abc801f50507778a5a Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Fri, 2 Sep 2022 12:52:49 +0800 Subject: [PATCH 09/24] feat: multiple level drill down (alpha) --- src/animation/universalTransition.ts | 280 ++++++------------ ...iversalTransition-multiLevelDrillDown.html | 2 +- 2 files changed, 94 insertions(+), 188 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 74686d190e..e40716489e 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -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, @@ -47,10 +54,9 @@ interface GlobalStore { oldSeries: SeriesModel[], oldDataGroupIds: string[], old const getUniversalTransitionGlobalStore = makeInner(); interface DiffItem { - dataGroupId: string data: SeriesData - groupIdDim: DimensionLoose - childGroupIdDim: DimensionLoose + groupId: string + childGroupId: string divide: UniversalTransitionOption['divideShape'] dataIndex: number } @@ -61,24 +67,67 @@ interface TransitionSeries { 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]; } } } -function getChildGroupIdDimension(data: SeriesData) { - const dimensions = data.dimensions; - for (let i = 0; i < dimensions.length; i++) { - const dimInfo = data.getDimensionInfo(dimensions[i]); - if (dimInfo && dimInfo.otherDims.childGroupId === 0) { - return dimensions[i]; +// 这个函数是为获取groupId和childGroupId服务的,所以这个value得转成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) { + // 根据encode获取itemGroupID,若有则return + const groupIdDim = getDimension(data, 'itemGroupId'); + if (groupIdDim) { + // TODO 这个“容错”不知道还有没有必要保留 + // const groupIdDim = newGroupIdDim || oldGroupIdDim; + const groupId = getValueByDimension(data, dataIndex, groupIdDim); + if (groupId) { + return groupId; } } + // 根据raw获取groupId,若有则return + const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; + if (itemVal && itemVal.groupId) { + return itemVal.groupId + ''; + } + // 获取series.dataGroupId,若有则return + // 获取dataItem.id + return (dataGroupId || data.getId(dataIndex)); +} + +function getChildGroupId(data: SeriesData, dataIndex: number) { + // 根据encode获取childGroupID,若有则return + const childGroupIdDim = getDimension(data, 'childGroupId'); + if (childGroupIdDim) { + // TODO 这个“容错”不知道还有没有必要保留 + // const childGroupIdDim = newChildGroupIdDim || oldChildGroupIdDim; + const childGroupId = getValueByDimension(data, dataIndex, childGroupIdDim); + if (childGroupId) { + return childGroupId; + } + } + // 根据raw获取childGroupId,若有则return + const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; + if (itemVal && itemVal.childGroupId) { + return itemVal.childGroupId + ''; + } + return undefined; } // flatten all data items from different serieses into one arrary @@ -87,6 +136,7 @@ function flattenDataDiffItems(list: TransitionSeries[]) { 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.'); @@ -94,14 +144,11 @@ function flattenDataDiffItems(list: TransitionSeries[]) { return; } const indices = data.getIndices(); - const groupIdDim = getGroupIdDimension(data); - const childGroupIdDim = getChildGroupIdDimension(data); for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ - dataGroupId: seriesInfo.dataGroupId, data, - groupIdDim: seriesInfo.groupIdDim || groupIdDim, - childGroupIdDim, + groupId: getGroupId(data, dataIndex, dataGroupId), + childGroupId: getChildGroupId(data, dataIndex), divide: seriesInfo.divide, dataIndex }); @@ -199,198 +246,57 @@ function transitionBetween( } } - - function findGroupIdDim(items: DiffItem[]) { - for (let i = 0; i < items.length; i++) { - if (items[i].groupIdDim) { - return items[i].groupIdDim; - } - } - } - - function findChildGroupIdDim(items: DiffItem[]) { - for (let i = 0; i < items.length; i++) { - if (items[i].childGroupIdDim) { - return items[i].childGroupIdDim; - } - } - } - - const oldGroupIdDim = findGroupIdDim(oldDiffItems); - const newGroupIdDim = findGroupIdDim(newDiffItems); - - const oldChildGroupIdDim = findChildGroupIdDim(oldDiffItems); - const newChildGroupIdDim = findChildGroupIdDim(newDiffItems); - let hasMorphAnimation = false; // 在createKeyGetter之前先要确定"父->子"还是"子->父" - const oldGroupIds: string[] = []; - const oldChildGroupIds: string[] = []; - - if (oldGroupIdDim || oldChildGroupIdDim) { - oldDiffItems.forEach((item) => { - item.groupIdDim - && oldGroupIds.push( - '' + item.data.get(item.data.getDimensionInfo(item.groupIdDim).name, item.dataIndex) - ); - item.childGroupIdDim - && oldChildGroupIds.push( - '' + item.data.get(item.data.getDimensionInfo(item.childGroupIdDim).name, item.dataIndex) - ); - }); - } + const oldGroupIds = oldDiffItems.filter((item) => item.groupId !== undefined).map((item) => item.groupId); + const oldChildGroupIds = oldDiffItems + .filter((item) => item.childGroupId !== undefined) + .map((item) => item.childGroupId); + // 若o.childGroupIds中的任意一个等于n.groupIds中的任意一个,则判断为“父->子”方向 // 若o.groupIds中的任意一个等于n.childGroupIds的任意一个,则判断为“子->父”方向 let direction = 'nodirection'; - // TODO 下面的判断方向没有考虑itemGroupId缺失,需要dataGroupId作为groupId的情形 - // 同时也没有考虑没有encode,而是从rawItem拿到groupId和childGroupId的情况 - // 还没考虑nodirection也就是没有childGroupId的情况(undefined) - if (newGroupIdDim || newChildGroupIdDim) { - for (let i = 0; i < newDiffItems.length; i++) { - const newGroupId = - newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].groupIdDim).name, - newDiffItems[i].dataIndex - ) + ''; - if (oldChildGroupIds.includes(newGroupId)) { - direction = 'parent2child'; - break; - } - const newChildGroupId = - newDiffItems[i].data.get( - newDiffItems[i].data.getDimensionInfo(newDiffItems[i].childGroupIdDim).name, - newDiffItems[i].dataIndex - ) + ''; - if (oldGroupIds.includes(newChildGroupId)) { - direction = 'child2parent'; - break; - } + for (let i = 0; i < newDiffItems.length; i++) { + const newGroupId = newDiffItems[i].groupId; + if (oldChildGroupIds.includes(newGroupId)) { + direction = 'parent2child'; + break; + } + const newChildGroupId = newDiffItems[i].childGroupId; + if (newChildGroupId && oldGroupIds.includes(newChildGroupId)) { + direction = 'child2parent'; + break; } } - function createKeyGetterForNew(onlyGetId: boolean) { + function createKeyGetter(isOld: boolean, onlyGetId: boolean) { return function (diffItem: DiffItem): string { const data = diffItem.data; const dataIndex = diffItem.dataIndex; // TODO if specified dim - if (onlyGetId) { // 猜测之前所有需要key的地方用的其实就是dataItem.id, onlyGetId若为true其实就是之前的情况 + 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 (direction === 'parent2child' || direction === 'nodirection') { - // If specified key dimension(itemGroupId by default). Use this same dimension from other data. - // PENDING: If only use key dimension of newData. - const groupIdDim = newGroupIdDim || oldGroupIdDim; - - const dimInfo = groupIdDim && data.getDimensionInfo(groupIdDim); - 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) { + if (direction === 'child2parent' || direction === 'nodirection') { + return diffItem.groupId; } - } - - if (direction === 'child2parent') { - const childGroupIdDim = newChildGroupIdDim || oldChildGroupIdDim; - - const childGroupIdDimInfo = childGroupIdDim && data.getDimensionInfo(childGroupIdDim); - const childGroupIdDimOrdinalMeta = childGroupIdDimInfo && childGroupIdDimInfo.ordinalMeta; - - if (childGroupIdDimInfo) { - // Get from encode.childGroupId. - const key = data.get(childGroupIdDimInfo.name, dataIndex); - if (childGroupIdDimOrdinalMeta) { - return (childGroupIdDimOrdinalMeta.categories[key as number] as string) || key + ''; - } - //console.log(key); - return key + ''; + if (direction === 'parent2child') { + return diffItem.childGroupId; } } - - // Get groupId from raw item. { groupId: '' } - const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; - if (itemVal && itemVal.groupId) { - if (itemVal.childGroupId) { - //console.log(itemVal.childGroupId); - } - return itemVal.groupId + ''; // 注意这个item的return --tyn - } - return (dataGroupId || data.getId(dataIndex)); - }; - } - - function createKeyGetterForOld(onlyGetId: boolean) { - return function (diffItem: DiffItem): string { - const data = diffItem.data; - const dataIndex = diffItem.dataIndex; - // TODO if specified dim - if (onlyGetId) { // 猜测之前所有需要key的地方用的其实就是dataItem.id, onlyGetId若为true其实就是之前的情况 - 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 (direction === 'child2parent' || direction === 'nodirection') { - // If specified key dimension(itemGroupId by default). Use this same dimension from other data. - // PENDING: If only use key dimension of newData. - const groupIdDim = oldGroupIdDim || newGroupIdDim; - - const dimInfo = groupIdDim && data.getDimensionInfo(groupIdDim); - 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 + ''; + else { + if (direction === 'parent2child' || direction === 'nodirection') { + return diffItem.groupId; } - } - - if (direction === 'parent2child') { - const childGroupIdDim = oldChildGroupIdDim || newChildGroupIdDim; - - const childGroupIdDimInfo = childGroupIdDim && data.getDimensionInfo(childGroupIdDim); - const childGroupIdDimOrdinalMeta = childGroupIdDimInfo && childGroupIdDimInfo.ordinalMeta; - - if (childGroupIdDimInfo) { - // Get from encode.childGroupId. - const key = data.get(childGroupIdDimInfo.name, dataIndex); - if (childGroupIdDimOrdinalMeta) { - return (childGroupIdDimOrdinalMeta.categories[key as number] as string) || key + ''; - } - //console.log(key); - return key + ''; + if (direction === 'child2parent') { + return diffItem.childGroupId; } } - - // Get groupId from raw item. { groupId: '' } - const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; - if (itemVal && itemVal.groupId) { - if (itemVal.childGroupId) { - //console.log(itemVal.childGroupId); - } - return itemVal.groupId + ''; // 注意这个item的return --tyn - } - return (dataGroupId || data.getId(dataIndex)); }; } @@ -469,8 +375,8 @@ function transitionBetween( (new DataDiffer( oldDiffItems, newDiffItems, - createKeyGetterForOld(useId), - createKeyGetterForNew(useId), + createKeyGetter(true, useId), + createKeyGetter(false, useId), null, 'multiple' )) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index 951278fb93..18736b297c 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -184,7 +184,7 @@ console.log('Already in root dataGroup!'); } else { console.log('Go back to previous level'); - // myChart.setOption(allOptionsWithItemGroupId[dataGroupIdStack.pop()], true); // Note: the parameter notMerge is set true + // myChart.setOption(allOptionsWithItemGroupId[dataGroupIdStack.pop()], false); // Note: the parameter notMerge is set true myChart.setOption(allOptionsWithItemGroupId[dataGroupIdStack.pop()]); // Note: the parameter notMerge is set true } }; From 9fcbc7c58b132c5e7395e60fe9bf08e449c28f33 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Fri, 2 Sep 2022 16:12:21 +0800 Subject: [PATCH 10/24] refactor: more readable universalTransition-multiLevelDrillDown.html --- ...iversalTransition-multiLevelDrillDown.html | 177 ++++++++---------- 1 file changed, 78 insertions(+), 99 deletions(-) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index 18736b297c..36bfb1cb74 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -41,81 +41,56 @@ From ce89ee778d03b4d4099c601a44f9a52cd2cb74a5 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Fri, 2 Sep 2022 21:48:06 +0800 Subject: [PATCH 11/24] docs: add comments for code --- src/animation/universalTransition.ts | 96 +++++++++++++++++++--------- 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index e40716489e..2bf6f0a374 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -67,6 +67,12 @@ interface TransitionSeries { groupIdDim?: DimensionLoose } +enum TransitionDirection { + None = 'none', + P2C = 'parent -> child', + C2P = 'child -> parent' +} + function getDimension(data: SeriesData, visualDimension: string) { const dimensions = data.dimensions; for (let i = 0; i < dimensions.length; i++) { @@ -77,7 +83,7 @@ function getDimension(data: SeriesData, visualDimension: string) { } } -// 这个函数是为获取groupId和childGroupId服务的,所以这个value得转成string类型 +// 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; @@ -91,42 +97,39 @@ function getValueByDimension(data: SeriesData, dataIndex: number, dimension: Dim } function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string) { - // 根据encode获取itemGroupID,若有则return + // try to get groupId from encode const groupIdDim = getDimension(data, 'itemGroupId'); if (groupIdDim) { - // TODO 这个“容错”不知道还有没有必要保留 - // const groupIdDim = newGroupIdDim || oldGroupIdDim; const groupId = getValueByDimension(data, dataIndex, groupIdDim); if (groupId) { return groupId; } } - // 根据raw获取groupId,若有则return + // try to get groupId from raw data item const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; if (itemVal && itemVal.groupId) { return itemVal.groupId + ''; } - // 获取series.dataGroupId,若有则return - // 获取dataItem.id + // try to use series.dataGroupId as groupId + // if failing to get groupId by all 3 ways above, fallback to data.getId(dataIndex) return (dataGroupId || data.getId(dataIndex)); } function getChildGroupId(data: SeriesData, dataIndex: number) { - // 根据encode获取childGroupID,若有则return + // try to get childGroupId from encode const childGroupIdDim = getDimension(data, 'childGroupId'); if (childGroupIdDim) { - // TODO 这个“容错”不知道还有没有必要保留 - // const childGroupIdDim = newChildGroupIdDim || oldChildGroupIdDim; const childGroupId = getValueByDimension(data, dataIndex, childGroupIdDim); if (childGroupId) { return childGroupId; } } - // 根据raw获取childGroupId,若有则return + // try to get groupId from raw data item const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; if (itemVal && itemVal.childGroupId) { return itemVal.childGroupId + ''; } + // if no childGroupId specified, return undefined return undefined; } @@ -147,8 +150,8 @@ function flattenDataDiffItems(list: TransitionSeries[]) { for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ data, - groupId: getGroupId(data, dataIndex, dataGroupId), - childGroupId: getChildGroupId(data, dataIndex), + groupId: getGroupId(data, dataIndex, dataGroupId), // either of groupId or childGroupId will be used as diffItem's key, + childGroupId: getChildGroupId(data, dataIndex), // depending on the transition direction (see below) divide: seriesInfo.divide, dataIndex }); @@ -248,27 +251,61 @@ function transitionBetween( let hasMorphAnimation = false; - // 在createKeyGetter之前先要确定"父->子"还是"子->父" + /** + * 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 too. This direction is "none". + * + * So basiclly we need to know whether using groupId or childGroupId as key when we get key from + * the keyGetter function. 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 = TransitionDirection.None; + const oldGroupIds = oldDiffItems.filter((item) => item.groupId !== undefined).map((item) => item.groupId); const oldChildGroupIds = oldDiffItems .filter((item) => item.childGroupId !== undefined) .map((item) => item.childGroupId); - - - // 若o.childGroupIds中的任意一个等于n.groupIds中的任意一个,则判断为“父->子”方向 - // 若o.groupIds中的任意一个等于n.childGroupIds的任意一个,则判断为“子->父”方向 - - let direction = 'nodirection'; - for (let i = 0; i < newDiffItems.length; i++) { const newGroupId = newDiffItems[i].groupId; if (oldChildGroupIds.includes(newGroupId)) { - direction = 'parent2child'; + direction = TransitionDirection.P2C; break; } const newChildGroupId = newDiffItems[i].childGroupId; if (newChildGroupId && oldGroupIds.includes(newChildGroupId)) { - direction = 'child2parent'; + direction = TransitionDirection.C2P; break; } } @@ -282,18 +319,18 @@ function transitionBetween( return data.getId(dataIndex); } if (isOld) { - if (direction === 'child2parent' || direction === 'nodirection') { + if (direction === TransitionDirection.C2P || direction === TransitionDirection.None) { return diffItem.groupId; } - if (direction === 'parent2child') { + if (direction === TransitionDirection.P2C) { return diffItem.childGroupId; } } else { - if (direction === 'parent2child' || direction === 'nodirection') { + if (direction === TransitionDirection.P2C || direction === TransitionDirection.None) { return diffItem.groupId; } - if (direction === 'child2parent') { + if (direction === TransitionDirection.C2P) { return diffItem.childGroupId; } } @@ -546,7 +583,6 @@ function findTransitionSeriesBatches( data: SeriesData }>(); - // 处理oldSerieses each(globalStore.oldSeries, (series, idx) => { const oldDataGroupId = globalStore.oldDataGroupIds[idx] as string; const oldData = globalStore.oldData[idx]; @@ -574,15 +610,13 @@ function findTransitionSeriesBatches( warn(`Duplicated seriesKey in universalTransition ${transitionKeyStr}`); } } - // 处理newSerieses each(params.updatedSeries, series => { if (series.isUniversalTransitionEnabled() && series.isAnimationEnabled()) { const newDataGroupId = series.get('dataGroupId') as string; const newData = series.getData(); - // TODO rename "transitionKey" to "seriesKey" const transitionKey = getSeriesTransitionKey(series); const transitionKeyStr = convertArraySeriesKeyToString(transitionKey); - // Only transition between series with same seriesKey. + // Only transition between series with same id. const oldData = oldDataMap.get(transitionKeyStr); // string transition key is the best match. if (oldData) { From b123f35e364398c5fee90d6cfa6dac081bcf9cfc Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 3 Sep 2022 10:27:20 +0800 Subject: [PATCH 12/24] docs: improve comments in test html --- test/universalTransition-multiLevelDrillDown.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index 36bfb1cb74..9920ed6b0c 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -104,8 +104,8 @@ const allOptions = {}; allLevelData.forEach((data) => { - // since this dataItems of all level data in this example has same groupId, - // we can use groupId as optionId for optionStack. + // since dataItems of each data have same groupId in this + // example, we can use groupId as optionId for optionStack. const optionId = data[0][2]; const option = { From 6168f98e2a5651197ff41aa1f694596450798884 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Thu, 22 Sep 2022 21:50:24 +0800 Subject: [PATCH 13/24] docs: update universalTransition-multiLevelDrilldown.html --- ...iversalTransition-multiLevelDrillDown.html | 144 +++++++++++------- 1 file changed, 92 insertions(+), 52 deletions(-) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index 9920ed6b0c..da54c0f2a4 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -41,7 +41,7 @@ From d6895216a071679d069846c4e470068af47c758c Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 15 Oct 2022 22:21:55 +0800 Subject: [PATCH 14/24] revert changes introduced by a merge in mistake --- src/animation/universalTransition.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 8a91af1c85..2bf6f0a374 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -54,7 +54,6 @@ interface GlobalStore { oldSeries: SeriesModel[], oldDataGroupIds: string[], old const getUniversalTransitionGlobalStore = makeInner(); interface DiffItem { - dataGroupId: string data: SeriesData groupId: string childGroupId: string @@ -150,7 +149,6 @@ function flattenDataDiffItems(list: TransitionSeries[]) { const indices = data.getIndices(); for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ - dataGroupId: seriesInfo.dataGroupId, data, groupId: getGroupId(data, dataIndex, dataGroupId), // either of groupId or childGroupId will be used as diffItem's key, childGroupId: getChildGroupId(data, dataIndex), // depending on the transition direction (see below) From 938e4152b3cb636101d7a83b797d50e8d48f6f4c Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 15 Oct 2022 22:46:33 +0800 Subject: [PATCH 15/24] rename `childGroupId` to `itemChildGroupId` to make it consistent with `itemGroupId` --- src/animation/universalTransition.ts | 2 +- src/util/types.ts | 4 ++-- test/universalTransition-multiLevelDrillDown.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 2bf6f0a374..c71ed4318b 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -117,7 +117,7 @@ function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string) { function getChildGroupId(data: SeriesData, dataIndex: number) { // try to get childGroupId from encode - const childGroupIdDim = getDimension(data, 'childGroupId'); + const childGroupIdDim = getDimension(data, 'itemChildGroupId'); if (childGroupIdDim) { const childGroupId = getValueByDimension(data, dataIndex, childGroupIdDim); if (childGroupId) { diff --git a/src/util/types.ts b/src/util/types.ts index 93a1d45416..1a038df762 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -430,7 +430,7 @@ export type DimensionLoose = DimensionName | DimensionIndexLoose; export type DimensionType = DataStoreDimensionType; export const VISUAL_DIMENSIONS = createHashMap([ - 'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'childGroupId', 'seriesName' + 'tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'itemChildGroupId', 'seriesName' ]); // The key is VISUAL_DIMENSIONS export interface DataVisualDimensions { @@ -442,7 +442,7 @@ export interface DataVisualDimensions { itemName?: DimensionIndex; itemId?: DimensionIndex; itemGroupId?: DimensionIndex; - childGroupId?: DimensionIndex; + itemChildGroupId?: DimensionIndex; seriesName?: DimensionIndex; } diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index da54c0f2a4..c6d550d8c0 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -160,7 +160,7 @@ x: 'x', y: 'y', itemGroupId: 'groupId', - childGroupId: 'childGroupId' + itemChildGroupId: 'childGroupId' }, data, universalTransition: { From 8e80c011622a33a4d40545bd9e01aae3f1322a55 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 15 Oct 2022 22:54:24 +0800 Subject: [PATCH 16/24] no need to return undefined, just return --- src/animation/universalTransition.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index c71ed4318b..9e023ffb23 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -129,8 +129,8 @@ function getChildGroupId(data: SeriesData, dataIndex: number) { if (itemVal && itemVal.childGroupId) { return itemVal.childGroupId + ''; } - // if no childGroupId specified, return undefined - return undefined; + // if no childGroupId specified + return; } // flatten all data items from different serieses into one arrary From 55ba82589d41216c331e701723e5b0c6d89a07ce Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 15 Oct 2022 22:59:46 +0800 Subject: [PATCH 17/24] use `!= null` to test if equal to `undefined` or `null` --- src/animation/universalTransition.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 9e023ffb23..6a4c48d1f1 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -293,9 +293,9 @@ function transitionBetween( */ let direction = TransitionDirection.None; - const oldGroupIds = oldDiffItems.filter((item) => item.groupId !== undefined).map((item) => item.groupId); + const oldGroupIds = oldDiffItems.filter((item) => item.groupId != null).map((item) => item.groupId); const oldChildGroupIds = oldDiffItems - .filter((item) => item.childGroupId !== undefined) + .filter((item) => item.childGroupId != null) .map((item) => item.childGroupId); for (let i = 0; i < newDiffItems.length; i++) { const newGroupId = newDiffItems[i].groupId; From ffbc6afaf78a56a428e47997c60b045acea7ee16 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 15 Oct 2022 23:03:49 +0800 Subject: [PATCH 18/24] not use enum, just use const variables --- src/animation/universalTransition.ts | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 6a4c48d1f1..edced6bef2 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -49,6 +49,9 @@ 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(); @@ -67,12 +70,6 @@ interface TransitionSeries { groupIdDim?: DimensionLoose } -enum TransitionDirection { - None = 'none', - P2C = 'parent -> child', - C2P = 'child -> parent' -} - function getDimension(data: SeriesData, visualDimension: string) { const dimensions = data.dimensions; for (let i = 0; i < dimensions.length; i++) { @@ -291,7 +288,7 @@ function transitionBetween( * direction = 'none'; * } */ - let direction = TransitionDirection.None; + let direction = TRANSITION_NONE; const oldGroupIds = oldDiffItems.filter((item) => item.groupId != null).map((item) => item.groupId); const oldChildGroupIds = oldDiffItems @@ -300,12 +297,12 @@ function transitionBetween( for (let i = 0; i < newDiffItems.length; i++) { const newGroupId = newDiffItems[i].groupId; if (oldChildGroupIds.includes(newGroupId)) { - direction = TransitionDirection.P2C; + direction = TRANSITION_P2C; break; } const newChildGroupId = newDiffItems[i].childGroupId; if (newChildGroupId && oldGroupIds.includes(newChildGroupId)) { - direction = TransitionDirection.C2P; + direction = TRANSITION_C2P; break; } } @@ -319,18 +316,18 @@ function transitionBetween( return data.getId(dataIndex); } if (isOld) { - if (direction === TransitionDirection.C2P || direction === TransitionDirection.None) { + if (direction === TRANSITION_C2P || direction === TRANSITION_NONE) { return diffItem.groupId; } - if (direction === TransitionDirection.P2C) { + if (direction === TRANSITION_P2C) { return diffItem.childGroupId; } } else { - if (direction === TransitionDirection.P2C || direction === TransitionDirection.None) { + if (direction === TRANSITION_P2C || direction === TRANSITION_NONE) { return diffItem.groupId; } - if (direction === TransitionDirection.C2P) { + if (direction === TRANSITION_C2P) { return diffItem.childGroupId; } } From 5321c2d8db8988e958f28273633a1eface326415 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sun, 16 Oct 2022 22:32:04 +0800 Subject: [PATCH 19/24] merge `getGroupId` and `getChildGroupId` into one function --- src/animation/universalTransition.ts | 47 +++++++++++----------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index edced6bef2..7ec6b54c86 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -93,9 +93,10 @@ function getValueByDimension(data: SeriesData, dataIndex: number, dimension: Dim } } -function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string) { +function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string, isChild: boolean) { // try to get groupId from encode - const groupIdDim = getDimension(data, 'itemGroupId'); + const visualDimension = isChild ? 'itemChildGroupId' : 'itemGroupId'; + const groupIdDim = getDimension(data, visualDimension); if (groupIdDim) { const groupId = getValueByDimension(data, dataIndex, groupIdDim); if (groupId) { @@ -103,31 +104,19 @@ function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string) { } } // try to get groupId from raw data item - const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; - if (itemVal && itemVal.groupId) { - return itemVal.groupId + ''; + const rawDataItem = data.getRawDataItem(dataIndex) as OptionDataItemObject; + const property = isChild ? 'childGroupId' : 'groupId'; + if (rawDataItem && rawDataItem[property]) { + return rawDataItem[property] + ''; } - // try to use series.dataGroupId as groupId - // if failing to get groupId by all 3 ways above, fallback to data.getId(dataIndex) - return (dataGroupId || data.getId(dataIndex)); -} - -function getChildGroupId(data: SeriesData, dataIndex: number) { - // try to get childGroupId from encode - const childGroupIdDim = getDimension(data, 'itemChildGroupId'); - if (childGroupIdDim) { - const childGroupId = getValueByDimension(data, dataIndex, childGroupIdDim); - if (childGroupId) { - return childGroupId; - } + // fallback + if (isChild) { + return; } - // try to get groupId from raw data item - const itemVal = data.getRawDataItem(dataIndex) as OptionDataItemObject; - if (itemVal && itemVal.childGroupId) { - return itemVal.childGroupId + ''; + else { + // try to use series.dataGroupId as groupId, otherwise use dataItem's id as groupId + return (dataGroupId || data.getId(dataIndex)); } - // if no childGroupId specified - return; } // flatten all data items from different serieses into one arrary @@ -147,8 +136,8 @@ function flattenDataDiffItems(list: TransitionSeries[]) { for (let dataIndex = 0; dataIndex < indices.length; dataIndex++) { items.push({ data, - groupId: getGroupId(data, dataIndex, dataGroupId), // either of groupId or childGroupId will be used as diffItem's key, - childGroupId: getChildGroupId(data, dataIndex), // depending on the transition direction (see below) + 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 }); @@ -273,10 +262,10 @@ function transitionBetween( * 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 too. This direction is "none". + * parent-child relationship exists. This direction is "none". * - * So basiclly we need to know whether using groupId or childGroupId as key when we get key from - * the keyGetter function. Thus, we need to decide the direction first. + * 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: * From dc9a3f68cd4242033fbebb18f05d557b5c05baeb Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Mon, 17 Oct 2022 09:25:12 +0800 Subject: [PATCH 20/24] use createHashMap() to improve performance --- src/animation/universalTransition.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 7ec6b54c86..7f2289bcca 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -279,18 +279,23 @@ function transitionBetween( */ let direction = TRANSITION_NONE; - const oldGroupIds = oldDiffItems.filter((item) => item.groupId != null).map((item) => item.groupId); - const oldChildGroupIds = oldDiffItems - .filter((item) => item.childGroupId != null) - .map((item) => item.childGroupId); + // 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.includes(newGroupId)) { + if (oldChildGroupIds.get(newGroupId)) { direction = TRANSITION_P2C; break; } const newChildGroupId = newDiffItems[i].childGroupId; - if (newChildGroupId && oldGroupIds.includes(newChildGroupId)) { + if (newChildGroupId && oldGroupIds.get(newChildGroupId)) { direction = TRANSITION_C2P; break; } From 6f7a395ac26fb661cebf3e5e16b3fb9bdae52060 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Mon, 17 Oct 2022 15:08:15 +0800 Subject: [PATCH 21/24] add another test case --- ...iversalTransition-multiLevelDrillDown.html | 258 +++++++++++++++++- 1 file changed, 253 insertions(+), 5 deletions(-) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index c6d550d8c0..b1345690b1 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -33,7 +33,8 @@ -
+
+
+ + From edd2d3cf3184aa42bff882eee3fe577a2921cb46 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Mon, 17 Oct 2022 15:17:54 +0800 Subject: [PATCH 22/24] slow down animation update in test cases --- test/universalTransition-multiLevelDrillDown.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index b1345690b1..f48a7bf43d 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -154,7 +154,7 @@ yAxis: { minInterval: 1 }, - animationDurationUpdate: 500, + animationDurationUpdate: ANIMATION_DURATION_UPDATE, series: { type: 'bar', dimensions: ['x', 'y', 'groupId', 'childGroupId'], @@ -309,7 +309,7 @@ minInterval: 1 }, tooltip: {}, - animationDurationUpdate: 500, + animationDurationUpdate: ANIMATION_DURATION_UPDATE, series: { type: 'bar', data: data.map((item) => { @@ -353,7 +353,7 @@ xAxis: { show: false }, yAxis: { show: false }, tooltip: {}, - animationDurationUpdate: 500, + animationDurationUpdate: ANIMATION_DURATION_UPDATE, series: { type: 'pie', data: data.map((item) => { @@ -406,7 +406,7 @@ minInterval: 1 }, tooltip: {}, - animationDurationUpdate: 500, + animationDurationUpdate: ANIMATION_DURATION_UPDATE, series: { type: 'line', data: data.map((item) => { From 9d52862cbc5cdde16a59a83af0e96265ddc4edc9 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Tue, 18 Oct 2022 21:18:02 +0800 Subject: [PATCH 23/24] fix unexpected appearance of xAxis.name after switching options --- test/universalTransition-multiLevelDrillDown.html | 1 + 1 file changed, 1 insertion(+) diff --git a/test/universalTransition-multiLevelDrillDown.html b/test/universalTransition-multiLevelDrillDown.html index f48a7bf43d..7d40d1aafd 100644 --- a/test/universalTransition-multiLevelDrillDown.html +++ b/test/universalTransition-multiLevelDrillDown.html @@ -298,6 +298,7 @@ id: optionId, // option.id is not a property of emyCharts option model, but can be accessed if we provide it xAxis: { show: true, + name: '', type: 'category', data: data.map((item) => item[0]) }, From 3d5b32c4291351fe68c80578ce0a621060d3a7b2 Mon Sep 17 00:00:00 2001 From: Lam Tang Date: Sat, 22 Oct 2022 22:03:33 +0800 Subject: [PATCH 24/24] simplify code --- src/animation/universalTransition.ts | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index 7f2289bcca..c1747bbe7b 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -99,9 +99,7 @@ function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string, is const groupIdDim = getDimension(data, visualDimension); if (groupIdDim) { const groupId = getValueByDimension(data, dataIndex, groupIdDim); - if (groupId) { - return groupId; - } + return groupId; } // try to get groupId from raw data item const rawDataItem = data.getRawDataItem(dataIndex) as OptionDataItemObject; @@ -113,10 +111,8 @@ function getGroupId(data: SeriesData, dataIndex: number, dataGroupId: string, is if (isChild) { return; } - else { - // try to use series.dataGroupId as groupId, otherwise use dataItem's id as groupId - return (dataGroupId || data.getId(dataIndex)); - } + // 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 @@ -310,20 +306,10 @@ function transitionBetween( return data.getId(dataIndex); } if (isOld) { - if (direction === TRANSITION_C2P || direction === TRANSITION_NONE) { - return diffItem.groupId; - } - if (direction === TRANSITION_P2C) { - return diffItem.childGroupId; - } + return direction === TRANSITION_P2C ? diffItem.childGroupId : diffItem.groupId; } else { - if (direction === TRANSITION_P2C || direction === TRANSITION_NONE) { - return diffItem.groupId; - } - if (direction === TRANSITION_C2P) { - return diffItem.childGroupId; - } + return direction === TRANSITION_C2P ? diffItem.childGroupId : diffItem.groupId; } }; }