@luceosports/play-rendering 2.1.4 → 2.2.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 +2 -2
- package/dist/play-rendering.js.map +1 -1
- package/dist/types/models/PlayModel.d.ts +10 -2
- package/package.json +1 -1
- package/src/layers/NoteLayer.ts +22 -9
- package/src/layers/PlayerLayer.ts +25 -4
- package/src/models/NoteModel.ts +13 -7
- package/src/models/PlayModel.ts +15 -3
|
@@ -30,10 +30,18 @@ export type PlayModelOptions = {
|
|
|
30
30
|
legacyPrintStyle: boolean;
|
|
31
31
|
showHalfCourtCircle: boolean;
|
|
32
32
|
playersMap: PlayersMapItem[];
|
|
33
|
-
labelsOverrideType: 'Headshot' | null;
|
|
33
|
+
labelsOverrideType: 'Initials' | 'Jersey number' | 'Headshot' | null;
|
|
34
34
|
inDrawingState: boolean;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export type TeamPlayer = {
|
|
38
|
+
id: string;
|
|
39
|
+
User_Name: string;
|
|
40
|
+
Initials: string;
|
|
41
|
+
jersey_number: number;
|
|
42
|
+
headshotUrl?: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
37
45
|
export class PlayModel {
|
|
38
46
|
name: string;
|
|
39
47
|
playData: PlayData;
|
|
@@ -42,7 +50,7 @@ export class PlayModel {
|
|
|
42
50
|
static init({ teamLogoPath }?: {
|
|
43
51
|
teamLogoPath?: string;
|
|
44
52
|
}): Promise<void>;
|
|
45
|
-
static
|
|
53
|
+
static setTeamPlayers(data: TeamPlayer[]): Promise<void>
|
|
46
54
|
get totalPhasesCount(): number;
|
|
47
55
|
get scale(): number;
|
|
48
56
|
get width(): number;
|
package/package.json
CHANGED
package/src/layers/NoteLayer.ts
CHANGED
|
@@ -67,7 +67,10 @@ export default class NoteLayer extends BaseLayer {
|
|
|
67
67
|
lines.forEach(({ words }, index) => {
|
|
68
68
|
this.ctx.save();
|
|
69
69
|
|
|
70
|
-
this.ctx.translate(
|
|
70
|
+
this.ctx.translate(
|
|
71
|
+
NoteModel.NOTE_WRAP_PADDING,
|
|
72
|
+
note.fontSize + NoteModel.NOTE_WRAP_PADDING + note.lineHeight * index
|
|
73
|
+
);
|
|
71
74
|
|
|
72
75
|
let wordStartX = 0;
|
|
73
76
|
words.forEach((word, i) => {
|
|
@@ -80,7 +83,17 @@ export default class NoteLayer extends BaseLayer {
|
|
|
80
83
|
|
|
81
84
|
this.ctx.fillStyle = `rgba(0, 0, 0, ${this.animationAlpha})`;
|
|
82
85
|
const wordText = matches.length ? word.text.replace(/(<player=(\d*)>)/gi, '') : word.text;
|
|
83
|
-
this.ctx.fillText(wordText, wordStartX,
|
|
86
|
+
this.ctx.fillText(wordText, wordStartX, -note.baseLineOffset);
|
|
87
|
+
|
|
88
|
+
// BASELINE FOR TESTING
|
|
89
|
+
// this.ctx.save();
|
|
90
|
+
// this.ctx.strokeStyle = 'red';
|
|
91
|
+
// this.ctx.beginPath();
|
|
92
|
+
// this.ctx.moveTo(wordStartX, 0);
|
|
93
|
+
// this.ctx.lineTo(word.width, 0);
|
|
94
|
+
// this.ctx.stroke();
|
|
95
|
+
// this.ctx.restore();
|
|
96
|
+
|
|
84
97
|
wordStartX += word.width;
|
|
85
98
|
if (matches.length) {
|
|
86
99
|
wordStartX -= note.playerTokenRadius * 2;
|
|
@@ -92,7 +105,7 @@ export default class NoteLayer extends BaseLayer {
|
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
if (i !== words.length - 1) {
|
|
95
|
-
this.ctx.fillText(' ', wordStartX,
|
|
108
|
+
this.ctx.fillText(' ', wordStartX, -note.baseLineOffset);
|
|
96
109
|
wordStartX += this.ctx.measureText(' ').width;
|
|
97
110
|
}
|
|
98
111
|
});
|
|
@@ -102,12 +115,12 @@ export default class NoteLayer extends BaseLayer {
|
|
|
102
115
|
this.ctx.strokeStyle = `rgba(0, 0, 0, ${this.animationAlpha})`;
|
|
103
116
|
this.ctx.beginPath();
|
|
104
117
|
if (note.font.underline) {
|
|
105
|
-
this.ctx.moveTo(0, note.
|
|
106
|
-
this.ctx.lineTo(wordStartX, note.
|
|
118
|
+
this.ctx.moveTo(0, note.baseLineOffset);
|
|
119
|
+
this.ctx.lineTo(wordStartX, note.baseLineOffset);
|
|
107
120
|
}
|
|
108
121
|
if (note.font.strikethrough) {
|
|
109
|
-
this.ctx.moveTo(0, note.
|
|
110
|
-
this.ctx.lineTo(wordStartX, note.
|
|
122
|
+
this.ctx.moveTo(0, -note.fontSize / 2 + note.baseLineOffset);
|
|
123
|
+
this.ctx.lineTo(wordStartX, -note.fontSize / 2 + note.baseLineOffset);
|
|
111
124
|
}
|
|
112
125
|
this.ctx.stroke();
|
|
113
126
|
}
|
|
@@ -124,14 +137,14 @@ export default class NoteLayer extends BaseLayer {
|
|
|
124
137
|
this.ctx.beginPath();
|
|
125
138
|
this.ctx.strokeStyle = `rgba(255, 255, 255, ${this.animationAlpha})`;
|
|
126
139
|
this.ctx.fillStyle = `rgba(243, 111, 33, ${this.animationAlpha})`;
|
|
127
|
-
this.ctx.arc(0, note.
|
|
140
|
+
this.ctx.arc(0, -note.fontSize / 2, note.playerTokenRadius, 0, Math.PI * 2);
|
|
128
141
|
this.ctx.fill();
|
|
129
142
|
this.ctx.stroke();
|
|
130
143
|
|
|
131
144
|
const playerFontSize = note.fontSize * 0.8;
|
|
132
145
|
this.ctx.font = `${playerFontSize}px Arial`;
|
|
133
146
|
const textX = -this.ctx.measureText(label).width / 2;
|
|
134
|
-
const textY =
|
|
147
|
+
const textY = -playerFontSize / 4;
|
|
135
148
|
this.ctx.fillStyle = `rgba(255, 255, 255, ${this.animationAlpha})`;
|
|
136
149
|
this.ctx.fillText(label, textX, textY);
|
|
137
150
|
|
|
@@ -102,8 +102,9 @@ export default class PlayerLayer extends BaseLayer {
|
|
|
102
102
|
setPlayerLabel(player: PlayerModel) {
|
|
103
103
|
const { x, y } = player.location;
|
|
104
104
|
|
|
105
|
+
const playerMapItem = this.options.playersMap.find(item => item.position === player.position);
|
|
106
|
+
|
|
105
107
|
if (this.staticData.playerHeadshots && this.options.labelsOverrideType === 'Headshot') {
|
|
106
|
-
const playerMapItem = this.options.playersMap.find(item => item.position === player.position);
|
|
107
108
|
const headshotImage = this.staticData.playerHeadshots.find(item => item.id === playerMapItem?.teamPlayerId);
|
|
108
109
|
|
|
109
110
|
this.ctx.save();
|
|
@@ -148,13 +149,33 @@ export default class PlayerLayer extends BaseLayer {
|
|
|
148
149
|
if (headshotImage) return;
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
let playerTextLabel = player.textLabel;
|
|
153
|
+
if (playerMapItem) {
|
|
154
|
+
if (playerMapItem.textOverride) {
|
|
155
|
+
playerTextLabel = playerMapItem.textOverride;
|
|
156
|
+
}
|
|
157
|
+
if (playerMapItem.teamPlayerId) {
|
|
158
|
+
const teamPlayer = this.staticData.teamPlayers.find(p => p.id === playerMapItem.teamPlayerId);
|
|
159
|
+
if (teamPlayer) {
|
|
160
|
+
const fallbackLabel = teamPlayer.User_Name.split(' ')
|
|
161
|
+
.map(n => n[0])
|
|
162
|
+
.join('')
|
|
163
|
+
.slice(0, 2);
|
|
164
|
+
playerTextLabel = teamPlayer.Initials || fallbackLabel;
|
|
165
|
+
if (this.options.labelsOverrideType === 'Jersey number') {
|
|
166
|
+
playerTextLabel = `${teamPlayer.jersey_number}` || fallbackLabel;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
151
172
|
const { alpha } = player.color;
|
|
152
173
|
|
|
153
|
-
const fontSizeLength = 3 -
|
|
174
|
+
const fontSizeLength = 3 - playerTextLabel.length * 0.5;
|
|
154
175
|
const fontSizeMultiplier = this.options.legacyPrintStyle ? 1.3 : 1;
|
|
155
176
|
const fontSize = fontSizeLength * fontSizeMultiplier * this.playerScale;
|
|
156
177
|
|
|
157
|
-
const textVOffsetLength = 1 -
|
|
178
|
+
const textVOffsetLength = 1 - playerTextLabel.length * 0.15;
|
|
158
179
|
const textVOffsetMultiplier = this.options.legacyPrintStyle ? 1.4 : 1;
|
|
159
180
|
const textVerticalOffset = textVOffsetLength * textVOffsetMultiplier * this.playerScale;
|
|
160
181
|
|
|
@@ -181,7 +202,7 @@ export default class PlayerLayer extends BaseLayer {
|
|
|
181
202
|
this.ctx.rotate(Math.PI); // 180
|
|
182
203
|
}
|
|
183
204
|
|
|
184
|
-
this.ctx.fillText(
|
|
205
|
+
this.ctx.fillText(playerTextLabel, px, py + textVerticalOffset);
|
|
185
206
|
|
|
186
207
|
if (this.options.flipPlayerLabels) {
|
|
187
208
|
this.ctx.restore();
|
package/src/models/NoteModel.ts
CHANGED
|
@@ -2,6 +2,8 @@ import Model from './Base/InternalFrameModel';
|
|
|
2
2
|
import { CourtPoint, Note as NoteData } from '../types';
|
|
3
3
|
|
|
4
4
|
const NOTE_GREY_COLOR = { red: 0.502, green: 0.502, blue: 0.502, alpha: 0.35 };
|
|
5
|
+
const NOTE_LINE_HEIGHT_OFFSET = 0.3;
|
|
6
|
+
const NOTE_BASE_LINE_ALPHABETIC_OFFSET = 0.1;
|
|
5
7
|
|
|
6
8
|
export default class NoteModel extends Model<NoteData, NoteData> {
|
|
7
9
|
private internalCanvas: HTMLCanvasElement;
|
|
@@ -19,10 +21,6 @@ export default class NoteModel extends Model<NoteData, NoteData> {
|
|
|
19
21
|
return 0.43;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
static get NOTE_LINE_HEIGHT_OFFSET() {
|
|
23
|
-
return 0.3;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
24
|
get id() {
|
|
27
25
|
return this._getAttr('id');
|
|
28
26
|
}
|
|
@@ -68,7 +66,15 @@ export default class NoteModel extends Model<NoteData, NoteData> {
|
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
get lineHeight() {
|
|
71
|
-
return this.fontSize +
|
|
69
|
+
return this.fontSize + this.lineHeightOffset;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get lineHeightOffset() {
|
|
73
|
+
return this.fontSize * NOTE_LINE_HEIGHT_OFFSET;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get baseLineOffset() {
|
|
77
|
+
return this.fontSize * NOTE_BASE_LINE_ALPHABETIC_OFFSET;
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
get playerTokenRadius() {
|
|
@@ -85,7 +91,7 @@ export default class NoteModel extends Model<NoteData, NoteData> {
|
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
get textBaseline(): CanvasTextBaseline {
|
|
88
|
-
return '
|
|
94
|
+
return 'alphabetic';
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
get internalCtx(): CanvasRenderingContext2D {
|
|
@@ -100,7 +106,7 @@ export default class NoteModel extends Model<NoteData, NoteData> {
|
|
|
100
106
|
lines,
|
|
101
107
|
box: {
|
|
102
108
|
width: maxLineWidth + NoteModel.NOTE_WRAP_PADDING * 2,
|
|
103
|
-
height: lines.length * this.lineHeight + NoteModel.NOTE_WRAP_PADDING * 2
|
|
109
|
+
height: lines.length * this.lineHeight + NoteModel.NOTE_WRAP_PADDING * 2
|
|
104
110
|
}
|
|
105
111
|
};
|
|
106
112
|
}
|
package/src/models/PlayModel.ts
CHANGED
|
@@ -42,6 +42,7 @@ export type PlayStaticData = {
|
|
|
42
42
|
playerHats: readonly ImageConfigItem[];
|
|
43
43
|
shapes: readonly ImageConfigItem[];
|
|
44
44
|
playerHeadshots: typeof PlayModel.playerHeadshots;
|
|
45
|
+
teamPlayers: typeof PlayModel.teamPlayers;
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
export type PlayersMapItem = {
|
|
@@ -51,6 +52,14 @@ export type PlayersMapItem = {
|
|
|
51
52
|
playerHatKey?: string | null;
|
|
52
53
|
};
|
|
53
54
|
|
|
55
|
+
export type TeamPlayer = {
|
|
56
|
+
id: string;
|
|
57
|
+
User_Name: string;
|
|
58
|
+
Initials: string;
|
|
59
|
+
jersey_number: number;
|
|
60
|
+
headshotUrl?: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
54
63
|
export type PlayModelOptions = {
|
|
55
64
|
width: number;
|
|
56
65
|
lineColor: string;
|
|
@@ -73,7 +82,7 @@ export type PlayModelOptions = {
|
|
|
73
82
|
legacyPrintStyle: boolean;
|
|
74
83
|
showHalfCourtCircle: boolean;
|
|
75
84
|
playersMap: PlayersMapItem[];
|
|
76
|
-
labelsOverrideType: 'Headshot' | null;
|
|
85
|
+
labelsOverrideType: 'Initials' | 'Jersey number' | 'Headshot' | null;
|
|
77
86
|
inDrawingState: boolean;
|
|
78
87
|
};
|
|
79
88
|
|
|
@@ -81,6 +90,7 @@ export default class PlayModel {
|
|
|
81
90
|
public name: string;
|
|
82
91
|
public playData: PlayData;
|
|
83
92
|
public options: PlayModelOptions;
|
|
93
|
+
public static teamPlayers: TeamPlayer[] = [];
|
|
84
94
|
public static playerHeadshots: PlayerHeadshotItem[] = [];
|
|
85
95
|
public static playerHats: readonly ImageConfigItem[];
|
|
86
96
|
public static shapes: readonly ImageConfigItem[];
|
|
@@ -120,7 +130,8 @@ export default class PlayModel {
|
|
|
120
130
|
};
|
|
121
131
|
}
|
|
122
132
|
|
|
123
|
-
static async
|
|
133
|
+
static async setTeamPlayers(data: TeamPlayer[]) {
|
|
134
|
+
PlayModel.teamPlayers = data;
|
|
124
135
|
await Promise.all(
|
|
125
136
|
data.map(async ({ id, headshotUrl }) => {
|
|
126
137
|
try {
|
|
@@ -159,7 +170,8 @@ export default class PlayModel {
|
|
|
159
170
|
watermark: PlayModel.watermark,
|
|
160
171
|
playerHats: PlayModel.playerHats,
|
|
161
172
|
shapes: PlayModel.shapes,
|
|
162
|
-
playerHeadshots: PlayModel.playerHeadshots
|
|
173
|
+
playerHeadshots: PlayModel.playerHeadshots,
|
|
174
|
+
teamPlayers: PlayModel.teamPlayers
|
|
163
175
|
};
|
|
164
176
|
}
|
|
165
177
|
|