@luceosports/play-rendering 2.0.2 → 2.0.4

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.
Files changed (38) hide show
  1. package/dist/play-rendering.js +3 -3
  2. package/dist/play-rendering.js.map +1 -1
  3. package/dist/types/models/PlayModel.d.ts +1 -1
  4. package/dist/types/models/ShapeModels/index.d.ts +2 -2
  5. package/package.json +1 -1
  6. package/src/helpers/common.ts +1 -1
  7. package/src/layers/CourtLayer.ts +9 -8
  8. package/src/layers/LineLayer.ts +2 -2
  9. package/src/layers/NoteLayer.ts +5 -3
  10. package/src/layers/PlayerLayer.ts +23 -6
  11. package/src/layers/ShapeLayer.ts +2 -2
  12. package/src/layers/court/layers/BASEBALL/courtTypes/BASEBALL_HIGH_SCHOOL/layers/ADirtLayer.ts +2 -1
  13. package/src/layers/court/layers/BASEBALL/courtTypes/BASEBALL_HIGH_SCHOOL/layers/BaseLineLayer.ts +1 -1
  14. package/src/layers/court/layers/BASKETBALL/common/LaneMarkingNBATrait.ts +13 -1
  15. package/src/layers/court/layers/BASKETBALL/common/LaneMarkingNCAATrait.ts +13 -1
  16. package/src/layers/court/layers/BASKETBALL/courtTypes/BIG3/layers/Big3Layer.ts +1 -1
  17. package/src/layers/court/layers/FOOTBALL/layers/FieldNumberLayer.ts +1 -1
  18. package/src/layers/court/layers/LACROSSE/courtTypes/LACROSSE_US_W/layers/FanLineLayer.ts +2 -1
  19. package/src/layers/line/base/InternalLineLayer.ts +5 -5
  20. package/src/layers/line/layers/DribbleLineLayer.ts +4 -4
  21. package/src/layers/shape/base/InternalShapeLayer.ts +1 -1
  22. package/src/layers/shape/layers/line/DribbleLineShapeLayer.ts +1 -1
  23. package/src/layers/shape/layers/line/base/InternalLineShapeLayer.ts +1 -1
  24. package/src/math/Bezier.ts +7 -5
  25. package/src/math/LineDrawingMath.ts +15 -15
  26. package/src/models/AnimationModel.ts +11 -11
  27. package/src/models/Base/InternalFrameModel.ts +2 -2
  28. package/src/models/FrameModel.ts +18 -15
  29. package/src/models/LineModel.ts +2 -2
  30. package/src/models/NoteModel.ts +7 -7
  31. package/src/models/PlayModel.ts +3 -3
  32. package/src/models/PlayerModel.ts +1 -1
  33. package/src/models/ShapeModel.ts +3 -6
  34. package/src/models/ShapeModels/CircleShape.ts +4 -0
  35. package/src/models/ShapeModels/LineShape.ts +7 -2
  36. package/src/traits/DribbleLineTrait.ts +17 -2
  37. package/src/traits/LineDrawOperationsTrait.ts +31 -7
  38. package/tsconfig.json +2 -1
@@ -15,7 +15,7 @@ export type PlayModelOptions = {
15
15
  linesSelectedIds: string[];
16
16
  shapeSelectedId: string | null;
17
17
  noteSelectedId: string | null;
18
- playersHiddenPositions?: string[];
18
+ playersHiddenPositions: string[];
19
19
  background: string;
20
20
  watermark: string | null;
21
21
  mirror: boolean;
@@ -10,5 +10,5 @@ import LineShape from './LineShape';
10
10
  import SquareShape from './SquareShape';
11
11
  import StraightShape from './StraightShape';
12
12
  import TriangleShape from './TriangleShape';
13
- import XMarkShape from './XMarkShape';
14
- export { CutLineShape, DribbleLineShape, HandoffLineShape, PassLineShape, ScreenLineShape, CircleShape, ConeShape, FovShape, LineShape, SquareShape, StraightShape, TriangleShape, XMarkShape };
13
+ import XmarkShape from './XmarkShape';
14
+ export { CutLineShape, DribbleLineShape, HandoffLineShape, PassLineShape, ScreenLineShape, CircleShape, ConeShape, FovShape, LineShape, SquareShape, StraightShape, TriangleShape, XmarkShape };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luceosports/play-rendering",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "main": "dist/play-rendering.js",
5
5
  "types": "dist/play-rendering.d.ts",
6
6
  "scripts": {
@@ -25,7 +25,7 @@ export function shapeModelKeyFromImport(shapeModels: typeof ShapeModels, type: S
25
25
  const prefix = type.replace('LINE.', '');
26
26
  const suffix = type.indexOf('LINE.') >= 0 ? 'LineShape' : 'Shape';
27
27
  return key.toLowerCase() === `${prefix}${suffix}`.toLowerCase();
28
- });
28
+ }) as keyof typeof ShapeModels;
29
29
  }
30
30
 
31
31
  export async function loadImage(src: string | Buffer) {
@@ -23,7 +23,7 @@ export default class CourtLayer extends BaseLayer {
23
23
  }
24
24
 
25
25
  get background() {
26
- return this.options.background || this.playData.sport;
26
+ return (this.options.background || this.playData.sport) as keyof typeof this.staticData.backgroundOptions;
27
27
  }
28
28
 
29
29
  apply() {
@@ -58,8 +58,7 @@ export default class CourtLayer extends BaseLayer {
58
58
 
59
59
  setBackground() {
60
60
  if (this.staticData.backgroundOptions && this.staticData.backgroundOptions[this.background]) {
61
- const ptrn = this.ctx.createPattern(this.staticData.backgroundOptions[this.background], 'repeat');
62
- this.ctx.fillStyle = ptrn;
61
+ this.ctx.fillStyle = this.ctx.createPattern(this.staticData.backgroundOptions[this.background], 'repeat')!;
63
62
  this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
64
63
  } else if (this.background.indexOf('#') === 0) {
65
64
  this.ctx.save();
@@ -70,8 +69,10 @@ export default class CourtLayer extends BaseLayer {
70
69
  }
71
70
 
72
71
  setWatermark() {
73
- if (this.options.watermark && this.staticData.watermark && this.staticData.watermark[this.options.watermark]) {
74
- const watermarkImage = this.staticData.watermark[this.options.watermark];
72
+ const watermarkImage = this.options.watermark
73
+ ? this.staticData.watermark[this.options.watermark as keyof typeof this.staticData.watermark]
74
+ : null;
75
+ if (watermarkImage) {
75
76
  const aRatio = watermarkImage.width / watermarkImage.height;
76
77
  const maxWatermarkLimit = this.frameWidth / 5;
77
78
  const destination = {
@@ -92,11 +93,11 @@ export default class CourtLayer extends BaseLayer {
92
93
  const dy = (this.playData.court.courtRect.size.height - fullCourtIndentY - 1) * this.scale - destination.height;
93
94
 
94
95
  this.ctx.drawImage(
95
- this.staticData.watermark[this.options.watermark],
96
+ watermarkImage,
96
97
  0,
97
98
  0,
98
- this.staticData.watermark[this.options.watermark].width,
99
- this.staticData.watermark[this.options.watermark].height,
99
+ watermarkImage.width,
100
+ watermarkImage.height,
100
101
  dx,
101
102
  dy,
102
103
  destination.width,
@@ -16,8 +16,8 @@ export default class LineLayer extends BaseLayer {
16
16
  this.playData.lines.forEach(line => {
17
17
  if (this.options.linesHiddenIds.indexOf(line.id) >= 0) return;
18
18
  const layerKey = `${_.capitalize(line.type)}LineLayer`;
19
- if (lineLayers[layerKey]) {
20
- new lineLayers[layerKey](this, line).apply();
19
+ if (lineLayers[layerKey as keyof typeof lineLayers]) {
20
+ new lineLayers[layerKey as keyof typeof lineLayers](this, line).apply();
21
21
  }
22
22
  });
23
23
 
@@ -3,7 +3,7 @@ import BaseLayer from './base/BaseLayer';
3
3
  import NoteModel from '../models/NoteModel';
4
4
 
5
5
  export default class NoteLayer extends BaseLayer {
6
- private noteAlpha: number;
6
+ private noteAlpha?: number;
7
7
 
8
8
  apply() {
9
9
  this.ctx.save();
@@ -62,6 +62,8 @@ export default class NoteLayer extends BaseLayer {
62
62
  }
63
63
 
64
64
  setColor(note: NoteModel) {
65
+ if (typeof this.noteAlpha === 'undefined') throw new Error('noteAlpha is not set');
66
+
65
67
  const { alpha, blue, green, red } = note.color;
66
68
 
67
69
  const r = Math.ceil(red * 255);
@@ -82,7 +84,7 @@ export default class NoteLayer extends BaseLayer {
82
84
  this.ctx.textBaseline = note.textBaseline;
83
85
  }
84
86
 
85
- drawBubble(note: NoteModel, { width, height }) {
87
+ drawBubble(note: NoteModel, { width, height }: { width: number; height: number }) {
86
88
  this.ctx.lineWidth = this.courtTypeConstants.COURT_LINE_WIDTH;
87
89
  this.ctx.beginPath();
88
90
  this.ctx.rect(0, 0, width, height);
@@ -92,7 +94,7 @@ export default class NoteLayer extends BaseLayer {
92
94
  }
93
95
  }
94
96
 
95
- drawText(note: NoteModel, lines) {
97
+ drawText(note: NoteModel, lines: { words: { text: string; width: number }[] }[]) {
96
98
  lines.forEach(({ words }, index) => {
97
99
  this.ctx.save();
98
100
 
@@ -106,14 +106,31 @@ export default class PlayerLayer extends BaseLayer {
106
106
  const playerMapItem = this.options.playersMap.find(item => item.position === player.position);
107
107
  const headshotImage = this.staticData.playerHeadshots.find(item => item.id === playerMapItem?.teamPlayerId);
108
108
  if (headshotImage) {
109
+ const imageVertical = headshotImage.image.width < headshotImage.image.height;
110
+ const imageHorizontal = headshotImage.image.height < headshotImage.image.width;
111
+
112
+ const imageScale = imageVertical
113
+ ? headshotImage.image.height / headshotImage.image.width
114
+ : imageHorizontal
115
+ ? headshotImage.image.width / headshotImage.image.height
116
+ : 1;
117
+
118
+ const dw =
119
+ this.radius * 2 * (imageVertical ? headshotImage.image.width / headshotImage.image.height : 1) * imageScale;
120
+ const dh =
121
+ this.radius * 2 * (imageHorizontal ? headshotImage.image.height / headshotImage.image.width : 1) * imageScale;
122
+
123
+ const topLeftX = 0 - (imageHorizontal ? dw / 2 : this.radius);
124
+ const topLeftY = 0 - (imageVertical ? dh / 2 : this.radius);
125
+
109
126
  this.ctx.save();
110
127
  this.ctx.translate(x, y);
111
- if (this.options.flipPlayerLabels === true) {
128
+ if (this.options.flipPlayerLabels) {
112
129
  this.ctx.rotate(Math.PI);
113
130
  }
114
131
  this.ctx.arc(0, 0, this.radius, 0, Math.PI * 2, true);
115
132
  this.ctx.clip();
116
- this.ctx.drawImage(headshotImage.image, 0 - this.radius, 0 - this.radius, this.radius * 2, this.radius * 2);
133
+ this.ctx.drawImage(headshotImage.image, topLeftX, topLeftY, dw, dh);
117
134
  this.ctx.restore();
118
135
  return;
119
136
  }
@@ -135,7 +152,7 @@ export default class PlayerLayer extends BaseLayer {
135
152
  this.ctx.textAlign = 'center';
136
153
  this.ctx.font = `${fontSize}px Helvetica`;
137
154
 
138
- if (this.options.mirror === true) {
155
+ if (this.options.mirror) {
139
156
  this.ctx.save();
140
157
  this.ctx.translate(x * 2, 0);
141
158
  this.ctx.scale(-1, 1);
@@ -144,7 +161,7 @@ export default class PlayerLayer extends BaseLayer {
144
161
  let px = x;
145
162
  let py = y;
146
163
 
147
- if (this.options.flipPlayerLabels === true) {
164
+ if (this.options.flipPlayerLabels) {
148
165
  px = 0;
149
166
  py = 0;
150
167
  this.ctx.save();
@@ -154,11 +171,11 @@ export default class PlayerLayer extends BaseLayer {
154
171
 
155
172
  this.ctx.fillText(player.textLabel, px, py + textVerticalOffset);
156
173
 
157
- if (this.options.flipPlayerLabels === true) {
174
+ if (this.options.flipPlayerLabels) {
158
175
  this.ctx.restore();
159
176
  }
160
177
 
161
- if (this.options.mirror === true) {
178
+ if (this.options.mirror) {
162
179
  this.ctx.restore();
163
180
  }
164
181
  }
@@ -11,8 +11,8 @@ export default class ShapeLayer extends BaseLayer {
11
11
  ? `${_.capitalize(shape.type.replace('LINE.', ''))}Line`
12
12
  : _.capitalize(shape.type);
13
13
  const layerKey = `${shapeType}ShapeLayer`;
14
- if (shapeLayers[layerKey]) {
15
- new shapeLayers[layerKey](this, shape).apply();
14
+ if (shapeLayers[layerKey as keyof typeof shapeLayers]) {
15
+ new shapeLayers[layerKey as keyof typeof shapeLayers](this, shape).apply();
16
16
  }
17
17
  });
18
18
 
@@ -11,6 +11,7 @@ import {
11
11
  PITCHERS_PLATE_TO_PITCHING_MOUND_CENTER,
12
12
  PITCHING_MOUND_DIA
13
13
  } from '../constants';
14
+ import { CourtPoint } from '../../../../../../../types';
14
15
 
15
16
  export default class ADirtLayer extends InternalCourtLayer {
16
17
  original() {
@@ -119,6 +120,6 @@ export default class ADirtLayer extends InternalCourtLayer {
119
120
  }
120
121
  }
121
122
 
122
- function getArcPointForAngle(c, radius, angle) {
123
+ function getArcPointForAngle(c: CourtPoint, radius: number, angle: number) {
123
124
  return { x: c.x + Math.cos(angle) * radius, y: c.y + Math.sin(angle) * radius };
124
125
  }
@@ -56,7 +56,7 @@ export default class BaseLineLayer extends InternalCourtLayer {
56
56
  });
57
57
  }
58
58
 
59
- drawBaseSquare(x, y) {
59
+ drawBaseSquare(x: number, y: number) {
60
60
  this.ctx.save();
61
61
  this.ctx.lineCap = 'square';
62
62
  this.ctx.beginPath();
@@ -1,3 +1,15 @@
1
+ import { CourtPoint, CourtTypeConstants } from '../../../../../types';
2
+
3
+ interface InheritedPropsAndMethods {
4
+ ctx: CanvasRenderingContext2D;
5
+ courtTypeConstants: CourtTypeConstants & Record<string, any>;
6
+ courtCenter: CourtPoint;
7
+ }
8
+
9
+ interface LineMarkingNBATrait extends InheritedPropsAndMethods {
10
+ drawLogic: () => void;
11
+ }
12
+
1
13
  const COURT_INNER_MARK_OFFSET = 5;
2
14
 
3
15
  export default {
@@ -31,4 +43,4 @@ export default {
31
43
  this.ctx.lineTo(courtInnerMarkRightX - 0.5, 13.0);
32
44
  this.ctx.stroke();
33
45
  }
34
- };
46
+ } as LineMarkingNBATrait;
@@ -1,3 +1,15 @@
1
+ import { CourtPoint, CourtTypeConstants } from '../../../../../types';
2
+
3
+ interface InheritedPropsAndMethods {
4
+ ctx: CanvasRenderingContext2D;
5
+ courtTypeConstants: CourtTypeConstants & Record<string, any>;
6
+ courtCenter: CourtPoint;
7
+ }
8
+
9
+ interface LineMarkingNCAATrait extends InheritedPropsAndMethods {
10
+ drawLogic: () => void;
11
+ }
12
+
1
13
  export default {
2
14
  drawLogic() {
3
15
  const courtMarkingWidth = 0.667;
@@ -27,4 +39,4 @@ export default {
27
39
  this.ctx.fill();
28
40
  this.ctx.stroke();
29
41
  }
30
- };
42
+ } as LineMarkingNCAATrait;
@@ -36,7 +36,7 @@ export default class Big3Layer extends InternalCourtLayer {
36
36
  this.ctx.fill();
37
37
  }
38
38
 
39
- this.ctx.fillStyle = this.options.lineColor;
39
+ this.ctx.fillStyle = this.options.lineColor!;
40
40
  this.ctx.fillText('4', point.x - textHorizontalOffset, point.y + textVerticalOffset);
41
41
  });
42
42
  }
@@ -9,7 +9,7 @@ export default class FieldNumberLayer extends InternalCourtLayer {
9
9
 
10
10
  const thinSpaceChar = String.fromCharCode(8202);
11
11
 
12
- this.ctx.fillStyle = this.options.lineColor;
12
+ this.ctx.fillStyle = this.options.lineColor!;
13
13
  this.ctx.translate(x, y);
14
14
 
15
15
  for (let i = 1; i < 10; i++) {
@@ -1,4 +1,5 @@
1
1
  import InternalCourtLayer from '../../../../../base/InternalCourtLayer';
2
+ import { CourtPoint } from '../../../../../../../types';
2
3
 
3
4
  const ARC_8M_RADIUS = 11.59;
4
5
  const ARC_12M_RADIUS = 15.97;
@@ -140,6 +141,6 @@ export default class CenterLineLayer extends InternalCourtLayer {
140
141
  }
141
142
  }
142
143
 
143
- function getArcPointForAngle(c, radius, angle) {
144
+ function getArcPointForAngle(c: CourtPoint, radius: number, angle: number) {
144
145
  return { x: c.x + Math.cos(angle) * radius, y: c.y + Math.sin(angle) * radius };
145
146
  }
@@ -44,7 +44,7 @@ export default class InternalLineLayer extends InternalBaseLayer {
44
44
  this.drawLineCap();
45
45
  }
46
46
 
47
- setColor(alphaOverride = null) {
47
+ setColor(alphaOverride: number | null = null) {
48
48
  let lineForPlayerInPosition = false;
49
49
  if (this.options.position) {
50
50
  const { playerPositionOrigin, playerPositionTerminus } = this.line.originalData;
@@ -135,8 +135,8 @@ export default class InternalLineLayer extends InternalBaseLayer {
135
135
  const [preLastLine] = linesForPlayerPosition;
136
136
  if (preLastLine.lineParts.length) {
137
137
  const lastLinePart = [...preLastLine.lineParts].pop();
138
- const lastLinePartCp = [...lastLinePart.controlPoints].pop();
139
- this.startMaskSettings = { centerPoint: lastLinePartCp, radius: 3.0 }; // 1
138
+ const lastLinePartCp = [...lastLinePart!.controlPoints].pop();
139
+ this.startMaskSettings = { centerPoint: lastLinePartCp!, radius: 3.0 }; // 1
140
140
  }
141
141
  }
142
142
  }
@@ -146,11 +146,11 @@ export default class InternalLineLayer extends InternalBaseLayer {
146
146
  if (this.line.type !== 'SCREEN') {
147
147
  let radius = 3.7; // 0.7
148
148
  const lastLinePart = [...this.line.getLineParts()].pop();
149
- const lastLinePartCp = [...lastLinePart.controlPoints].pop();
149
+ const lastLinePartCp = [...lastLinePart!.controlPoints].pop();
150
150
  if (['PASS', 'HANDOFF'].indexOf(this.line.type) >= 0) {
151
151
  radius = 1.75;
152
152
  }
153
- this.endMaskSettings = { centerPoint: lastLinePartCp, radius: radius };
153
+ this.endMaskSettings = { centerPoint: lastLinePartCp!, radius: radius };
154
154
  }
155
155
  }
156
156
 
@@ -2,7 +2,7 @@ import _ from 'lodash';
2
2
  import { animationProgress } from '../../../helpers/common';
3
3
  import ActionLineLayer from '../base/ActionLineLayer';
4
4
  import DribbleLineTrait from '../../../traits/DribbleLineTrait';
5
- import { CourtPoint, LinePart } from '../../../types';
5
+ import { LinePart } from '../../../types';
6
6
  import { LinePartAdjusted } from '../../../models/LineModel';
7
7
 
8
8
  export default class DribbleLineLayer extends ActionLineLayer {
@@ -23,11 +23,11 @@ export default class DribbleLineLayer extends ActionLineLayer {
23
23
  dribbleLineParts.forEach(lp => {
24
24
  const { controlPoints, lpIndex } = lp;
25
25
  const [firstPoint] = controlPoints;
26
- let alpha = lineParts[lpIndex].alpha || this.line.color.alpha;
26
+ let alpha = lineParts[lpIndex!].alpha || this.line.color.alpha;
27
27
  if (this.options.animationGlobalProgress) {
28
- const [start, end] = this.line.animationKeyTimeChunks[lpIndex];
28
+ const [start, end] = this.line.animationKeyTimeChunks[lpIndex!];
29
29
  if (_.inRange(this.options.animationGlobalProgress, start, end)) {
30
- if (animationProgress(this.options.animationGlobalProgress, start, end) > firstPoint.time) {
30
+ if (animationProgress(this.options.animationGlobalProgress, start, end) > firstPoint.time!) {
31
31
  alpha = 0.1;
32
32
  }
33
33
  }
@@ -13,7 +13,7 @@ export default class InternalShapeLayer extends InternalBaseLayer {
13
13
  }
14
14
 
15
15
  get staticData() {
16
- return this.options.staticData;
16
+ return this.options.staticData!;
17
17
  }
18
18
 
19
19
  drawLogic() {
@@ -19,7 +19,7 @@ export default class DribbleLineShapeLayer extends InternalLineShapeLayer {
19
19
  }
20
20
 
21
21
  getProcessedLinePaths() {
22
- return this.convertLinePartsToDribble([this.shape.linePart]);
22
+ return this.convertLinePartsToDribble([...(this.shape.linePart ? [this.shape.linePart] : [])]);
23
23
  }
24
24
  }
25
25
 
@@ -24,7 +24,7 @@ export default class InternalLineShapeLayer extends InternalShapeLayer {
24
24
  }
25
25
 
26
26
  getProcessedLinePaths() {
27
- return [this.shape.linePart];
27
+ return [this.shape.linePart!];
28
28
  }
29
29
 
30
30
  drawShapeLogic() {
@@ -8,8 +8,8 @@ export default class Bezier {
8
8
  constructor(
9
9
  private a: CourtPoint,
10
10
  private b: CourtPoint,
11
- private c: CourtPoint = null,
12
- private d: CourtPoint = null
11
+ private c: CourtPoint | null = null,
12
+ private d: CourtPoint | null = null
13
13
  ) {
14
14
  this.len = 100;
15
15
  this.arcLengths = new Array(this.len + 1);
@@ -42,6 +42,7 @@ export default class Bezier {
42
42
  if (this.a && this.b && !this.c && !this.d) {
43
43
  return this.linearBezierEquation(t, 'x');
44
44
  }
45
+ throw new Error('invalid input params');
45
46
  }
46
47
 
47
48
  y(t: number) {
@@ -54,6 +55,7 @@ export default class Bezier {
54
55
  if (this.a && this.b && !this.c && !this.d) {
55
56
  return this.linearBezierEquation(t, 'y');
56
57
  }
58
+ throw new Error('invalid input params');
57
59
  }
58
60
 
59
61
  map(u: number) {
@@ -94,15 +96,15 @@ export default class Bezier {
94
96
  }
95
97
 
96
98
  quadraticBezierEquation(t: number, axis: 'x' | 'y') {
97
- return (1 - t) * (1 - t) * this.a[axis] + 2 * (1 - t) * t * this.b[axis] + t * t * this.c[axis];
99
+ return (1 - t) * (1 - t) * this.a[axis] + 2 * (1 - t) * t * this.b[axis] + t * t * this.c![axis];
98
100
  }
99
101
 
100
102
  cubicBezierEquation(t: number, axis: 'x' | 'y') {
101
103
  return (
102
104
  (1 - t) * (1 - t) * (1 - t) * this.a[axis] +
103
105
  3 * ((1 - t) * (1 - t)) * t * this.b[axis] +
104
- 3 * (1 - t) * (t * t) * this.c[axis] +
105
- t * t * t * this.d[axis]
106
+ 3 * (1 - t) * (t * t) * this.c![axis] +
107
+ t * t * t * this.d![axis]
106
108
  );
107
109
  }
108
110
  }
@@ -5,26 +5,26 @@ const sinusoidNumberOfPoints = 1000;
5
5
 
6
6
  export function adjustedBezierCurveWithExclusionZones(
7
7
  controlPoints: CourtPoint[],
8
- startZoneRadius = null,
9
- startAnchor = null,
10
- endZoneRadius = null,
11
- endAnchor = null
8
+ startZoneRadius: number | null = null,
9
+ startAnchor: CourtPoint | null = null,
10
+ endZoneRadius: number | null = null,
11
+ endAnchor: CourtPoint | null = null
12
12
  ) {
13
13
  let curve = [...controlPoints];
14
14
  if (startZoneRadius && startAnchor) {
15
15
  const controlPointsMat = controlPointsMatFromPoints(controlPoints);
16
16
  const tVal = firstTValForPointOnCurveOutsideCircle(controlPointsMat, startAnchor, startZoneRadius);
17
17
  const splitCurves = splitBezierCurveAtTVal(controlPoints, tVal);
18
- curve = [...splitCurves].pop();
18
+ curve = [...splitCurves!].pop() as CourtPoint[];
19
19
  }
20
20
 
21
21
  if (endZoneRadius && endAnchor) {
22
- const reverseControlPoints = [].concat(curve).reverse(); // reverse array without changing the original
22
+ const reverseControlPoints = ([] as CourtPoint[]).concat(curve).reverse(); // reverse array without changing the original
23
23
  const reverseControlPointsMat = controlPointsMatFromPoints(reverseControlPoints);
24
24
  const reverseTVal = firstTValForPointOnCurveOutsideCircle(reverseControlPointsMat, endAnchor, endZoneRadius);
25
25
  const tVal = 1.0 - reverseTVal;
26
26
  const splitCurves = splitBezierCurveAtTVal(curve, tVal);
27
- curve = splitCurves[0];
27
+ curve = splitCurves![0];
28
28
  }
29
29
  return curve as LinePart['controlPoints'];
30
30
  }
@@ -225,7 +225,7 @@ export function splitBezierCurveAtTVal(controlPoints: CourtPoint[], tVal: number
225
225
 
226
226
  function linearPointAtTVal(controlPoints: CourtPoint[], tVal: number) {
227
227
  const [firstControlPoint] = controlPoints;
228
- const lastControlPoint = [...controlPoints].pop();
228
+ const lastControlPoint = [...controlPoints].pop() as CourtPoint;
229
229
  const xt = firstControlPoint.x + (lastControlPoint.x - firstControlPoint.x) * tVal;
230
230
  const yt = firstControlPoint.y + (lastControlPoint.y - firstControlPoint.y) * tVal;
231
231
  return { y: yt, x: xt };
@@ -233,11 +233,11 @@ function linearPointAtTVal(controlPoints: CourtPoint[], tVal: number) {
233
233
 
234
234
  function splitLinearBezierCurveAtTVal(controlPoints: CourtPoint[], tVal: number) {
235
235
  // Comment from prev dev:
236
- // this could be faster by doing calculations directly.. but who cares
237
- const midPoint = linearPointAtTVal(controlPoints, tVal);
236
+ // this could be faster by doing calculations directly... but who cares
237
+ const midPoint: CourtPoint = linearPointAtTVal(controlPoints, tVal);
238
238
  return [
239
239
  [controlPoints[0], midPoint],
240
- [midPoint, [...controlPoints].pop()]
240
+ [midPoint, [...controlPoints].pop() as CourtPoint]
241
241
  ];
242
242
  }
243
243
 
@@ -275,12 +275,12 @@ function splitCubicCurveAtTVal(controlPoints: CourtPoint[], tVal: number) {
275
275
  function firstTValForPointOnCurveOutsideCircle(controlPointsMat: Matrix, anchorPoint: CourtPoint, radius: number) {
276
276
  const [numberOfRows] = controlPointsMat.size();
277
277
  const helperMat = helperMatrixForDegree(numberOfRows - 1);
278
- const pointsOnCurveMat = multiply(helperMat, controlPointsMat);
278
+ const pointsOnCurveMat = multiply(helperMat!, controlPointsMat);
279
279
  const distances = distancesFromPointToPoints(anchorPoint, pointsOnCurveMat);
280
280
 
281
281
  // Comment from prev dev:
282
282
  // We're assuming that point 0 is the closest to the anchor point... So we could use a binary search here to save a bit of time
283
- // Chances are is that the tVal will actually be near the beginning however due to the way the function i used at this time
283
+ // Chances are is that the tVal will actually be near the beginning however due to the way the function I used at this time
284
284
 
285
285
  let indexOfPoint = distances.length - 1;
286
286
  for (let i = 0; i < distances.length; i++) {
@@ -298,8 +298,8 @@ function distancesFromPointToPoints(anchorPoint: CourtPoint, pointsOnCurveMat: M
298
298
  const xPointAdjustFromOrigin = -anchorPoint.x;
299
299
  const yPointAdjustFromOrigin = -anchorPoint.y;
300
300
 
301
- const adjustedXPoints = [];
302
- const adjustedYPoints = [];
301
+ const adjustedXPoints: number[] = [];
302
+ const adjustedYPoints: number[] = [];
303
303
 
304
304
  pointsOnCurveMat.forEach((value, [, col]) => {
305
305
  switch (col) {
@@ -12,8 +12,8 @@ export default class AnimationModel {
12
12
  private running: boolean;
13
13
  private framesLoadTime: number[];
14
14
  private timeStart: number | null;
15
- private timeElapsed: number;
16
- private timeElapsedSaved: number;
15
+ private timeElapsed: number | null;
16
+ private timeElapsedSaved: number | null;
17
17
 
18
18
  constructor(private ctx: CanvasRenderingContext2D, play: PlayModel) {
19
19
  this.play = _.cloneDeep(play);
@@ -35,7 +35,7 @@ export default class AnimationModel {
35
35
  }
36
36
 
37
37
  get globalProgress() {
38
- return (this.timeElapsed * 100) / (this.animationDuration * 1000) / 100;
38
+ return ((this.timeElapsed || 0) * 100) / (this.animationDuration * 1000) / 100;
39
39
  }
40
40
 
41
41
  get currentPlayPhase() {
@@ -43,7 +43,7 @@ export default class AnimationModel {
43
43
  return _.inRange(this.globalProgress, interval.min, interval.max);
44
44
  });
45
45
 
46
- return parseInt(phaseInterval ? phaseInterval[0] : Object.keys(this.linesPhaseIntervals).pop());
46
+ return parseInt(phaseInterval ? phaseInterval[0] : Object.keys(this.linesPhaseIntervals).pop()!);
47
47
  }
48
48
 
49
49
  get linesPhaseIntervals(): Record<number, { min: number; max: number }> {
@@ -52,7 +52,7 @@ export default class AnimationModel {
52
52
  if (!result[line.phase]) result[line.phase] = { min: 0, max: 0 };
53
53
  line.animations.forEach(({ keyTimes }) => {
54
54
  const [from] = keyTimes;
55
- const to = [...keyTimes].pop();
55
+ const to = [...keyTimes].pop()!;
56
56
  if (from < result[line.phase].min || (!result[line.phase].min && line.phase > 1)) result[line.phase].min = from;
57
57
  if (to > result[line.phase].max) result[line.phase].max = to;
58
58
  });
@@ -61,9 +61,9 @@ export default class AnimationModel {
61
61
  }
62
62
 
63
63
  get lastLineAnimationMax() {
64
- return this.play.playData.lines.reduce((result, line) => {
64
+ return this.play.playData.lines.reduce<number>((result, line) => {
65
65
  const lineModel = new LineModel(line);
66
- return result > lineModel.lastAnimEndTime ? result : lineModel.lastAnimEndTime;
66
+ return result > lineModel.lastAnimEndTime! ? result : lineModel.lastAnimEndTime!;
67
67
  }, 0);
68
68
  }
69
69
 
@@ -78,7 +78,7 @@ export default class AnimationModel {
78
78
  }
79
79
 
80
80
  pause() {
81
- cancelAnimationFrame(this.loopId);
81
+ cancelAnimationFrame(this.loopId!);
82
82
  this.running = false;
83
83
  this.timeStart = null;
84
84
  this.timeElapsedSaved = this.timeElapsed;
@@ -117,7 +117,7 @@ export default class AnimationModel {
117
117
  if (this.globalProgress >= this.lastLineAnimationMax) {
118
118
  progressCallback(this.lastLineAnimationMax);
119
119
  this.reset();
120
- cancelAnimationFrame(this.loopId);
120
+ cancelAnimationFrame(this.loopId!);
121
121
  setTimeout(() => {
122
122
  finishCallback();
123
123
  }, 1000);
@@ -128,10 +128,10 @@ export default class AnimationModel {
128
128
 
129
129
  if (!this.timeStart) this.timeStart = timestamp;
130
130
 
131
- const frameTime = timestamp - this.timeStart + this.timeElapsedSaved - this.timeElapsed;
131
+ const frameTime = timestamp - this.timeStart + (this.timeElapsedSaved || 0) - (this.timeElapsed || 0);
132
132
  this.framesLoadTime.push(frameTime);
133
133
 
134
- this.timeElapsed = timestamp - this.timeStart + this.timeElapsedSaved;
134
+ this.timeElapsed = timestamp - this.timeStart + (this.timeElapsedSaved || 0);
135
135
 
136
136
  if (debug) {
137
137
  console.log(
@@ -10,11 +10,11 @@ export default class Model<M extends Line | Player | Note | Shape, A extends Lin
10
10
  }
11
11
 
12
12
  _getAttrOriginal<K extends keyof M>(attr: K) {
13
- return typeof this.originalData[attr] !== 'undefined' ? this.originalData[attr] : null;
13
+ return this.originalData[attr];
14
14
  }
15
15
 
16
16
  _getAttr<K extends keyof A>(attr: K) {
17
- return typeof this.adjustedData[attr] !== 'undefined' ? this.adjustedData[attr] : null;
17
+ return this.adjustedData[attr];
18
18
  }
19
19
 
20
20
  _setAttr<K extends keyof A>(attr: K, value: A[K]) {