@luceosports/play-rendering 2.5.7 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { Color, CourtPoint, Line, LineAnimation, LinePart, LineType, Position } from '../../play-rendering';
1
+ import { Color, CourtPoint, Line, LineAnimation, LinePart, LineType, Position, AnimationMode } from '../../play-rendering';
2
2
 
3
3
  export class LineModel {
4
4
  readonly lineParts: LinePart[];
@@ -14,10 +14,10 @@ export class LineModel {
14
14
  get playerLineSequence(): number;
15
15
  get hideLineTip(): boolean;
16
16
  get animations(): LineAnimation[];
17
- get animationsByEndTime(): number[];
17
+ animationsByEndTime(mode: AnimationMode): number[];
18
18
  get animationKeyTimeChunks(): [number, number][];
19
19
  set animationKeyTimeChunks(value: [number, number][]);
20
- get lastAnimEndTime(): number;
20
+ lastAnimEndTime(mode: AnimationMode): number;
21
21
  get firstLinePartControlPoint(): CourtPoint;
22
22
  get lastLinePartControlPoint(): CourtPoint;
23
23
  }
@@ -1,5 +1,5 @@
1
1
  import { PlayConstructData, PlayData, } from "../../play-rendering";
2
- import { Position } from '../../../src/types';
2
+ import { AnimationMode, Position } from '../../../src/types';
3
3
 
4
4
  export type PlayersMapItem = {
5
5
  position: Position;
@@ -37,6 +37,7 @@ export type PlayModelOptions = {
37
37
  // sub-options for showBallMode
38
38
  highlightPlayerPuck: boolean;
39
39
  showPassLinesDuringPlayback: boolean;
40
+ animationMode: AnimationMode;
40
41
  }
41
42
 
42
43
  export type TeamPlayer = {
@@ -1,4 +1,4 @@
1
- import { Color, CourtPoint, Line, Player, PlayerAnimation, Position } from "../../play-rendering";
1
+ import { Color, CourtPoint, Line, Player, PlayerAnimation, Position, AnimationMode } from "../../play-rendering";
2
2
 
3
3
  export class PlayerModel {
4
4
  constructor(data: Player);
@@ -13,8 +13,8 @@ export class PlayerModel {
13
13
  get location(): CourtPoint;
14
14
  get color(): Color;
15
15
  get animations(): PlayerAnimation[];
16
- get animationsByEndTime(): number[];
17
- get lastAnimEndTime(): number;
16
+ animationsByEndTime(mode: AnimationMode): number[];
17
+ lastAnimEndTime(mode: AnimationMode): number;
18
18
  get lastAnimation(): PlayerAnimation;
19
19
  get lastAnimationLastLinePartControlPoint(): CourtPoint;
20
20
  setPossession(prevPassLines: Line[]): void;
@@ -0,0 +1,4 @@
1
+ export declare enum AnimationMode {
2
+ PREDICTIVE = "PREDICTIVE",
3
+ SEQUENTIAL = "SEQUENTIAL"
4
+ }
@@ -1,142 +1,142 @@
1
- export type PlayerPosition = `${number}`;
2
- export type DefenderPosition = `x${number}`;
3
- export type ExtraPosition = `+${number}`;
4
- export type CoachPosition = 'C';
5
- export type Position = PlayerPosition | DefenderPosition | ExtraPosition | CoachPosition;
6
- export type LineType = 'PASS' | 'CUT' | 'SCREEN' | 'DRIBBLE' | 'HANDOFF' | 'SHOT';
7
- export type LineShapeType = 'LINE.CUT' | 'LINE.SCREEN' | 'LINE.DRIBBLE' | 'LINE.PASS' | 'LINE.HANDOFF';
8
- export type ShapeType = 'CIRCLE' | 'SQUARE' | 'TRIANGLE' | 'FOV' | 'XMARK' | 'STRAIGHT' | 'CONE' | LineShapeType;
9
- export type SportType = 'FOOTBALL' | 'BASKETBALL' | 'VOLLEYBALL' | 'BEACH_VOLLEYBALL' | 'LACROSSE' | 'LACROSSE_BOX' | 'SOCCER' | 'HOCKEY' | 'BASEBALL' | 'SOFTBALL';
10
- export type CourtTypeSportBasketball = 'BIG3' | 'NBA' | 'WNBA' | 'FIBA' | 'NCAAM' | 'NCAAW' | 'US_HIGH_SCHOOL' | 'US_JUNIOR_HIGH';
11
- export type CourtTypeSportVolleyball = 'VOLLEYBALL_INDOOR';
12
- export type CourtTypeSportBeachVolleyball = 'BEACH_VOLLEYBALL_NCAA' | 'BEACH_VOLLEYBALL_RECREATIONAL';
13
- export type CourtTypeSportSoccer = 'SOCCER_FIFA' | 'SOCCER_NCAA' | 'SOCCER_NFHS' | 'SOCCER_U10' | 'SOCCER_U12' | 'SOCCER_U19';
14
- export type CourtTypeSportHockey = 'HOCKEY_NHL' | 'HOCKEY_INTERNATIONAL';
15
- export type CourtTypeSportBaseball = 'BASEBALL_HIGH_SCHOOL';
16
- export type CourtTypeSportSoftball = 'SOFTBALL_FP_COLLEGE' | 'SOFTBALL_FP_HS';
17
- export type CourtTypeSportLacrosse = 'LACROSSE_US_M' | 'LACROSSE_US_W';
18
- export type CourtTypeSportLacrosseBox = 'LACROSSE_BOX_US' | 'LACROSSE_BOX_CLA';
19
- export type CourtTypeSportFootball = 'FOOTBALL_HIGH_SCHOOL' | 'FOOTBALL_COLLEGE' | 'FOOTBALL_NFL';
20
- export type CourtTypeSportFootballLegacy = 'FOOTBALL';
21
- export type CourtType = CourtTypeSportBasketball | CourtTypeSportVolleyball | CourtTypeSportBeachVolleyball | CourtTypeSportLacrosse | CourtTypeSportLacrosseBox | CourtTypeSportSoccer | CourtTypeSportHockey | CourtTypeSportBaseball | CourtTypeSportSoftball | CourtTypeSportFootball | CourtTypeSportFootballLegacy;
22
- export type ShapeControlPoints = [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
23
- export type NoteDisplayModes = ['onCourt'] | ['playNote'] | ['onCourt', 'playNote'];
24
- export interface SportConstants {
25
- PLAYER_TOKEN_RADIUS: number;
26
- PLAYER_TOKEN_SCALE: number;
27
- }
28
- export interface CourtTypeConstants {
29
- COURT_RECT_WIDTH: number;
30
- COURT_RECT_HEIGHT: number;
31
- }
32
- export interface CourtPoint {
33
- x: number;
34
- y: number;
35
- }
36
- export interface CourtSize {
37
- height: number;
38
- width: number;
39
- }
40
- export interface Scale {
41
- x: number;
42
- y: number;
43
- }
44
- export interface LinePart {
45
- controlPoints: [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
46
- }
47
- export interface Color {
48
- red: number;
49
- green: number;
50
- blue: number;
51
- alpha: number;
52
- }
53
- export interface CourtRect {
54
- origin: CourtPoint;
55
- size: CourtSize;
56
- }
57
- export interface Court {
58
- type: CourtType;
59
- courtRect: CourtRect;
60
- }
61
- export type PlayerAnimationType = 'POSITION';
62
- export interface Animation {
63
- id: string;
64
- keyTimes: number[];
65
- }
66
- export interface PlayerAnimation extends Animation {
67
- type: PlayerAnimationType;
68
- lineParts: LinePart[];
69
- }
70
- export interface Player {
71
- id: string;
72
- possession: boolean;
73
- color: Color;
74
- position: Position;
75
- location: CourtPoint;
76
- textOverride?: string;
77
- animations: PlayerAnimation[];
78
- }
79
- export type LineAnimationType = 'LINESTROKE';
80
- export interface LineAnimation {
81
- id: string;
82
- type: LineAnimationType;
83
- keyTimes: number[];
84
- strokeStartValues: [number, number, number];
85
- }
86
- export interface Line {
87
- id: string;
88
- type: LineType;
89
- phase: number;
90
- playerPositionOrigin: Position;
91
- playerPositionTerminus: Position | null;
92
- playerLineSequence: number;
93
- lineParts: LinePart[];
94
- color: Color;
95
- hideLineTip?: boolean;
96
- animations: LineAnimation[];
97
- }
98
- export interface Shape {
99
- id: string;
100
- type: ShapeType;
101
- location: CourtPoint;
102
- color: Color;
103
- scale: Scale;
104
- angle?: number;
105
- showBorder?: boolean;
106
- linePart?: LinePart;
107
- animations?: Animation[];
108
- hideForStatic?: boolean;
109
- }
110
- export interface Note {
111
- id: string;
112
- location: CourtPoint;
113
- displayModes: NoteDisplayModes;
114
- text: string;
115
- animations?: Animation[];
116
- font: NoteFont;
117
- color: Color;
118
- showBorder: boolean;
119
- hideForStatic?: boolean;
120
- }
121
- export interface NoteFont {
122
- bold: boolean;
123
- italic: boolean;
124
- underline: boolean;
125
- strikethrough: boolean;
126
- fontSize: number;
127
- }
128
- export interface PlayConstructData {
129
- id?: string;
130
- lastUpdtTS?: string;
131
- name: string;
132
- playData: PlayData;
133
- }
134
- export interface PlayData {
135
- animationDuration: number;
136
- sport: SportType;
137
- court: Court;
138
- players: Player[];
139
- lines: Line[];
140
- shapes?: Shape[];
141
- notes?: Note[];
142
- }
1
+ export { AnimationMode } from './enums';
2
+ export type PlayerPosition = `${number}`;
3
+ export type DefenderPosition = `x${number}`;
4
+ export type ExtraPosition = `+${number}`;
5
+ export type CoachPosition = 'C';
6
+ export type Position = PlayerPosition | DefenderPosition | ExtraPosition | CoachPosition;
7
+ export type LineType = 'PASS' | 'CUT' | 'SCREEN' | 'DRIBBLE' | 'HANDOFF' | 'SHOT';
8
+ export type LineShapeType = 'LINE.CUT' | 'LINE.SCREEN' | 'LINE.DRIBBLE' | 'LINE.PASS' | 'LINE.HANDOFF';
9
+ export type ShapeType = 'CIRCLE' | 'SQUARE' | 'TRIANGLE' | 'FOV' | 'XMARK' | 'STRAIGHT' | 'CONE' | LineShapeType;
10
+ export type SportType = 'FOOTBALL' | 'BASKETBALL' | 'VOLLEYBALL' | 'BEACH_VOLLEYBALL' | 'LACROSSE' | 'LACROSSE_BOX' | 'SOCCER' | 'HOCKEY' | 'BASEBALL' | 'SOFTBALL';
11
+ export type CourtTypeSportBasketball = 'BIG3' | 'NBA' | 'WNBA' | 'FIBA' | 'NCAAM' | 'NCAAW' | 'US_HIGH_SCHOOL' | 'US_JUNIOR_HIGH';
12
+ export type CourtTypeSportVolleyball = 'VOLLEYBALL_INDOOR';
13
+ export type CourtTypeSportBeachVolleyball = 'BEACH_VOLLEYBALL_NCAA' | 'BEACH_VOLLEYBALL_RECREATIONAL';
14
+ export type CourtTypeSportSoccer = 'SOCCER_FIFA' | 'SOCCER_NCAA' | 'SOCCER_NFHS' | 'SOCCER_U10' | 'SOCCER_U12' | 'SOCCER_U19';
15
+ export type CourtTypeSportHockey = 'HOCKEY_NHL' | 'HOCKEY_INTERNATIONAL';
16
+ export type CourtTypeSportBaseball = 'BASEBALL_HIGH_SCHOOL';
17
+ export type CourtTypeSportSoftball = 'SOFTBALL_FP_COLLEGE' | 'SOFTBALL_FP_HS';
18
+ export type CourtTypeSportLacrosse = 'LACROSSE_US_M' | 'LACROSSE_US_W';
19
+ export type CourtTypeSportLacrosseBox = 'LACROSSE_BOX_US' | 'LACROSSE_BOX_CLA';
20
+ export type CourtTypeSportFootball = 'FOOTBALL_HIGH_SCHOOL' | 'FOOTBALL_COLLEGE' | 'FOOTBALL_NFL';
21
+ export type CourtTypeSportFootballLegacy = 'FOOTBALL';
22
+ export type CourtType = CourtTypeSportBasketball | CourtTypeSportVolleyball | CourtTypeSportBeachVolleyball | CourtTypeSportLacrosse | CourtTypeSportLacrosseBox | CourtTypeSportSoccer | CourtTypeSportHockey | CourtTypeSportBaseball | CourtTypeSportSoftball | CourtTypeSportFootball | CourtTypeSportFootballLegacy;
23
+ export type ShapeControlPoints = [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
24
+ export type NoteDisplayModes = ['onCourt'] | ['playNote'] | ['onCourt', 'playNote'];
25
+ export interface SportConstants {
26
+ PLAYER_TOKEN_RADIUS: number;
27
+ PLAYER_TOKEN_SCALE: number;
28
+ }
29
+ export interface CourtTypeConstants {
30
+ COURT_RECT_WIDTH: number;
31
+ COURT_RECT_HEIGHT: number;
32
+ }
33
+ export interface CourtPoint {
34
+ x: number;
35
+ y: number;
36
+ }
37
+ export interface CourtSize {
38
+ height: number;
39
+ width: number;
40
+ }
41
+ export interface Scale {
42
+ x: number;
43
+ y: number;
44
+ }
45
+ export interface LinePart {
46
+ controlPoints: [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
47
+ }
48
+ export interface Color {
49
+ red: number;
50
+ green: number;
51
+ blue: number;
52
+ alpha: number;
53
+ }
54
+ export interface CourtRect {
55
+ origin: CourtPoint;
56
+ size: CourtSize;
57
+ }
58
+ export interface Court {
59
+ type: CourtType;
60
+ courtRect: CourtRect;
61
+ }
62
+ export type PlayerAnimationType = 'POSITION';
63
+ export interface Animation {
64
+ id: string;
65
+ keyTimes: number[];
66
+ keyTimesSeq?: number[];
67
+ }
68
+ export interface PlayerAnimation extends Animation {
69
+ type: PlayerAnimationType;
70
+ lineParts: LinePart[];
71
+ }
72
+ export interface Player {
73
+ id: string;
74
+ possession: boolean;
75
+ color: Color;
76
+ position: Position;
77
+ location: CourtPoint;
78
+ textOverride?: string;
79
+ animations: PlayerAnimation[];
80
+ }
81
+ export type LineAnimationType = 'LINESTROKE';
82
+ export interface LineAnimation extends Animation {
83
+ type: LineAnimationType;
84
+ strokeStartValues: [number, number, number];
85
+ }
86
+ export interface Line {
87
+ id: string;
88
+ type: LineType;
89
+ phase: number;
90
+ playerPositionOrigin: Position;
91
+ playerPositionTerminus: Position | null;
92
+ playerLineSequence: number;
93
+ lineParts: LinePart[];
94
+ color: Color;
95
+ hideLineTip?: boolean;
96
+ animations: LineAnimation[];
97
+ }
98
+ export interface Shape {
99
+ id: string;
100
+ type: ShapeType;
101
+ location: CourtPoint;
102
+ color: Color;
103
+ scale: Scale;
104
+ angle?: number;
105
+ showBorder?: boolean;
106
+ linePart?: LinePart;
107
+ animations?: Animation[];
108
+ hideForStatic?: boolean;
109
+ }
110
+ export interface Note {
111
+ id: string;
112
+ location: CourtPoint;
113
+ displayModes: NoteDisplayModes;
114
+ text: string;
115
+ animations?: Animation[];
116
+ font: NoteFont;
117
+ color: Color;
118
+ showBorder: boolean;
119
+ hideForStatic?: boolean;
120
+ }
121
+ export interface NoteFont {
122
+ bold: boolean;
123
+ italic: boolean;
124
+ underline: boolean;
125
+ strikethrough: boolean;
126
+ fontSize: number;
127
+ }
128
+ export interface PlayConstructData {
129
+ id?: string;
130
+ lastUpdtTS?: string;
131
+ name: string;
132
+ playData: PlayData;
133
+ }
134
+ export interface PlayData {
135
+ animationDuration: number;
136
+ sport: SportType;
137
+ court: Court;
138
+ players: Player[];
139
+ lines: Line[];
140
+ shapes?: Shape[];
141
+ notes?: Note[];
142
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luceosports/play-rendering",
3
- "version": "2.5.7",
3
+ "version": "2.6.0",
4
4
  "main": "dist/play-rendering.js",
5
5
  "types": "dist/play-rendering.d.ts",
6
6
  "scripts": {
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export * from './types/enums';
2
+
1
3
  import PlayModel from './models/PlayModel';
2
4
  import FrameModel from './models/FrameModel';
3
5
  import AnimationModel from './models/AnimationModel';
@@ -67,22 +67,28 @@ export default class AnimationModel {
67
67
 
68
68
  get linesPhaseIntervals(): Record<number, { min: number; max: number }> {
69
69
  const result: Record<number, { min: number; max: number }> = {};
70
+ const mode = this.play.options.animationMode;
71
+
70
72
  this.play.playData.lines.forEach(line => {
71
73
  if (!result[line.phase]) result[line.phase] = { min: 0, max: 0 };
72
- line.animations.forEach(({ keyTimes }) => {
74
+ line.animations.forEach(animation => {
75
+ const keyTimes = mode === 'SEQUENTIAL' ? animation.keyTimesSeq || [] : animation.keyTimes;
76
+
73
77
  const [from] = keyTimes;
74
78
  const to = [...keyTimes].pop()!;
75
79
  if (from < result[line.phase].min || (!result[line.phase].min && line.phase > 1)) result[line.phase].min = from;
76
80
  if (to > result[line.phase].max) result[line.phase].max = to;
77
81
  });
78
82
  });
83
+
79
84
  return result;
80
85
  }
81
86
 
82
87
  get lastLineAnimationMax() {
88
+ const mode = this.play.options.animationMode;
83
89
  return this.play.playData.lines.reduce<number>((result, line) => {
84
90
  const lineModel = new LineModel(line);
85
- return result > lineModel.lastAnimEndTime! ? result : lineModel.lastAnimEndTime!;
91
+ return result > lineModel.lastAnimEndTime(mode)! ? result : lineModel.lastAnimEndTime(mode)!;
86
92
  }, 0);
87
93
  }
88
94
 
@@ -22,7 +22,7 @@ import {
22
22
  } from '../constants';
23
23
 
24
24
  import PlayModel, { PlayModelOptions, PlayStaticData } from './PlayModel';
25
- import { Court, CourtPoint, ShapeType, SportType } from '../types';
25
+ import { AnimationMode, Court, CourtPoint, SportType } from '../types';
26
26
  import ShapeModel from './ShapeModel';
27
27
 
28
28
  export type FrameData = {
@@ -110,9 +110,10 @@ export default class FrameModel {
110
110
  }
111
111
 
112
112
  get playAnimationDuration() {
113
+ const mode = this.play.options.animationMode;
113
114
  return this.play.playData.lines.reduce<number>((result, l) => {
114
115
  const line = new LineModel(l);
115
- const lineLastAnimEndTime = line.lastAnimEndTime!;
116
+ const lineLastAnimEndTime = line.lastAnimEndTime(mode)!;
116
117
  return result > lineLastAnimEndTime ? result : lineLastAnimEndTime;
117
118
  }, 0);
118
119
  }
@@ -149,7 +150,7 @@ export default class FrameModel {
149
150
 
150
151
  get currentPhasePlayers() {
151
152
  const { currentPhaseLines } = this;
152
- const { huddleMode, magnetMode } = this.play.options;
153
+ const { huddleMode, magnetMode, animationMode } = this.play.options;
153
154
 
154
155
  const lines = huddleMode || magnetMode ? this.playDataLines : this.prevPhaseLines;
155
156
 
@@ -173,7 +174,7 @@ export default class FrameModel {
173
174
 
174
175
  const playerLines = playerCurrentPhaseLines.length ? playerCurrentPhaseLines : playerPrevLines;
175
176
  if (playerLines.length) {
176
- const maxLine = _.maxBy(playerLines, l => l.lastAnimEndTime);
177
+ const maxLine = _.maxBy(playerLines, l => l.lastAnimEndTime(animationMode));
177
178
  if (maxLine) {
178
179
  const lastPoint = maxLine.lastLinePartControlPoint;
179
180
  if (lastPoint) {
@@ -197,6 +198,10 @@ export default class FrameModel {
197
198
 
198
199
  get animationProgressPlayers() {
199
200
  const passLines = this.prevAnimationLines.filter(l => ['PASS', 'HANDOFF', 'SHOT'].includes(l.type));
201
+ const { animationMode } = this.play.options;
202
+
203
+ // TODO MAYBE WE WILL SUSPEND PLAYER ANIMATIONS COMPLETELY AND RELY ONLY ON LINE ANIMATIONS TO HAVE SINGE SOURCE OF TRUTH
204
+
200
205
  return this.play.playData.players.map(p => {
201
206
  const player = new PlayerModel(p);
202
207
  player.setPossession(passLines);
@@ -204,13 +209,16 @@ export default class FrameModel {
204
209
  if (!player.animations.length) return player;
205
210
 
206
211
  player.animations.forEach(animation => {
212
+ const keyTimes =
213
+ animationMode === AnimationMode.SEQUENTIAL ? animation.keyTimesSeq || animation.keyTimes : animation.keyTimes;
214
+
207
215
  const keyTimesChunks: [number, number][] = [];
208
- animation.keyTimes.forEach((value, index) => {
209
- if (index) keyTimesChunks.push([animation.keyTimes[index - 1], value]);
216
+ keyTimes.forEach((value, index) => {
217
+ if (index) keyTimesChunks.push([keyTimes[index - 1], value]);
210
218
  });
219
+
211
220
  keyTimesChunks.forEach(([start, end], index) => {
212
221
  if (_.inRange(this.animationGlobalProgress, start, end)) {
213
- // console.log(`(${player.position}) [${start}-${end}] | a: ${this.animationProgress(start, end)}`);
214
222
  const animProgress = this.animationProgress(start, end);
215
223
  const bezier = new Bezier(
216
224
  ...(animation.lineParts[index].controlPoints as ConstructorParameters<typeof Bezier>)
@@ -223,7 +231,7 @@ export default class FrameModel {
223
231
  });
224
232
  });
225
233
 
226
- if (this.animationGlobalProgress >= player.lastAnimEndTime!) {
234
+ if (this.animationGlobalProgress >= player.lastAnimEndTime(animationMode)!) {
227
235
  player.location = player.lastAnimationLastLinePartControlPoint!;
228
236
  }
229
237
 
@@ -232,13 +240,15 @@ export default class FrameModel {
232
240
  }
233
241
 
234
242
  get animationProgressLines() {
235
- const { linesDisplayOnMoveOnly } = this.play.options;
243
+ const { linesDisplayOnMoveOnly, animationMode } = this.play.options;
244
+
236
245
  return this.play.playData.lines
237
246
  .map(l => {
238
247
  const line = new LineModel(l);
239
248
 
240
249
  line.setAnimationKeyTimesChunked(
241
- this.play.playData.players.find(p => p.position === line.playerPositionOrigin)!
250
+ this.play.playData.players.find(p => p.position === line.playerPositionOrigin)!,
251
+ animationMode
242
252
  );
243
253
 
244
254
  const linePartsAdjusted: LinePartAdjusted[] = [];
@@ -248,6 +258,7 @@ export default class FrameModel {
248
258
  new CustomEvent('@luceosports/play-rendering:lineAnimationFinished', { detail: { id: line.id } })
249
259
  );
250
260
  }
261
+
251
262
  if (_.inRange(this.animationGlobalProgress, start, end)) {
252
263
  if (line.type === 'DRIBBLE') {
253
264
  return linePartsAdjusted.push({ ...line.getLineParts()[index] });
@@ -276,18 +287,25 @@ export default class FrameModel {
276
287
  linePartsAdjusted.push({ ...line.getLineParts()[index] });
277
288
  }
278
289
  });
290
+
279
291
  line.setLinePartsAdjusted(linePartsAdjusted);
280
292
 
281
- if (this.animationGlobalProgress > line.lastAnimEndTime!) {
293
+ if (this.animationGlobalProgress > line.lastAnimEndTime(animationMode)!) {
282
294
  line.color = { ...line.color, alpha: 0.1 }; // To adjust line cap opacity
283
295
  }
284
296
 
285
297
  return line;
286
298
  })
287
299
  .filter(l => {
288
- const [{ keyTimes: firstAnimationKeyTimes }] = l.animations;
289
- const [start] = firstAnimationKeyTimes;
290
- const [end] = firstAnimationKeyTimes.reverse();
300
+ const [firstAnimation] = l.animations;
301
+ const keyTimes =
302
+ animationMode === AnimationMode.SEQUENTIAL
303
+ ? firstAnimation.keyTimesSeq || firstAnimation.keyTimes
304
+ : firstAnimation.keyTimes;
305
+
306
+ const [start] = keyTimes;
307
+ const [end] = [...keyTimes].reverse();
308
+
291
309
  const lineOnMove = _.inRange(this.animationGlobalProgress, start, end);
292
310
  if (linesDisplayOnMoveOnly) return lineOnMove;
293
311
  return lineOnMove || this.animationGlobalProgress > end || l.phase === this.phase;
@@ -305,7 +323,8 @@ export default class FrameModel {
305
323
  }
306
324
 
307
325
  get prevAnimationLines() {
308
- return this.playDataLines.filter(l => this.animationGlobalProgress >= l.lastAnimEndTime!);
326
+ const mode = this.play.options.animationMode;
327
+ return this.playDataLines.filter(l => this.animationGlobalProgress >= l.lastAnimEndTime(mode)!);
309
328
  }
310
329
 
311
330
  draw() {
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import Model from './Base/InternalFrameModel';
3
- import { Line as LineData, LinePart, Player } from '../types';
3
+ import { AnimationMode, Line as LineData, LinePart, Player } from '../types';
4
4
 
5
5
  export type CourtPointAdjusted = { x: number; y: number; time?: number };
6
6
  export type LineAdjusted = LineData & { animationKeyTimeChunks: [number, number][] };
@@ -54,22 +54,29 @@ export default class LineModel extends Model<LineData, LineAdjusted> {
54
54
  }
55
55
  }
56
56
 
57
- setAnimationKeyTimesChunked(linePlayer: Player) {
57
+ setAnimationKeyTimesChunked(linePlayer: Player, mode: AnimationMode) {
58
58
  let keyTimesChunks: [number, number][] = [];
59
- this.animations[0].keyTimes.forEach((value, index) => {
60
- if (index) keyTimesChunks.push([this.animations[0].keyTimes[index - 1], value]);
59
+ const lineKeyTimes = this.getLineAnimationKeyTimes(mode);
60
+
61
+ lineKeyTimes.forEach((value, index) => {
62
+ if (index) keyTimesChunks.push([lineKeyTimes[index - 1], value]);
61
63
  });
62
64
 
63
65
  if (keyTimesChunks.length !== this.getLineParts().length) {
64
66
  const [[start, end]] = keyTimesChunks;
65
67
  const [animation] = linePlayer.animations;
66
- const playerAnimStartIndex = animation.keyTimes.indexOf(start);
67
- const playerAnimEndIndex = animation.keyTimes.indexOf(end);
68
+
69
+ const playerKeyTimes =
70
+ mode === AnimationMode.SEQUENTIAL ? animation.keyTimesSeq || animation.keyTimes : animation.keyTimes;
71
+
72
+ const playerAnimStartIndex = playerKeyTimes.indexOf(start);
73
+ const playerAnimEndIndex = playerKeyTimes.indexOf(end);
74
+
68
75
  if (playerAnimStartIndex >= 0 && playerAnimEndIndex >= 0) {
69
- const lineKeyTimes = animation.keyTimes.slice(playerAnimStartIndex, playerAnimEndIndex + 1);
76
+ const derivedLineKeyTimes = playerKeyTimes.slice(playerAnimStartIndex, playerAnimEndIndex + 1);
70
77
  keyTimesChunks = [];
71
- lineKeyTimes.forEach((value, index) => {
72
- if (index) keyTimesChunks.push([lineKeyTimes[index - 1], value]);
78
+ derivedLineKeyTimes.forEach((value, index) => {
79
+ if (index) keyTimesChunks.push([derivedLineKeyTimes[index - 1], value]);
73
80
  });
74
81
  }
75
82
  }
@@ -132,8 +139,15 @@ export default class LineModel extends Model<LineData, LineAdjusted> {
132
139
  return this._getAttr('animations');
133
140
  }
134
141
 
135
- get animationsByEndTime() {
136
- return this._getAttr('animations').map(a => _.last(a.keyTimes));
142
+ private getLineAnimationKeyTimes(mode: AnimationMode) {
143
+ const a = this.animations[0];
144
+ return mode === AnimationMode.SEQUENTIAL ? a.keyTimesSeq || a.keyTimes : a.keyTimes;
145
+ }
146
+
147
+ animationsByEndTime(mode: AnimationMode) {
148
+ return this._getAttr('animations').map(a =>
149
+ _.last(mode === AnimationMode.SEQUENTIAL ? a.keyTimesSeq || a.keyTimes : a.keyTimes)
150
+ );
137
151
  }
138
152
 
139
153
  get animationKeyTimeChunks() {
@@ -144,8 +158,8 @@ export default class LineModel extends Model<LineData, LineAdjusted> {
144
158
  this._setAttr('animationKeyTimeChunks', value);
145
159
  }
146
160
 
147
- get lastAnimEndTime() {
148
- return _.max(this.animationsByEndTime);
161
+ lastAnimEndTime(mode: AnimationMode) {
162
+ return _.max(this.animationsByEndTime(mode));
149
163
  }
150
164
 
151
165
  get firstLinePartControlPoint() {