@luceosports/play-rendering 2.0.0 → 2.0.2
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/.babelrc +2 -1
- package/dist/play-rendering.js +4 -4
- package/dist/play-rendering.js.map +1 -1
- package/dist/types/models/PlayModel.d.ts +50 -39
- package/dist/types/models/PlayerModel.d.ts +2 -1
- package/package.json +2 -1
- package/src/layers/PlayerLayer.ts +20 -1
- package/src/models/Play/Options.ts +3 -1
- package/src/models/PlayModel.ts +54 -21
- package/src/models/PlayerModel.ts +8 -4
- package/src/models/ShapeModels/{XMarkShape.ts → XmarkShape.ts} +1 -1
- package/src/models/ShapeModels/index.ts +2 -2
- package/src/types/index.ts +0 -1
- package/tsconfig.json +2 -1
- /package/dist/types/models/ShapeModels/{XMarkShape.d.ts → XmarkShape.d.ts} +0 -0
|
@@ -1,40 +1,51 @@
|
|
|
1
|
-
import { PlayConstructData, PlayData
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
import { PlayConstructData, PlayData, } from "../../play-rendering";
|
|
2
|
+
import { Position } from '../../../src/types';
|
|
3
|
+
|
|
4
|
+
export type PlayersMapItem = {
|
|
5
|
+
position: Position;
|
|
6
|
+
textOverride: string | null;
|
|
7
|
+
teamPlayerId: string | null;
|
|
8
|
+
playerHatKey?: string | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type PlayModelOptions = {
|
|
12
|
+
width: number;
|
|
13
|
+
lineColor: string;
|
|
14
|
+
linesDisplay: boolean;
|
|
15
|
+
linesSelectedIds: string[];
|
|
16
|
+
shapeSelectedId: string | null;
|
|
17
|
+
noteSelectedId: string | null;
|
|
18
|
+
playersHiddenPositions?: string[];
|
|
19
|
+
background: string;
|
|
20
|
+
watermark: string | null;
|
|
21
|
+
mirror: boolean;
|
|
22
|
+
speed: number;
|
|
23
|
+
position: string | null;
|
|
24
|
+
huddleMode: boolean;
|
|
25
|
+
magnetMode: boolean;
|
|
26
|
+
playerTokenScale: number;
|
|
27
|
+
flipPlayerLabels: boolean;
|
|
28
|
+
linesDisplayOnMoveOnly: boolean;
|
|
29
|
+
linesHiddenIds: string[];
|
|
30
|
+
legacyPrintStyle: boolean;
|
|
31
|
+
showHalfCourtCircle: boolean;
|
|
32
|
+
playersMap: PlayersMapItem[];
|
|
33
|
+
labelsOverrideType: 'Headshot' | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class PlayModel {
|
|
37
|
+
name: string;
|
|
38
|
+
playData: PlayData;
|
|
39
|
+
options: PlayModelOptions;
|
|
40
|
+
constructor(data: PlayConstructData, options?: Partial<PlayModelOptions>);
|
|
41
|
+
static init({ teamLogoPath }?: {
|
|
42
|
+
teamLogoPath?: string;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
static loadPlayerHeadshots(data: { id: string; headshotUrl?: string | null }[]): Promise<void>
|
|
45
|
+
get totalPhasesCount(): number;
|
|
46
|
+
get scale(): number;
|
|
47
|
+
get width(): number;
|
|
48
|
+
get height(): number;
|
|
49
|
+
setOptions(options: Partial<PlayModelOptions>): void;
|
|
50
|
+
setPlayData(playData: PlayData): void;
|
|
40
51
|
}
|
|
@@ -3,6 +3,8 @@ import { Color, CourtPoint, Line, Player, PlayerAnimation, Position } from "../.
|
|
|
3
3
|
export class PlayerModel {
|
|
4
4
|
constructor(data: Player);
|
|
5
5
|
get id(): string;
|
|
6
|
+
get textOverride(): string;
|
|
7
|
+
set textOverride(data: string);
|
|
6
8
|
get textLabel(): string;
|
|
7
9
|
get isDefender(): boolean;
|
|
8
10
|
get possession(): boolean;
|
|
@@ -10,7 +12,6 @@ export class PlayerModel {
|
|
|
10
12
|
get position(): Position;
|
|
11
13
|
get location(): CourtPoint;
|
|
12
14
|
get color(): Color;
|
|
13
|
-
get playerHatKey(): string;
|
|
14
15
|
get animations(): PlayerAnimation[];
|
|
15
16
|
get animationsByEndTime(): number[];
|
|
16
17
|
get lastAnimEndTime(): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luceosports/play-rendering",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"main": "dist/play-rendering.js",
|
|
5
5
|
"types": "dist/play-rendering.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@babel/core": "^7.18.6",
|
|
24
|
+
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
24
25
|
"@babel/plugin-transform-runtime": "^7.9.0",
|
|
25
26
|
"@babel/preset-env": "^7.9.0",
|
|
26
27
|
"@babel/preset-typescript": "^7.24.6",
|
|
@@ -31,8 +31,9 @@ export default class PlayerLayer extends BaseLayer {
|
|
|
31
31
|
this.setPlayerLabel(player);
|
|
32
32
|
|
|
33
33
|
if (this.staticData.playerHats && this.staticData.playerHats.length) {
|
|
34
|
+
const playerMapItem = this.options.playersMap.find(item => item.position === player.position);
|
|
34
35
|
const playerHat = this.staticData.playerHats.find(hat => {
|
|
35
|
-
return
|
|
36
|
+
return playerMapItem?.playerHatKey ? hat.key === playerMapItem.playerHatKey : false;
|
|
36
37
|
});
|
|
37
38
|
if (playerHat) {
|
|
38
39
|
if (playerHat.reverse === true) {
|
|
@@ -100,6 +101,24 @@ export default class PlayerLayer extends BaseLayer {
|
|
|
100
101
|
|
|
101
102
|
setPlayerLabel(player: PlayerModel) {
|
|
102
103
|
const { x, y } = player.location;
|
|
104
|
+
|
|
105
|
+
if (this.staticData.playerHeadshots && this.options.labelsOverrideType === 'Headshot') {
|
|
106
|
+
const playerMapItem = this.options.playersMap.find(item => item.position === player.position);
|
|
107
|
+
const headshotImage = this.staticData.playerHeadshots.find(item => item.id === playerMapItem?.teamPlayerId);
|
|
108
|
+
if (headshotImage) {
|
|
109
|
+
this.ctx.save();
|
|
110
|
+
this.ctx.translate(x, y);
|
|
111
|
+
if (this.options.flipPlayerLabels === true) {
|
|
112
|
+
this.ctx.rotate(Math.PI);
|
|
113
|
+
}
|
|
114
|
+
this.ctx.arc(0, 0, this.radius, 0, Math.PI * 2, true);
|
|
115
|
+
this.ctx.clip();
|
|
116
|
+
this.ctx.drawImage(headshotImage.image, 0 - this.radius, 0 - this.radius, this.radius * 2, this.radius * 2);
|
|
117
|
+
this.ctx.restore();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
const { alpha } = player.color;
|
|
104
123
|
|
|
105
124
|
const fontSizeLength = 3 - player.textLabel.length * 0.5;
|
|
@@ -22,7 +22,9 @@ export function useDefaults(options?: Partial<PlayModelOptions>): PlayModelOptio
|
|
|
22
22
|
legacyPrintStyle: false,
|
|
23
23
|
playerTokenScale: 1,
|
|
24
24
|
// TODO: refactor NBA court type constants below
|
|
25
|
-
showHalfCourtCircle: true
|
|
25
|
+
showHalfCourtCircle: true,
|
|
26
|
+
playersMap: [],
|
|
27
|
+
labelsOverrideType: null
|
|
26
28
|
};
|
|
27
29
|
return {
|
|
28
30
|
...defaults,
|
package/src/models/PlayModel.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
SPORT_TYPE_VOLLEYBALL
|
|
14
14
|
} from '../constants';
|
|
15
15
|
|
|
16
|
-
import { PlayConstructData, PlayData, SportType } from '../types';
|
|
16
|
+
import { PlayConstructData, PlayData, Position, SportType } from '../types';
|
|
17
17
|
|
|
18
18
|
import hardwoodImageData from '../assets/wood_bg.png';
|
|
19
19
|
import grassImageData from '../assets/grass_bg.png';
|
|
@@ -31,40 +31,56 @@ export type ImageConfigItem = {
|
|
|
31
31
|
reverse?: boolean;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
export type PlayerHeadshotItem = {
|
|
35
|
+
id: string;
|
|
36
|
+
image: HTMLImageElement;
|
|
37
|
+
};
|
|
38
|
+
|
|
34
39
|
export type PlayStaticData = {
|
|
35
40
|
backgroundOptions: typeof PlayModel.backgroundOptions;
|
|
36
41
|
watermark: typeof PlayModel.watermark;
|
|
37
42
|
playerHats: readonly ImageConfigItem[];
|
|
38
43
|
shapes: readonly ImageConfigItem[];
|
|
44
|
+
playerHeadshots: typeof PlayModel.playerHeadshots;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type PlayersMapItem = {
|
|
48
|
+
position: Position;
|
|
49
|
+
textOverride: string | null;
|
|
50
|
+
teamPlayerId: string | null;
|
|
51
|
+
playerHatKey?: string | null;
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
export type PlayModelOptions = {
|
|
42
|
-
width
|
|
43
|
-
lineColor
|
|
44
|
-
linesDisplay
|
|
45
|
-
linesSelectedIds
|
|
46
|
-
shapeSelectedId
|
|
47
|
-
noteSelectedId
|
|
55
|
+
width: number;
|
|
56
|
+
lineColor: string;
|
|
57
|
+
linesDisplay: boolean;
|
|
58
|
+
linesSelectedIds: string[];
|
|
59
|
+
shapeSelectedId: string | null;
|
|
60
|
+
noteSelectedId: string | null;
|
|
48
61
|
playersHiddenPositions?: string[];
|
|
49
|
-
background
|
|
50
|
-
watermark
|
|
51
|
-
mirror
|
|
52
|
-
speed
|
|
53
|
-
position
|
|
54
|
-
huddleMode
|
|
55
|
-
magnetMode
|
|
56
|
-
playerTokenScale
|
|
57
|
-
flipPlayerLabels
|
|
58
|
-
linesDisplayOnMoveOnly
|
|
59
|
-
linesHiddenIds
|
|
60
|
-
legacyPrintStyle
|
|
61
|
-
showHalfCourtCircle
|
|
62
|
+
background: string;
|
|
63
|
+
watermark: string | null;
|
|
64
|
+
mirror: boolean;
|
|
65
|
+
speed: number;
|
|
66
|
+
position: string | null;
|
|
67
|
+
huddleMode: boolean;
|
|
68
|
+
magnetMode: boolean;
|
|
69
|
+
playerTokenScale: number;
|
|
70
|
+
flipPlayerLabels: boolean;
|
|
71
|
+
linesDisplayOnMoveOnly: boolean;
|
|
72
|
+
linesHiddenIds: string[];
|
|
73
|
+
legacyPrintStyle: boolean;
|
|
74
|
+
showHalfCourtCircle: boolean;
|
|
75
|
+
playersMap: PlayersMapItem[];
|
|
76
|
+
labelsOverrideType: 'Headshot' | null;
|
|
62
77
|
};
|
|
63
78
|
|
|
64
79
|
export default class PlayModel {
|
|
65
80
|
public name: string;
|
|
66
81
|
public playData: PlayData;
|
|
67
82
|
public options: PlayModelOptions;
|
|
83
|
+
public static playerHeadshots: PlayerHeadshotItem[] = [];
|
|
68
84
|
public static playerHats: readonly ImageConfigItem[];
|
|
69
85
|
public static shapes: readonly ImageConfigItem[];
|
|
70
86
|
public static watermark: { LuceoSports: HTMLImageElement; TeamLogo: HTMLImageElement };
|
|
@@ -103,6 +119,22 @@ export default class PlayModel {
|
|
|
103
119
|
};
|
|
104
120
|
}
|
|
105
121
|
|
|
122
|
+
static async loadPlayerHeadshots(data: { id: string; headshotUrl?: string | null }[]) {
|
|
123
|
+
await Promise.all(
|
|
124
|
+
data.map(async ({ id, headshotUrl }) => {
|
|
125
|
+
try {
|
|
126
|
+
if (headshotUrl) {
|
|
127
|
+
const image = await loadImage(headshotUrl);
|
|
128
|
+
PlayModel.playerHeadshots.push({ id, image });
|
|
129
|
+
}
|
|
130
|
+
} catch (e) {
|
|
131
|
+
console.error(e);
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
get totalPhasesCount() {
|
|
107
139
|
const distinctPhases = _.uniq(_.map(this.playData.lines, 'phase'));
|
|
108
140
|
return distinctPhases.length || 1;
|
|
@@ -125,7 +157,8 @@ export default class PlayModel {
|
|
|
125
157
|
backgroundOptions: PlayModel.backgroundOptions,
|
|
126
158
|
watermark: PlayModel.watermark,
|
|
127
159
|
playerHats: PlayModel.playerHats,
|
|
128
|
-
shapes: PlayModel.shapes
|
|
160
|
+
shapes: PlayModel.shapes,
|
|
161
|
+
playerHeadshots: PlayModel.playerHeadshots
|
|
129
162
|
};
|
|
130
163
|
}
|
|
131
164
|
|
|
@@ -7,6 +7,14 @@ export default class PlayerModel extends Model<PlayerData, PlayerData> {
|
|
|
7
7
|
return this._getAttr('id');
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
get textOverride() {
|
|
11
|
+
return this._getAttr('textOverride');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
set textOverride(data) {
|
|
15
|
+
this._setAttr('textOverride', data);
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
get textLabel() {
|
|
11
19
|
return this._getAttr('textOverride') || this.position;
|
|
12
20
|
}
|
|
@@ -39,10 +47,6 @@ export default class PlayerModel extends Model<PlayerData, PlayerData> {
|
|
|
39
47
|
return this._getAttr('color');
|
|
40
48
|
}
|
|
41
49
|
|
|
42
|
-
get playerHatKey() {
|
|
43
|
-
return this._getAttr('playerHatKey');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
50
|
get animations() {
|
|
47
51
|
return this._getAttr('animations');
|
|
48
52
|
}
|
|
@@ -11,7 +11,7 @@ import LineShape from './LineShape';
|
|
|
11
11
|
import SquareShape from './SquareShape';
|
|
12
12
|
import StraightShape from './StraightShape';
|
|
13
13
|
import TriangleShape from './TriangleShape';
|
|
14
|
-
import
|
|
14
|
+
import XmarkShape from './XmarkShape';
|
|
15
15
|
|
|
16
16
|
export {
|
|
17
17
|
CutLineShape,
|
|
@@ -26,5 +26,5 @@ export {
|
|
|
26
26
|
SquareShape,
|
|
27
27
|
StraightShape,
|
|
28
28
|
TriangleShape,
|
|
29
|
-
|
|
29
|
+
XmarkShape
|
|
30
30
|
};
|
package/src/types/index.ts
CHANGED
package/tsconfig.json
CHANGED
|
File without changes
|