@@ -51,7 +51,7 @@ import type {
51
51
IMarkStateManager ,
52
52
StateValueType
53
53
} from '../../compile/mark/interface' ;
54
- import { array , degreeToRadian , has , isArray , isBoolean , isFunction , isNil , isObject , isValid } from '@visactor/vutils' ;
54
+ import { array , degreeToRadian , isArray , isBoolean , isFunction , isNil , isObject , isValid } from '@visactor/vutils' ;
55
55
import { curveTypeTransform , groupData , runEncoder } from '../utils/common' ;
56
56
import type { ICompilableInitOption } from '../../compile/interface' ;
57
57
import { LayoutState } from '../../compile/interface' ;
@@ -67,7 +67,8 @@ import type { ICompilableData } from '../../compile/data/interface';
67
67
import type { IAnimationConfig } from '../../animation/interface' ;
68
68
import { AnimationStateEnum , type MarkAnimationSpec } from '../../animation/interface' ;
69
69
import { CompilableData } from '../../compile/data/compilable-data' ;
70
- import { log } from '../../util' ;
70
+ import { getDiffAttributesOfGraphic } from '../../util/mark' ;
71
+ import { log } from '../../util/debug' ;
71
72
import { morph as runMorph } from '../../compile/morph' ;
72
73
73
74
export type ExChannelCall = (
@@ -1074,6 +1075,7 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1074
1075
this . _dataByKey = ( mark as any ) . _dataByKey ;
1075
1076
this . _prevDataByKey = ( mark as any ) . _prevDataByKey ;
1076
1077
this . needClear = ( mark as any ) . needClear ;
1078
+ this . _aniamtionStateCallback = ( mark as any ) . _aniamtionStateCallback ;
1077
1079
}
1078
1080
1079
1081
private _parseProgressiveContext ( data : Datum [ ] ) {
@@ -1145,12 +1147,18 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1145
1147
// TODO 因为数据的覆盖特点,无动画的时候新的更新一定会覆盖前一次的旧值,所以默认都是后面的动画覆盖前面的动画
1146
1148
// TODO 但是如果用户定义了一个动画数组,他的预期是动画不会覆盖,通过priority为INfinity来控制不覆盖
1147
1149
if ( Array . isArray ( config ) ) {
1148
- config = config . map ( ( item : any , index : number ) => ( {
1150
+ return config . map ( ( item : any , index : number ) => ( {
1149
1151
...item ,
1150
1152
priority : item . priority ?? Infinity
1151
1153
} ) ) ;
1152
1154
}
1153
- return config ;
1155
+ return config
1156
+ ? {
1157
+ ...config ,
1158
+ // 循环动画的优先级定为最高,不会被屏蔽掉
1159
+ priority : type === 'normal' ? config . priority ?? Infinity : config . priority
1160
+ }
1161
+ : config ;
1154
1162
}
1155
1163
1156
1164
/**
@@ -1177,6 +1185,7 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1177
1185
if ( ! this . _animationConfig || graphics . length === 0 ) {
1178
1186
return ;
1179
1187
}
1188
+
1180
1189
if ( this . tryRunMorphing ( graphics ) ) {
1181
1190
return ;
1182
1191
}
@@ -1262,10 +1271,29 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1262
1271
}
1263
1272
}
1264
1273
1274
+ protected _setAnimationState ( g : IMarkGraphic ) {
1275
+ const customizedState = this . _aniamtionStateCallback ? this . _aniamtionStateCallback ( g ) : undefined ;
1276
+
1277
+ g . context . animationState = customizedState ?? g . context . diffState ;
1278
+
1279
+ // 复用exit的图元,需要设置属性为最初的属性
1280
+ if ( g . context . animationState === DiffState . exit ) {
1281
+ // 表示正在被复用,后续需要重设属性的
1282
+ g . context . reusing = true ;
1283
+ // 停止所有动画,
1284
+ // TODO:属性可能回不去了(如果enter和exit不是一个动画),所以在encode阶段要获取finalAttribute,设置上去
1285
+ ( g as any ) . animates && ( g as any ) . animates . forEach ( ( a : any ) => a . stop ( ) ) ;
1286
+ // force element to stop exit animation if it is reentered
1287
+ // todo animaiton
1288
+ // const animators = this.animate?.getElementAnimators(element, DiffState.exit);
1289
+ // animators && animators.forEach(animator => animator.stop('start'));
1290
+ }
1291
+ }
1292
+
1265
1293
protected _runJoin ( data : Datum [ ] ) {
1266
1294
const newGroupedData = this . _getDataByKey ( data ) ;
1267
1295
const prevGroupedData = this . _prevDataByKey ;
1268
- const newGraphics : IMarkGraphic [ ] = [ ] ;
1296
+ const allGraphics : IMarkGraphic [ ] = [ ] ;
1269
1297
1270
1298
const enterGraphics = new Set < IMarkGraphic > ( this . _graphics . filter ( g => g . context . diffState === DiffState . enter ) ) ;
1271
1299
@@ -1289,32 +1317,20 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1289
1317
diffState = DiffState . enter ;
1290
1318
g . isExiting = false ;
1291
1319
1292
- // 复用exit的图元,需要设置属性为最初的属性
1293
- if ( g . context ?. diffState === DiffState . exit ) {
1294
- // 表示正在被复用,后续需要重设属性的
1295
- g . context . reusing = true ;
1296
- // 停止所有动画,
1297
- // TODO:属性可能回不去了(如果enter和exit不是一个动画),所以在encode阶段要获取finalAttribute,设置上去
1298
- ( g as any ) . animates && ( g as any ) . animates . forEach ( ( a : any ) => a . stop ( ) ) ;
1299
- // force element to stop exit animation if it is reentered
1300
- // todo animaiton
1301
- // const animators = this.animate?.getElementAnimators(element, DiffState.exit);
1302
- // animators && animators.forEach(animator => animator.stop('start'));
1303
- }
1304
-
1305
1320
this . _graphicMap . set ( key , g as IMarkGraphic ) ;
1306
- newGraphics . push ( g as IMarkGraphic ) ;
1321
+ allGraphics . push ( g as IMarkGraphic ) ;
1307
1322
} else {
1308
1323
// update
1309
1324
g = this . _graphicMap . get ( key ) ;
1310
1325
1311
1326
if ( g ) {
1312
1327
diffState = DiffState . update ;
1313
- newGraphics . push ( g as IMarkGraphic ) ;
1328
+ allGraphics . push ( g ) ;
1314
1329
}
1315
1330
}
1316
1331
1317
1332
if ( g ) {
1333
+ enterGraphics . delete ( g ) ;
1318
1334
g . context = {
1319
1335
...this . _getCommonContext ( ) ,
1320
1336
diffState,
@@ -1328,7 +1344,6 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1328
1344
fieldX : g . context ?. fieldX ,
1329
1345
// 从旧context中继承
1330
1346
fieldY : g . context ?. fieldY ,
1331
- animationState : diffState ,
1332
1347
// TODO 如果newData为空,则使用旧的data,避免exit图元找不到data
1333
1348
data : newData ?? g . context ?. data ,
1334
1349
uniqueKey : key ,
@@ -1338,7 +1353,7 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1338
1353
indexKey : '__VCHART_DEFAULT_DATA_INDEX' ,
1339
1354
stateAnimateConfig : this . getAnimationConfig ( ) ?. state
1340
1355
} ;
1341
- enterGraphics . delete ( g ) ;
1356
+ this . _setAnimationState ( g ) ;
1342
1357
}
1343
1358
return g ;
1344
1359
} ;
@@ -1363,13 +1378,15 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1363
1378
const g = callback ( key , newGroupedData . data . get ( key ) , null ) ;
1364
1379
if ( g ) {
1365
1380
g . context . animationState = AnimationStateEnum . appear ;
1381
+ // this._setAnimationState(g);
1366
1382
}
1367
1383
} ) ;
1368
1384
} else if ( prevGroupedData ) {
1369
1385
prevGroupedData . keys . forEach ( key => {
1370
1386
// disappear
1371
1387
const g = callback ( key , null , prevGroupedData . data . get ( key ) ) ;
1372
1388
g . context . animationState = AnimationStateEnum . disappear ;
1389
+ // this._setAnimationState(g);
1373
1390
} ) ;
1374
1391
}
1375
1392
@@ -1383,13 +1400,13 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1383
1400
1384
1401
( g as IMarkGraphic ) . release ( ) ;
1385
1402
} ) ;
1386
- const graphicCount = newGraphics . length ;
1387
- newGraphics . forEach ( ( g , index ) => {
1403
+ const graphicCount = allGraphics . length ;
1404
+ allGraphics . forEach ( ( g , index ) => {
1388
1405
g . context . graphicCount = graphicCount ;
1389
1406
g . context . graphicIndex = index ;
1390
1407
} ) ;
1391
1408
this . _dataByKey = newGroupedData ;
1392
- this . _graphics = newGraphics ;
1409
+ this . _graphics = allGraphics ;
1393
1410
this . needClear = true ;
1394
1411
}
1395
1412
@@ -1543,14 +1560,7 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1543
1560
this . _graphicMap . set ( g . context . uniqueKey , g ) ;
1544
1561
}
1545
1562
} else {
1546
- // diff一下,获取差异的属性
1547
- const prevAttrs : Record < string , any > = g . getAttributes ( true ) ;
1548
- const diffAttrs : Record < string , any > = { } ;
1549
- Object . keys ( finalAttrs ) . forEach ( key => {
1550
- if ( prevAttrs [ key ] !== finalAttrs [ key ] ) {
1551
- diffAttrs [ key ] = finalAttrs [ key ] ;
1552
- }
1553
- } ) ;
1563
+ const diffAttrs = getDiffAttributesOfGraphic ( g , finalAttrs ) ;
1554
1564
g . context . diffAttrs = diffAttrs ;
1555
1565
if ( g . context . reusing ) {
1556
1566
// 表示正在被复用,需要重设属性的
@@ -1759,29 +1769,30 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1759
1769
}
1760
1770
} ;
1761
1771
this . _graphicMap . forEach ( ( g , key ) => {
1772
+ if ( g . context . diffState !== DiffState . exit || g . isExiting ) {
1773
+ return ;
1774
+ }
1762
1775
// 避免重复执行退场动画
1763
- if ( g . context . diffState === DiffState . exit && ! g . isExiting ) {
1764
- if ( this . hasAnimationByState ( 'exit' ) ) {
1765
- g . isExiting = true ;
1766
- // 执行exit动画
1767
- const animationConfig = this . getAnimationConfig ( ) ;
1768
- if ( ( animationConfig as any ) . exit && ( animationConfig as any ) . exit . length ) {
1769
- const exitConfigList = ( animationConfig as any ) . exit . map ( ( item : any , index : number ) => ( {
1770
- name : `exit_${ index } ` ,
1771
- animation : {
1772
- ...item ,
1773
- customParameters : g . context
1774
- }
1775
- } ) ) ;
1776
- g . applyAnimationState ( [ 'exit' ] , [ exitConfigList . length === 1 ? exitConfigList [ 0 ] : exitConfigList ] , ( ) => {
1777
- // 有可能又被复用了,所以这里需要判断,如果还是在exiting阶段的话才删除
1778
- // TODO 这里如果频繁执行的话,可能会误判
1779
- doRemove ( g , key ) ;
1780
- } ) ;
1781
- }
1782
- } else {
1783
- doRemove ( g , key ) ;
1776
+ if ( g . context . animationState === DiffState . exit && this . hasAnimationByState ( 'exit' ) ) {
1777
+ g . isExiting = true ;
1778
+ // 执行exit动画
1779
+ const animationConfig = this . getAnimationConfig ( ) ;
1780
+ if ( ( animationConfig as any ) . exit && ( animationConfig as any ) . exit . length ) {
1781
+ const exitConfigList = ( animationConfig as any ) . exit . map ( ( item : any , index : number ) => ( {
1782
+ name : `exit_${ index } ` ,
1783
+ animation : {
1784
+ ...item ,
1785
+ customParameters : g . context
1786
+ }
1787
+ } ) ) ;
1788
+ g . applyAnimationState ( [ 'exit' ] , [ exitConfigList . length === 1 ? exitConfigList [ 0 ] : exitConfigList ] , ( ) => {
1789
+ // 有可能又被复用了,所以这里需要判断,如果还是在exiting阶段的话才删除
1790
+ // TODO 这里如果频繁执行的话,可能会误判
1791
+ doRemove ( g , key ) ;
1792
+ } ) ;
1784
1793
}
1794
+ } else {
1795
+ doRemove ( g , key ) ;
1785
1796
}
1786
1797
} ) ;
1787
1798
}
@@ -1966,19 +1977,17 @@ export class BaseMark<T extends ICommonSpec> extends GrammarItem implements IMar
1966
1977
}
1967
1978
}
1968
1979
1980
+ protected _aniamtionStateCallback : ( g : IMarkGraphic ) => AnimationStateValues ;
1981
+
1969
1982
updateAnimationState ( callback : ( graphic : IMarkGraphic ) => AnimationStateValues ) {
1970
- if ( this . _graphics && this . _graphics . length ) {
1971
- this . _graphics . forEach ( g => {
1972
- g . context . animationState = callback ( g ) ;
1973
- } ) ;
1974
- }
1983
+ this . _aniamtionStateCallback = callback ;
1975
1984
}
1976
1985
1977
- hasAnimationByState ( state : keyof MarkAnimationSpec ) {
1978
- if ( ! state || ! this . _animationConfig || ! this . _animationConfig [ state ] ) {
1986
+ hasAnimationByState ( state : AnimationStateValues ) {
1987
+ if ( ! state || ! this . _animationConfig || ! ( this . _animationConfig as any ) [ state ] ) {
1979
1988
return false ;
1980
1989
}
1981
- const stateAnimationConfig = this . _animationConfig [ state ] ;
1990
+ const stateAnimationConfig = ( this . _animationConfig as any ) [ state ] ;
1982
1991
return ( stateAnimationConfig as IAnimationConfig [ ] ) . length > 0 || isObject ( stateAnimationConfig ) ;
1983
1992
}
1984
1993
0 commit comments