@luceosports/play-rendering 1.10.14 → 1.10.15

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/index.js CHANGED
@@ -3,6 +3,7 @@ module.exports.Frame = require('./src/models/Frame');
3
3
  module.exports.Animation = require('./src/models/Animation');
4
4
  module.exports.Line = require('./src/models/Line');
5
5
  module.exports.Player = require('./src/models/Player');
6
+ module.exports.Note = require('./src/models/Note');
6
7
  module.exports.Shape = require('./src/models/Shape');
7
8
  module.exports.ShapeModels = require('./src/models/ShapeModels');
8
9
  module.exports.LineDrawingMath = require('./src/math/LineDrawingMath');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luceosports/play-rendering",
3
- "version": "1.10.14",
3
+ "version": "1.10.15",
4
4
  "description": "",
5
5
  "main": "dist/play-rendering.js",
6
6
  "scripts": {
@@ -0,0 +1,187 @@
1
+ const BaseLayer = require('./base/BaseLayer');
2
+
3
+ const BOX_MAX_WIDTH = 250;
4
+ const FONT_SIZE = 14;
5
+ const LINE_HEIGHT_OFFSET = 4;
6
+ const BOX_PADDING = 6;
7
+ const PLAYER_TOKEN_RADIUS = 10;
8
+
9
+ class NoteLayer extends BaseLayer {
10
+ get boxMaxWidth() {
11
+ return this.scale(BOX_MAX_WIDTH);
12
+ }
13
+
14
+ get boxPadding() {
15
+ return this.scale(BOX_PADDING);
16
+ }
17
+
18
+ get fontSize() {
19
+ return this.scale(FONT_SIZE);
20
+ }
21
+
22
+ get spaceWidth() {
23
+ return this.ctx.measureText(' ').width;
24
+ }
25
+
26
+ get lineHeight() {
27
+ return this.scale(FONT_SIZE + LINE_HEIGHT_OFFSET);
28
+ }
29
+
30
+ get lineHeightOffset() {
31
+ return this.scale(LINE_HEIGHT_OFFSET);
32
+ }
33
+
34
+ get playerTokenRadius() {
35
+ return this.scale(PLAYER_TOKEN_RADIUS);
36
+ }
37
+
38
+ apply() {
39
+ this.ctx.save();
40
+
41
+ this.ctx.lineWidth = this.courtTypeConstants.COURT_LINE_WIDTH;
42
+
43
+ this.setColor();
44
+
45
+ this.playData.notes.forEach(note => {
46
+ const { location } = note;
47
+ this.ctx.translate(location.x, location.y);
48
+
49
+ this.setFont(note);
50
+
51
+ const { lines, box } = this.preProcessText(note);
52
+ this.drawBubble(box);
53
+ this.drawText(lines);
54
+ });
55
+
56
+ this.ctx.restore();
57
+ }
58
+
59
+ setColor() {
60
+ this.ctx.fillStyle = `rgba(0, 133, 133, 0.5)`;
61
+ this.ctx.strokeStyle = `rgba(0, 133, 133, 1)`;
62
+ }
63
+
64
+ setFont() {
65
+ this.ctx.font = `${this.fontSize}px Arial`;
66
+ this.ctx.textBaseline = 'top';
67
+ }
68
+
69
+ preProcessText(note) {
70
+ const fitWidth = this.boxMaxWidth - this.boxPadding * 2;
71
+ const lines = this.getLines(note.text, fitWidth);
72
+ const maxLineWidth = lines.reduce((a, b) => (a.width > b.width ? a : b)).width;
73
+ return {
74
+ lines,
75
+ box: {
76
+ width: maxLineWidth + this.boxPadding * 2,
77
+ height: lines.length * this.lineHeight + this.boxPadding * 2 - this.lineHeightOffset
78
+ }
79
+ };
80
+ }
81
+
82
+ getLines(text, fitWidth) {
83
+ const getLineInfo = inputWords => {
84
+ let lineWidth = 0;
85
+ const wordsResult = [];
86
+ inputWords.forEach((w, i) => {
87
+ const matches = [...w.matchAll(/(<player=(\d*)>)/gi)];
88
+ const wordProcessed = {
89
+ text: w,
90
+ width: matches.length
91
+ ? this.ctx.measureText(w.replace(/<player=(\d*)>/, '')).width + this.playerTokenRadius * 2
92
+ : this.ctx.measureText(w).width
93
+ };
94
+ lineWidth += wordProcessed.width;
95
+ if (i !== inputWords.length - 1) {
96
+ lineWidth += this.spaceWidth;
97
+ }
98
+ wordsResult.push(wordProcessed);
99
+ });
100
+ return { words: wordsResult, width: lineWidth };
101
+ };
102
+
103
+ const lines = [];
104
+ const words = text.split(' ');
105
+ let wordIndex = 1;
106
+ while (words.length > 0) {
107
+ const wordsForIndex = words.slice(0, wordIndex);
108
+ if (getLineInfo(wordsForIndex).width < fitWidth && wordIndex <= words.length) {
109
+ wordIndex++;
110
+ continue;
111
+ }
112
+ if (wordIndex !== 1) wordIndex--;
113
+ lines.push(getLineInfo(words.splice(0, wordIndex)));
114
+ wordIndex = 1;
115
+ }
116
+ return lines;
117
+ }
118
+
119
+ drawBubble({ width, height }) {
120
+ this.ctx.beginPath();
121
+ this.ctx.rect(0, 0, width, height);
122
+ this.ctx.fill();
123
+ this.ctx.stroke();
124
+ }
125
+
126
+ drawText(lines) {
127
+ lines.forEach(({ words }, index) => {
128
+ this.ctx.save();
129
+
130
+ this.ctx.translate(this.boxPadding, this.boxPadding + this.lineHeight * index);
131
+
132
+ let wordStartX = 0;
133
+ words.forEach((word, i) => {
134
+ const matches = [...word.text.matchAll(/(<player=(\d*)>)/gi)];
135
+
136
+ if (matches.length && matches[0].index === 0) {
137
+ this.drawPlayerToken(wordStartX, matches[0][2]);
138
+ wordStartX += this.playerTokenRadius * 2;
139
+ }
140
+
141
+ this.ctx.fillStyle = '#000';
142
+ const wordText = matches.length ? word.text.replace(/(<player=(\d*)>)/gi, '') : word.text;
143
+ this.ctx.fillText(wordText, wordStartX, 0);
144
+ wordStartX += word.width;
145
+ if (matches.length) {
146
+ wordStartX -= this.playerTokenRadius * 2;
147
+ }
148
+
149
+ if (matches.length && matches[0].index > 0) {
150
+ this.drawPlayerToken(wordStartX, matches[0][2]);
151
+ wordStartX += this.playerTokenRadius * 2;
152
+ }
153
+
154
+ if (i !== words.length - 1) {
155
+ this.ctx.fillText(' ', wordStartX, 0);
156
+ wordStartX += this.spaceWidth;
157
+ }
158
+ });
159
+
160
+ this.ctx.restore();
161
+ });
162
+ }
163
+
164
+ drawPlayerToken(x, label) {
165
+ this.ctx.save();
166
+
167
+ this.ctx.translate(x + this.playerTokenRadius, 0);
168
+
169
+ this.ctx.beginPath();
170
+ this.ctx.strokeStyle = '#ffffff';
171
+ this.ctx.fillStyle = '#f36f21';
172
+ this.ctx.arc(0, this.fontSize / 2, this.playerTokenRadius, 0, Math.PI * 2);
173
+ this.ctx.fill();
174
+ this.ctx.stroke();
175
+
176
+ this.ctx.fillStyle = '#ffffff';
177
+ this.ctx.fillText(label, -this.ctx.measureText(label).width / 2, 0);
178
+
179
+ this.ctx.restore();
180
+ }
181
+
182
+ scale(value) {
183
+ return value / this.options.scale;
184
+ }
185
+ }
186
+
187
+ module.exports = NoteLayer;
@@ -6,10 +6,12 @@ const CourtLayer = require('../layers/CourtLayer');
6
6
  const LineLayer = require('../layers/LineLayer');
7
7
  const PlayerLayer = require('../layers/PlayerLayer');
8
8
  const ShapeLayer = require('../layers/ShapeLayer');
9
+ const NoteLayer = require('../layers/NoteLayer');
9
10
  const LineControlPointLayer = require('../layers/LineControlPointLayer');
10
11
  const ShapeControlPointLayer = require('../layers/ShapeControlPointLayer');
11
12
  const Line = require('./Line');
12
13
  const Player = require('./Player');
14
+ const Note = require('./Note');
13
15
  const ShapeModels = require('./ShapeModels');
14
16
 
15
17
  class Frame {
@@ -38,6 +40,7 @@ class Frame {
38
40
  lines: this.lines,
39
41
  players: this.players,
40
42
  shapes: this.shapes,
43
+ notes: this.notes,
41
44
  options: {
42
45
  ...this.play.options,
43
46
  staticData: this.play.staticData,
@@ -64,6 +67,13 @@ class Frame {
64
67
  });
65
68
  }
66
69
 
70
+ get notes() {
71
+ if (!this.play.playData.notes) return [];
72
+ return this.play.playData.notes.map(n => {
73
+ return new Note(n);
74
+ });
75
+ }
76
+
67
77
  get currentPhasePlayers() {
68
78
  const lines = this.play.options.huddleMode ? this.playDataLines : this.prevPhaseLines;
69
79
  const { currentPhaseLines } = this;
@@ -218,6 +228,7 @@ class Frame {
218
228
  new PlayerLayer(this.ctx, frameData).apply();
219
229
  new LineControlPointLayer(this.ctx, frameData).apply();
220
230
  new ShapeControlPointLayer(this.ctx, frameData).apply();
231
+ new NoteLayer(this.ctx, frameData).apply();
221
232
 
222
233
  // console.timeEnd('draw');
223
234
 
@@ -0,0 +1,21 @@
1
+ const Model = require('./Base/InternalFrameModel');
2
+
3
+ class Note extends Model {
4
+ get id() {
5
+ return this._getAttr('id');
6
+ }
7
+
8
+ get headerText() {
9
+ return this._getAttr('headerText');
10
+ }
11
+
12
+ get text() {
13
+ return this._getAttr('text');
14
+ }
15
+
16
+ get location() {
17
+ return this._getAttr('location');
18
+ }
19
+ }
20
+
21
+ module.exports = Note;