@luceosports/play-rendering 2.0.7 → 2.1.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 +4 -4
- package/dist/play-rendering.js.map +1 -1
- package/dist/types/models/NoteModel.d.ts +2 -2
- package/dist/types/models/ShapeModel.d.ts +2 -1
- package/dist/types/types/index.d.ts +136 -138
- package/package.json +1 -1
- package/src/helpers/animation.ts +32 -0
- package/src/layers/NoteLayer.ts +12 -43
- package/src/layers/shape/base/InternalShapeLayer.ts +5 -2
- package/src/models/FrameModel.ts +2 -1
- package/src/models/ShapeModel.ts +4 -0
- package/src/types/index.ts +7 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, CourtPoint, Note,
|
|
1
|
+
import { Color, CourtPoint, Note, Animation, NoteFont } from "../../play-rendering";
|
|
2
2
|
|
|
3
3
|
export class NoteModel {
|
|
4
4
|
constructor(data: Note);
|
|
@@ -7,7 +7,7 @@ export class NoteModel {
|
|
|
7
7
|
get location(): CourtPoint;
|
|
8
8
|
get color(): Color;
|
|
9
9
|
get showBorder(): boolean;
|
|
10
|
-
get animations():
|
|
10
|
+
get animations(): Animation[];
|
|
11
11
|
get font(): NoteFont;
|
|
12
12
|
get fontSize(): number;
|
|
13
13
|
get lineHeight(): number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, CourtPoint, LinePart, Scale, Shape, ShapeType } from '../../play-rendering';
|
|
1
|
+
import { Color, CourtPoint, LinePart, Scale, Shape, ShapeType, Animation } from '../../play-rendering';
|
|
2
2
|
|
|
3
3
|
export class ShapeModel {
|
|
4
4
|
constructor(data: Shape)
|
|
@@ -12,6 +12,7 @@ export class ShapeModel {
|
|
|
12
12
|
get showBorder(): boolean;
|
|
13
13
|
get outerCircleRadius(): number;
|
|
14
14
|
get linePart(): LinePart;
|
|
15
|
+
get animations(): Animation[];
|
|
15
16
|
get rectWrapPointsPure(): {
|
|
16
17
|
x: number;
|
|
17
18
|
y: number;
|
|
@@ -1,138 +1,136 @@
|
|
|
1
|
-
export type PlayerPosition = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11';
|
|
2
|
-
export type DefenderPosition = 'x1' | 'x2' | 'x3' | 'x4' | 'x5' | 'x6' | 'x7' | 'x8' | 'x9' | 'x10' | 'x11';
|
|
3
|
-
export type CoachPosition = 'C';
|
|
4
|
-
export type Position = PlayerPosition | DefenderPosition | CoachPosition;
|
|
5
|
-
export type LineType = 'PASS' | 'CUT' | 'SCREEN' | 'DRIBBLE' | 'HANDOFF' | 'SHOT';
|
|
6
|
-
export type LineShapeType = 'LINE.CUT' | 'LINE.SCREEN' | 'LINE.DRIBBLE' | 'LINE.PASS' | 'LINE.HANDOFF';
|
|
7
|
-
export type ShapeType = 'CIRCLE' | 'SQUARE' | 'TRIANGLE' | 'FOV' | 'XMARK' | 'STRAIGHT' | 'CONE' | LineShapeType;
|
|
8
|
-
export type SportType = 'FOOTBALL' | 'BASKETBALL' | 'VOLLEYBALL' | 'LACROSSE' | 'SOCCER' | 'HOCKEY' | 'BASEBALL';
|
|
9
|
-
export type CourtTypeSportBasketball = 'BIG3' | 'NBA' | 'WNBA' | 'FIBA' | 'NCAAM' | 'NCAAW' | 'US_HIGH_SCHOOL' | 'US_JUNIOR_HIGH';
|
|
10
|
-
export type CourtTypeSportVolleyball = 'VOLLEYBALL_INDOOR';
|
|
11
|
-
export type CourtTypeSportSoccer = 'SOCCER_FIFA' | 'SOCCER_NCAA' | 'SOCCER_NFHS' | 'SOCCER_U10' | 'SOCCER_U12' | 'SOCCER_U19';
|
|
12
|
-
export type CourtTypeSportHockey = 'HOCKEY_NHL' | 'HOCKEY_INTERNATIONAL';
|
|
13
|
-
export type CourtTypeSportBaseball = 'BASEBALL_HIGH_SCHOOL';
|
|
14
|
-
export type CourtTypeSportLacrosse = 'LACROSSE_US_M' | 'LACROSSE_US_W';
|
|
15
|
-
export type CourtTypeSportFootball = 'FOOTBALL_HIGH_SCHOOL';
|
|
16
|
-
export type CourtTypeSportFootballLegacy = 'FOOTBALL';
|
|
17
|
-
export type CourtType = CourtTypeSportBasketball | CourtTypeSportVolleyball | CourtTypeSportLacrosse | CourtTypeSportSoccer | CourtTypeSportHockey | CourtTypeSportBaseball | CourtTypeSportFootball | CourtTypeSportFootballLegacy;
|
|
18
|
-
export type ShapeControlPoints = [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
|
|
19
|
-
export type NoteDisplayModes = ['onCourt'] | ['playNote'] | ['onCourt', 'playNote'];
|
|
20
|
-
export interface SportConstants {
|
|
21
|
-
PLAYER_TOKEN_RADIUS: number;
|
|
22
|
-
PLAYER_TOKEN_SCALE: number;
|
|
23
|
-
}
|
|
24
|
-
export interface CourtTypeConstants {
|
|
25
|
-
COURT_RECT_WIDTH: number;
|
|
26
|
-
COURT_RECT_HEIGHT: number;
|
|
27
|
-
}
|
|
28
|
-
export interface CourtPoint {
|
|
29
|
-
x: number;
|
|
30
|
-
y: number;
|
|
31
|
-
}
|
|
32
|
-
export interface CourtSize {
|
|
33
|
-
height: number;
|
|
34
|
-
width: number;
|
|
35
|
-
}
|
|
36
|
-
export interface Scale {
|
|
37
|
-
x: number;
|
|
38
|
-
y: number;
|
|
39
|
-
}
|
|
40
|
-
export interface LinePart {
|
|
41
|
-
controlPoints: [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
|
|
42
|
-
}
|
|
43
|
-
export interface Color {
|
|
44
|
-
red: number;
|
|
45
|
-
green: number;
|
|
46
|
-
blue: number;
|
|
47
|
-
alpha: number;
|
|
48
|
-
}
|
|
49
|
-
export interface CourtRect {
|
|
50
|
-
origin: CourtPoint;
|
|
51
|
-
size: CourtSize;
|
|
52
|
-
}
|
|
53
|
-
export interface Court {
|
|
54
|
-
type: CourtType;
|
|
55
|
-
courtRect: CourtRect;
|
|
56
|
-
}
|
|
57
|
-
export type PlayerAnimationType = 'POSITION';
|
|
58
|
-
export interface
|
|
59
|
-
id: string;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
export
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
notes?: Note[];
|
|
138
|
-
}
|
|
1
|
+
export type PlayerPosition = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11';
|
|
2
|
+
export type DefenderPosition = 'x1' | 'x2' | 'x3' | 'x4' | 'x5' | 'x6' | 'x7' | 'x8' | 'x9' | 'x10' | 'x11';
|
|
3
|
+
export type CoachPosition = 'C';
|
|
4
|
+
export type Position = PlayerPosition | DefenderPosition | CoachPosition;
|
|
5
|
+
export type LineType = 'PASS' | 'CUT' | 'SCREEN' | 'DRIBBLE' | 'HANDOFF' | 'SHOT';
|
|
6
|
+
export type LineShapeType = 'LINE.CUT' | 'LINE.SCREEN' | 'LINE.DRIBBLE' | 'LINE.PASS' | 'LINE.HANDOFF';
|
|
7
|
+
export type ShapeType = 'CIRCLE' | 'SQUARE' | 'TRIANGLE' | 'FOV' | 'XMARK' | 'STRAIGHT' | 'CONE' | LineShapeType;
|
|
8
|
+
export type SportType = 'FOOTBALL' | 'BASKETBALL' | 'VOLLEYBALL' | 'LACROSSE' | 'SOCCER' | 'HOCKEY' | 'BASEBALL';
|
|
9
|
+
export type CourtTypeSportBasketball = 'BIG3' | 'NBA' | 'WNBA' | 'FIBA' | 'NCAAM' | 'NCAAW' | 'US_HIGH_SCHOOL' | 'US_JUNIOR_HIGH';
|
|
10
|
+
export type CourtTypeSportVolleyball = 'VOLLEYBALL_INDOOR';
|
|
11
|
+
export type CourtTypeSportSoccer = 'SOCCER_FIFA' | 'SOCCER_NCAA' | 'SOCCER_NFHS' | 'SOCCER_U10' | 'SOCCER_U12' | 'SOCCER_U19';
|
|
12
|
+
export type CourtTypeSportHockey = 'HOCKEY_NHL' | 'HOCKEY_INTERNATIONAL';
|
|
13
|
+
export type CourtTypeSportBaseball = 'BASEBALL_HIGH_SCHOOL';
|
|
14
|
+
export type CourtTypeSportLacrosse = 'LACROSSE_US_M' | 'LACROSSE_US_W';
|
|
15
|
+
export type CourtTypeSportFootball = 'FOOTBALL_HIGH_SCHOOL';
|
|
16
|
+
export type CourtTypeSportFootballLegacy = 'FOOTBALL';
|
|
17
|
+
export type CourtType = CourtTypeSportBasketball | CourtTypeSportVolleyball | CourtTypeSportLacrosse | CourtTypeSportSoccer | CourtTypeSportHockey | CourtTypeSportBaseball | CourtTypeSportFootball | CourtTypeSportFootballLegacy;
|
|
18
|
+
export type ShapeControlPoints = [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
|
|
19
|
+
export type NoteDisplayModes = ['onCourt'] | ['playNote'] | ['onCourt', 'playNote'];
|
|
20
|
+
export interface SportConstants {
|
|
21
|
+
PLAYER_TOKEN_RADIUS: number;
|
|
22
|
+
PLAYER_TOKEN_SCALE: number;
|
|
23
|
+
}
|
|
24
|
+
export interface CourtTypeConstants {
|
|
25
|
+
COURT_RECT_WIDTH: number;
|
|
26
|
+
COURT_RECT_HEIGHT: number;
|
|
27
|
+
}
|
|
28
|
+
export interface CourtPoint {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
}
|
|
32
|
+
export interface CourtSize {
|
|
33
|
+
height: number;
|
|
34
|
+
width: number;
|
|
35
|
+
}
|
|
36
|
+
export interface Scale {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
}
|
|
40
|
+
export interface LinePart {
|
|
41
|
+
controlPoints: [CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint] | [CourtPoint, CourtPoint, CourtPoint, CourtPoint];
|
|
42
|
+
}
|
|
43
|
+
export interface Color {
|
|
44
|
+
red: number;
|
|
45
|
+
green: number;
|
|
46
|
+
blue: number;
|
|
47
|
+
alpha: number;
|
|
48
|
+
}
|
|
49
|
+
export interface CourtRect {
|
|
50
|
+
origin: CourtPoint;
|
|
51
|
+
size: CourtSize;
|
|
52
|
+
}
|
|
53
|
+
export interface Court {
|
|
54
|
+
type: CourtType;
|
|
55
|
+
courtRect: CourtRect;
|
|
56
|
+
}
|
|
57
|
+
export type PlayerAnimationType = 'POSITION';
|
|
58
|
+
export interface Animation {
|
|
59
|
+
id: string;
|
|
60
|
+
keyTimes: number[];
|
|
61
|
+
}
|
|
62
|
+
export interface PlayerAnimation extends Animation {
|
|
63
|
+
type: PlayerAnimationType;
|
|
64
|
+
lineParts: LinePart[];
|
|
65
|
+
}
|
|
66
|
+
export interface Player {
|
|
67
|
+
id: string;
|
|
68
|
+
possession: boolean;
|
|
69
|
+
color: Color;
|
|
70
|
+
position: Position;
|
|
71
|
+
location: CourtPoint;
|
|
72
|
+
textOverride?: string;
|
|
73
|
+
animations: PlayerAnimation[];
|
|
74
|
+
}
|
|
75
|
+
export type LineAnimationType = 'LINESTROKE';
|
|
76
|
+
export interface LineAnimation {
|
|
77
|
+
id: string;
|
|
78
|
+
type: LineAnimationType;
|
|
79
|
+
keyTimes: number[];
|
|
80
|
+
strokeStartValues: [number, number, number];
|
|
81
|
+
}
|
|
82
|
+
export interface Line {
|
|
83
|
+
id: string;
|
|
84
|
+
type: LineType;
|
|
85
|
+
phase: number;
|
|
86
|
+
playerPositionOrigin: Position;
|
|
87
|
+
playerPositionTerminus: Position | null;
|
|
88
|
+
playerLineSequence: number;
|
|
89
|
+
lineParts: LinePart[];
|
|
90
|
+
color: Color;
|
|
91
|
+
hideLineTip?: boolean;
|
|
92
|
+
animations: LineAnimation[];
|
|
93
|
+
}
|
|
94
|
+
export interface Shape {
|
|
95
|
+
id: string;
|
|
96
|
+
type: ShapeType;
|
|
97
|
+
location: CourtPoint;
|
|
98
|
+
color: Color;
|
|
99
|
+
scale: Scale;
|
|
100
|
+
angle?: number;
|
|
101
|
+
showBorder?: boolean;
|
|
102
|
+
linePart?: LinePart;
|
|
103
|
+
animations: Animation[];
|
|
104
|
+
}
|
|
105
|
+
export interface Note {
|
|
106
|
+
id: string;
|
|
107
|
+
location: CourtPoint;
|
|
108
|
+
displayModes: NoteDisplayModes;
|
|
109
|
+
text: string;
|
|
110
|
+
animations: Animation[];
|
|
111
|
+
font: NoteFont;
|
|
112
|
+
color: Color;
|
|
113
|
+
showBorder: boolean;
|
|
114
|
+
}
|
|
115
|
+
export interface NoteFont {
|
|
116
|
+
bold: boolean;
|
|
117
|
+
italic: boolean;
|
|
118
|
+
underline: boolean;
|
|
119
|
+
strikethrough: boolean;
|
|
120
|
+
fontSize: number;
|
|
121
|
+
}
|
|
122
|
+
export interface PlayConstructData {
|
|
123
|
+
id?: string;
|
|
124
|
+
lastUpdtTS?: string;
|
|
125
|
+
name: string;
|
|
126
|
+
playData: PlayData;
|
|
127
|
+
}
|
|
128
|
+
export interface PlayData {
|
|
129
|
+
animationDuration: number;
|
|
130
|
+
sport: SportType;
|
|
131
|
+
court: Court;
|
|
132
|
+
players: Player[];
|
|
133
|
+
lines: Line[];
|
|
134
|
+
shapes?: Shape[];
|
|
135
|
+
notes?: Note[];
|
|
136
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import NoteModel from '../models/NoteModel';
|
|
2
|
+
import ShapeModel from '../models/ShapeModel';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { FrameDataOptions } from '../models/FrameModel';
|
|
5
|
+
|
|
6
|
+
export function computeAnimationAlpha(model: NoteModel | ShapeModel, options: FrameDataOptions) {
|
|
7
|
+
let alpha = 1;
|
|
8
|
+
if (options.animationGlobalProgress) {
|
|
9
|
+
alpha = 0;
|
|
10
|
+
const animationKeyTimeChunks = model.animations.map(a => {
|
|
11
|
+
const [startPercent, endPercent] = a.keyTimes;
|
|
12
|
+
return [startPercent, endPercent];
|
|
13
|
+
});
|
|
14
|
+
animationKeyTimeChunks.forEach(([start, end]) => {
|
|
15
|
+
const fadeInDuration = 0.03;
|
|
16
|
+
const fadeInStart = start - fadeInDuration;
|
|
17
|
+
const fadeInEnd = start;
|
|
18
|
+
const fadeOutStart = end;
|
|
19
|
+
const fadeOutEnd = end + fadeInDuration;
|
|
20
|
+
if (_.inRange(options.animationGlobalProgress, fadeInStart, fadeInEnd)) {
|
|
21
|
+
alpha = (fadeInDuration - (fadeInEnd - options.animationGlobalProgress)) * 10;
|
|
22
|
+
}
|
|
23
|
+
if (_.inRange(options.animationGlobalProgress, start, end)) {
|
|
24
|
+
alpha = 1;
|
|
25
|
+
}
|
|
26
|
+
if (_.inRange(options.animationGlobalProgress, fadeOutStart, fadeOutEnd)) {
|
|
27
|
+
alpha = (fadeOutEnd - options.animationGlobalProgress) * 10;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return alpha;
|
|
32
|
+
}
|
package/src/layers/NoteLayer.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import BaseLayer from './base/BaseLayer';
|
|
3
2
|
import NoteModel from '../models/NoteModel';
|
|
3
|
+
import { computeAnimationAlpha } from '../helpers/animation';
|
|
4
4
|
|
|
5
5
|
export default class NoteLayer extends BaseLayer {
|
|
6
|
-
private
|
|
6
|
+
private animationAlpha?: number;
|
|
7
7
|
|
|
8
8
|
apply() {
|
|
9
9
|
this.ctx.save();
|
|
@@ -11,7 +11,7 @@ export default class NoteLayer extends BaseLayer {
|
|
|
11
11
|
this.playData.notes.forEach(note => {
|
|
12
12
|
this.ctx.save();
|
|
13
13
|
|
|
14
|
-
this.
|
|
14
|
+
this.animationAlpha = computeAnimationAlpha(note, this.options);
|
|
15
15
|
|
|
16
16
|
this.setColor(note);
|
|
17
17
|
|
|
@@ -30,39 +30,8 @@ export default class NoteLayer extends BaseLayer {
|
|
|
30
30
|
this.ctx.restore();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
setNoteAlpha(note: NoteModel) {
|
|
34
|
-
let alpha = 1;
|
|
35
|
-
if (this.options.animationGlobalProgress) {
|
|
36
|
-
alpha = 0;
|
|
37
|
-
const animationKeyTimeChunks = note.animations.map(a => {
|
|
38
|
-
const [startPercent, endPercent] = a.keyTimes;
|
|
39
|
-
return [
|
|
40
|
-
(this.options.playAnimationDuration / 100) * startPercent * 100,
|
|
41
|
-
(this.options.playAnimationDuration / 100) * endPercent * 100
|
|
42
|
-
];
|
|
43
|
-
});
|
|
44
|
-
animationKeyTimeChunks.forEach(([start, end]) => {
|
|
45
|
-
const fadeInDuration = 0.03;
|
|
46
|
-
const fadeInStart = start - fadeInDuration;
|
|
47
|
-
const fadeInEnd = start;
|
|
48
|
-
const fadeOutStart = end;
|
|
49
|
-
const fadeOutEnd = end + fadeInDuration;
|
|
50
|
-
if (_.inRange(this.options.animationGlobalProgress, fadeInStart, fadeInEnd)) {
|
|
51
|
-
alpha = (fadeInDuration - (fadeInEnd - this.options.animationGlobalProgress)) * 10;
|
|
52
|
-
}
|
|
53
|
-
if (_.inRange(this.options.animationGlobalProgress, start, end)) {
|
|
54
|
-
alpha = 1;
|
|
55
|
-
}
|
|
56
|
-
if (_.inRange(this.options.animationGlobalProgress, fadeOutStart, fadeOutEnd)) {
|
|
57
|
-
alpha = (fadeOutEnd - this.options.animationGlobalProgress) * 10;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
this.noteAlpha = alpha;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
33
|
setColor(note: NoteModel) {
|
|
65
|
-
if (typeof this.
|
|
34
|
+
if (typeof this.animationAlpha === 'undefined') throw new Error('animationAlpha is not set');
|
|
66
35
|
|
|
67
36
|
const { alpha, blue, green, red } = note.color;
|
|
68
37
|
|
|
@@ -70,12 +39,12 @@ export default class NoteLayer extends BaseLayer {
|
|
|
70
39
|
const g = Math.ceil(green * 255);
|
|
71
40
|
const b = Math.ceil(blue * 255);
|
|
72
41
|
|
|
73
|
-
this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha * this.
|
|
74
|
-
this.ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${this.
|
|
42
|
+
this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha * this.animationAlpha})`;
|
|
43
|
+
this.ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${this.animationAlpha})`;
|
|
75
44
|
|
|
76
45
|
if (this.options.noteSelectedId === note.id) {
|
|
77
46
|
this.ctx.setLineDash([0.5, 0.5]);
|
|
78
|
-
this.ctx.strokeStyle = `rgba(28, 127, 181, ${this.
|
|
47
|
+
this.ctx.strokeStyle = `rgba(28, 127, 181, ${this.animationAlpha})`;
|
|
79
48
|
}
|
|
80
49
|
}
|
|
81
50
|
|
|
@@ -109,7 +78,7 @@ export default class NoteLayer extends BaseLayer {
|
|
|
109
78
|
wordStartX += note.playerTokenRadius * 2;
|
|
110
79
|
}
|
|
111
80
|
|
|
112
|
-
this.ctx.fillStyle = `rgba(0, 0, 0, ${this.
|
|
81
|
+
this.ctx.fillStyle = `rgba(0, 0, 0, ${this.animationAlpha})`;
|
|
113
82
|
const wordText = matches.length ? word.text.replace(/(<player=(\d*)>)/gi, '') : word.text;
|
|
114
83
|
this.ctx.fillText(wordText, wordStartX, 0);
|
|
115
84
|
wordStartX += word.width;
|
|
@@ -130,7 +99,7 @@ export default class NoteLayer extends BaseLayer {
|
|
|
130
99
|
|
|
131
100
|
if (note.font.underline || note.font.strikethrough) {
|
|
132
101
|
this.ctx.lineWidth = 0.07 * note.fontSize;
|
|
133
|
-
this.ctx.strokeStyle = `rgba(0, 0, 0, ${this.
|
|
102
|
+
this.ctx.strokeStyle = `rgba(0, 0, 0, ${this.animationAlpha})`;
|
|
134
103
|
this.ctx.beginPath();
|
|
135
104
|
if (note.font.underline) {
|
|
136
105
|
this.ctx.moveTo(0, note.fontSize - NoteModel.NOTE_LINE_HEIGHT_OFFSET / 2);
|
|
@@ -153,8 +122,8 @@ export default class NoteLayer extends BaseLayer {
|
|
|
153
122
|
this.ctx.translate(x + note.playerTokenRadius, 0);
|
|
154
123
|
|
|
155
124
|
this.ctx.beginPath();
|
|
156
|
-
this.ctx.strokeStyle = `rgba(255, 255, 255, ${this.
|
|
157
|
-
this.ctx.fillStyle = `rgba(243, 111, 33, ${this.
|
|
125
|
+
this.ctx.strokeStyle = `rgba(255, 255, 255, ${this.animationAlpha})`;
|
|
126
|
+
this.ctx.fillStyle = `rgba(243, 111, 33, ${this.animationAlpha})`;
|
|
158
127
|
this.ctx.arc(0, note.playerTokenRadius, note.playerTokenRadius, 0, Math.PI * 2);
|
|
159
128
|
this.ctx.fill();
|
|
160
129
|
this.ctx.stroke();
|
|
@@ -163,7 +132,7 @@ export default class NoteLayer extends BaseLayer {
|
|
|
163
132
|
this.ctx.font = `${playerFontSize}px Arial`;
|
|
164
133
|
const textX = -this.ctx.measureText(label).width / 2;
|
|
165
134
|
const textY = ((note.playerTokenRadius * 2 - playerFontSize) / 2) * (1 + NoteModel.NOTE_LINE_HEIGHT_OFFSET);
|
|
166
|
-
this.ctx.fillStyle = `rgba(255, 255, 255, ${this.
|
|
135
|
+
this.ctx.fillStyle = `rgba(255, 255, 255, ${this.animationAlpha})`;
|
|
167
136
|
this.ctx.fillText(label, textX, textY);
|
|
168
137
|
|
|
169
138
|
this.ctx.restore();
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import InternalBaseLayer from '../../base/InternalBaseLayer';
|
|
2
2
|
import ShapeLayer from '../../ShapeLayer';
|
|
3
3
|
import ShapeModel from '../../../models/ShapeModel';
|
|
4
|
+
import { computeAnimationAlpha } from '../../../helpers/animation';
|
|
4
5
|
|
|
5
6
|
const DEBUG_WRAP_POINTS = false;
|
|
6
7
|
|
|
7
8
|
export default class InternalShapeLayer extends InternalBaseLayer {
|
|
8
9
|
protected readonly shape: ShapeModel;
|
|
10
|
+
protected animationAlpha: number;
|
|
9
11
|
|
|
10
12
|
constructor(parentLayer: ShapeLayer, shape: ShapeModel) {
|
|
11
13
|
super(parentLayer);
|
|
12
14
|
this.shape = shape;
|
|
15
|
+
this.animationAlpha = computeAnimationAlpha(shape, parentLayer.options);
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
get staticData() {
|
|
@@ -40,8 +43,8 @@ export default class InternalShapeLayer extends InternalBaseLayer {
|
|
|
40
43
|
const g = Math.ceil(green * 255);
|
|
41
44
|
const b = Math.ceil(blue * 255);
|
|
42
45
|
|
|
43
|
-
this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
44
|
-
this.ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha ?
|
|
46
|
+
this.ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${alpha * this.animationAlpha})`;
|
|
47
|
+
this.ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha ? this.animationAlpha : 0})`;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
drawShapeWrapPoints() {
|
package/src/models/FrameModel.ts
CHANGED
|
@@ -489,8 +489,9 @@ export default class FrameModel {
|
|
|
489
489
|
prepareCourtPoint(courtPoint: CourtPoint) {
|
|
490
490
|
const { mirror } = this.play.options;
|
|
491
491
|
const { width } = this.play.playData.court.courtRect.size;
|
|
492
|
+
const { origin } = this.play.playData.court.courtRect;
|
|
492
493
|
return {
|
|
493
|
-
x: mirror ? width - courtPoint.x : courtPoint.x,
|
|
494
|
+
x: mirror ? width + origin.x - (courtPoint.x - origin.x) : courtPoint.x,
|
|
494
495
|
y: courtPoint.y
|
|
495
496
|
};
|
|
496
497
|
}
|
package/src/models/ShapeModel.ts
CHANGED
|
@@ -49,6 +49,10 @@ export default abstract class ShapeModel extends Model<ShapeData, ShapeData> {
|
|
|
49
49
|
return this._getAttr('linePart');
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
get animations() {
|
|
53
|
+
return this._getAttr('animations') || [];
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
get rectWrapPointsPure() {
|
|
53
57
|
const topLeft = { x: -this.outerCircleRadius / 2, y: -this.outerCircleRadius / 2 };
|
|
54
58
|
const topRight = { x: this.outerCircleRadius / 2, y: -this.outerCircleRadius / 2 };
|
package/src/types/index.ts
CHANGED
|
@@ -112,10 +112,13 @@ export interface Court {
|
|
|
112
112
|
|
|
113
113
|
export type PlayerAnimationType = 'POSITION';
|
|
114
114
|
|
|
115
|
-
export interface
|
|
115
|
+
export interface Animation {
|
|
116
116
|
id: string;
|
|
117
|
-
type: PlayerAnimationType;
|
|
118
117
|
keyTimes: number[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface PlayerAnimation extends Animation {
|
|
121
|
+
type: PlayerAnimationType;
|
|
119
122
|
lineParts: LinePart[];
|
|
120
123
|
}
|
|
121
124
|
|
|
@@ -160,6 +163,7 @@ export interface Shape {
|
|
|
160
163
|
angle?: number;
|
|
161
164
|
showBorder?: boolean;
|
|
162
165
|
linePart?: LinePart;
|
|
166
|
+
animations: Animation[];
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
export interface Note {
|
|
@@ -167,17 +171,12 @@ export interface Note {
|
|
|
167
171
|
location: CourtPoint;
|
|
168
172
|
displayModes: NoteDisplayModes;
|
|
169
173
|
text: string;
|
|
170
|
-
animations:
|
|
174
|
+
animations: Animation[];
|
|
171
175
|
font: NoteFont;
|
|
172
176
|
color: Color;
|
|
173
177
|
showBorder: boolean;
|
|
174
178
|
}
|
|
175
179
|
|
|
176
|
-
export interface NoteAnimation {
|
|
177
|
-
id: string;
|
|
178
|
-
keyTimes: number[];
|
|
179
|
-
}
|
|
180
|
-
|
|
181
180
|
export interface NoteFont {
|
|
182
181
|
bold: boolean;
|
|
183
182
|
italic: boolean;
|