@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.
- package/dist/play-rendering.js +23 -23
- package/dist/play-rendering.js.map +1 -1
- package/dist/types/models/LineModel.d.ts +3 -3
- package/dist/types/models/PlayModel.d.ts +2 -1
- package/dist/types/models/PlayerModel.d.ts +3 -3
- package/dist/types/types/enums.d.ts +4 -0
- package/dist/types/types/index.d.ts +142 -142
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/models/AnimationModel.ts +8 -2
- package/src/models/FrameModel.ts +34 -15
- package/src/models/LineModel.ts +27 -13
- package/src/models/Play/Options.ts +41 -39
- package/src/models/PlayModel.ts +2 -1
- package/src/models/PlayerModel.ts +9 -5
- package/src/types/enums.ts +4 -0
- package/src/types/index.ts +4 -3
|
@@ -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
|
-
|
|
17
|
+
animationsByEndTime(mode: AnimationMode): number[];
|
|
18
18
|
get animationKeyTimeChunks(): [number, number][];
|
|
19
19
|
set animationKeyTimeChunks(value: [number, number][]);
|
|
20
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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;
|
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
export
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
5
|
-
export type
|
|
6
|
-
export type
|
|
7
|
-
export type
|
|
8
|
-
export type
|
|
9
|
-
export type
|
|
10
|
-
export type
|
|
11
|
-
export type
|
|
12
|
-
export type
|
|
13
|
-
export type
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
16
|
-
export type
|
|
17
|
-
export type
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
20
|
-
export type
|
|
21
|
-
export type
|
|
22
|
-
export type
|
|
23
|
-
export type
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
export
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
package/src/index.ts
CHANGED
|
@@ -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(
|
|
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
|
|
package/src/models/FrameModel.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from '../constants';
|
|
23
23
|
|
|
24
24
|
import PlayModel, { PlayModelOptions, PlayStaticData } from './PlayModel';
|
|
25
|
-
import { Court, CourtPoint,
|
|
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
|
-
|
|
209
|
-
if (index) keyTimesChunks.push([
|
|
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 [
|
|
289
|
-
const
|
|
290
|
-
|
|
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
|
-
|
|
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() {
|
package/src/models/LineModel.ts
CHANGED
|
@@ -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.
|
|
60
|
-
|
|
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
|
-
|
|
67
|
-
const
|
|
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
|
|
76
|
+
const derivedLineKeyTimes = playerKeyTimes.slice(playerAnimStartIndex, playerAnimEndIndex + 1);
|
|
70
77
|
keyTimesChunks = [];
|
|
71
|
-
|
|
72
|
-
if (index) keyTimesChunks.push([
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
148
|
-
return _.max(this.animationsByEndTime);
|
|
161
|
+
lastAnimEndTime(mode: AnimationMode) {
|
|
162
|
+
return _.max(this.animationsByEndTime(mode));
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
get firstLinePartControlPoint() {
|