@sportsdataverse/sporty 0.1.0 → 0.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/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { UnknownUnitError, UnknownLeagueError, UnknownDisplayRangeError, SportyError } from './chunk-23Y47RKN.js';
2
2
  export { InputError, SportyError, UnknownDisplayRangeError, UnknownLeagueError, UnknownUnitError } from './chunk-23Y47RKN.js';
3
- import { BASKETBALL_SPECS, BASEBALL_LEAGUES, BASEBALL_SPECS, BASKETBALL_LEAGUES, CURLING_LEAGUES, CURLING_SPECS, FOOTBALL_LEAGUES, FOOTBALL_SPECS, HOCKEY_LEAGUES, HOCKEY_SPECS, LACROSSE_LEAGUES, LACROSSE_SPECS, SOCCER_LEAGUES, SOCCER_SPECS, TENNIS_LEAGUES, TENNIS_SPECS, VOLLEYBALL_LEAGUES, VOLLEYBALL_SPECS } from './chunk-VID5HIDQ.js';
4
- export { BASEBALL_LEAGUES, BASEBALL_SPECS, BASKETBALL_LEAGUES, BASKETBALL_SPECS, CURLING_LEAGUES, CURLING_SPECS, FOOTBALL_LEAGUES, FOOTBALL_SPECS, HOCKEY_LEAGUES, HOCKEY_SPECS, LACROSSE_LEAGUES, LACROSSE_SPECS, SOCCER_LEAGUES, SOCCER_SPECS, TENNIS_LEAGUES, TENNIS_SPECS, VOLLEYBALL_LEAGUES, VOLLEYBALL_SPECS } from './chunk-VID5HIDQ.js';
3
+ import { BASKETBALL_SPECS, BASEBALL_LEAGUES, BASEBALL_SPECS, BASKETBALL_LEAGUES, CURLING_LEAGUES, CURLING_SPECS, FOOTBALL_LEAGUES, FOOTBALL_SPECS, HOCKEY_LEAGUES, HOCKEY_SPECS, LACROSSE_LEAGUES, LACROSSE_SPECS, SOCCER_LEAGUES, SOCCER_SPECS, SOFTBALL_LEAGUES, SOFTBALL_SPECS, TENNIS_LEAGUES, TENNIS_SPECS, VOLLEYBALL_LEAGUES, VOLLEYBALL_SPECS } from './chunk-3WYO7OMK.js';
4
+ export { BASEBALL_LEAGUES, BASEBALL_SPECS, BASKETBALL_LEAGUES, BASKETBALL_SPECS, CURLING_LEAGUES, CURLING_SPECS, FOOTBALL_LEAGUES, FOOTBALL_SPECS, HOCKEY_LEAGUES, HOCKEY_SPECS, LACROSSE_LEAGUES, LACROSSE_SPECS, SOCCER_LEAGUES, SOCCER_SPECS, SOFTBALL_LEAGUES, SOFTBALL_SPECS, TENNIS_LEAGUES, TENNIS_SPECS, VOLLEYBALL_LEAGUES, VOLLEYBALL_SPECS } from './chunk-3WYO7OMK.js';
5
5
 
6
6
  // src/version.ts
7
- var VERSION = "0.1.0";
7
+ var VERSION = "0.2.0";
8
8
 
9
9
  // src/transform.ts
10
10
  function rotateCoords(pts, angleDeg) {
@@ -1781,12 +1781,12 @@ function curlingSheet(league, opts = {}) {
1781
1781
  var zip = (xs, ys) => xs.map((x, i) => [x, ys[i] ?? 0]);
1782
1782
  var isRectangular = (benchShape) => ["rectangle", "rectangular"].includes(benchShape.toLowerCase());
1783
1783
  function outerCornerX(benchShape, startingDepth, thickness, teamBenchLengthFieldSide, teamBenchLengthBackSide, teamBenchWidth, teamBenchAreaBorderThickness) {
1784
- if (!isRectangular(benchShape))
1785
- return teamBenchLengthBackSide / 2 + teamBenchAreaBorderThickness + thickness / 2;
1784
+ const x1 = teamBenchLengthFieldSide / 2 + teamBenchAreaBorderThickness + thickness;
1785
+ if (isRectangular(benchShape) || !(teamBenchWidth > 0) || teamBenchLengthBackSide === teamBenchLengthFieldSide)
1786
+ return x1;
1786
1787
  const m = teamBenchWidth / (teamBenchLengthBackSide / 2 - teamBenchLengthFieldSide / 2);
1787
1788
  const y2 = startingDepth + thickness;
1788
1789
  const y1 = startingDepth - teamBenchWidth - teamBenchAreaBorderThickness;
1789
- const x1 = teamBenchLengthFieldSide / 2 + teamBenchAreaBorderThickness + thickness;
1790
1790
  return (y2 - y1) / m + x1;
1791
1791
  }
1792
1792
  function halfField({
@@ -2364,7 +2364,8 @@ function footballField(league, opts = {}) {
2364
2364
  );
2365
2365
  }
2366
2366
  const p = mergeParams(FOOTBALL_SPECS[key], opts.updates, ARRAY_FIELDS2);
2367
- const colors = mergeColors(FOOTBALL_DEFAULT_COLORS, opts.colorUpdates);
2367
+ const defaults = p.field_bordered ? { ...FOOTBALL_DEFAULT_COLORS, field_border_outline: "#ffffff", red_zone_border_outline: "#ffffff" } : FOOTBALL_DEFAULT_COLORS;
2368
+ const colors = mergeColors(defaults, opts.colorUpdates);
2368
2369
  const col = (k) => colorAt(colors[k], 0);
2369
2370
  arcResolution(opts.arcResolution);
2370
2371
  const from = normalizeUnit(p.field_units || "ft");
@@ -2646,9 +2647,7 @@ function footballField(league, opts = {}) {
2646
2647
  const [bx0, bx1, by0, by1] = [Math.min(...xs), Math.max(...xs), Math.min(...ys), Math.max(...ys)];
2647
2648
  addFeature(features2, "yardage_marker_box", createRectangle(bx0, bx1, by0, by1), "#ffffff00", {
2648
2649
  xAnchor: 0,
2649
- yAnchor: 0,
2650
- xTrans,
2651
- yTrans
2650
+ yAnchor: 0
2652
2651
  });
2653
2652
  const [[ux0, uy0], , [ux1, uy1]] = b.rect;
2654
2653
  addText(features2, "yardage_marker", {
@@ -3849,22 +3848,31 @@ function goalCircleFill({
3849
3848
  function goalArc({
3850
3849
  goalArcExtension = 0,
3851
3850
  goalArcRadius = 0,
3852
- lineThickness,
3851
+ lineThickness: t = 0,
3852
+ goalArcParallelLineToCenter,
3853
3853
  npoints
3854
- }) {
3854
+ } = {}) {
3855
3855
  const e = goalArcExtension;
3856
3856
  const r = goalArcRadius;
3857
- const outer = circle5({ center: [0, 0], start: 0.5, end: 1.5, r, npoints });
3858
- if (lineThickness === void 0) return [[e, r], ...outer, [e, -r], [e, -r], [e, r], [e, r]];
3859
- const t = lineThickness;
3857
+ const wOuter = Math.min(goalArcParallelLineToCenter ?? r, r);
3858
+ const wInner = wOuter - t;
3859
+ const rInner = r - t;
3860
+ const xOuter = -Math.sqrt(Math.max(r ** 2 - wOuter ** 2, 0));
3861
+ const xInner = -Math.sqrt(Math.max(rInner ** 2 - wInner ** 2, 0));
3862
+ const thetaOuter = Math.atan2(wOuter, xOuter) / Math.PI;
3863
+ const thetaInner = Math.atan2(wInner, xInner) / Math.PI;
3860
3864
  return [
3861
- [e, r],
3862
- ...outer,
3863
- [e, -r],
3864
- [e, -r + t],
3865
- ...circle5({ center: [0, 0], start: 1.5, end: 0.5, r: r - t, npoints }),
3866
- [e, r - t],
3867
- [e, r]
3865
+ [e, wOuter],
3866
+ [xOuter, wOuter],
3867
+ ...circle5({ center: [0, 0], start: thetaOuter, end: 2 - thetaOuter, r, npoints }),
3868
+ [xOuter, -wOuter],
3869
+ [e, -wOuter],
3870
+ [e, -wInner],
3871
+ [xInner, -wInner],
3872
+ ...circle5({ center: [0, 0], start: 2 - thetaInner, end: thetaInner, r: rInner, npoints }),
3873
+ [xInner, wInner],
3874
+ [e, wInner],
3875
+ [e, wOuter]
3868
3876
  ];
3869
3877
  }
3870
3878
  function goalFan({
@@ -3873,19 +3881,41 @@ function goalFan({
3873
3881
  lineThickness = 0,
3874
3882
  npoints
3875
3883
  } = {}) {
3876
- const c = goalCircleRadius;
3877
- const t = lineThickness;
3878
- const pi = Math.PI;
3879
- const inset = t / (goalFanRadius + c - t) / pi;
3884
+ if (goalFanRadius <= goalCircleRadius) return [];
3885
+ const dir = [-1 / Math.sqrt(2), 1 / Math.sqrt(2)];
3886
+ const toCircle = (p, radius) => {
3887
+ const b = p[0] * dir[0] + p[1] * dir[1];
3888
+ return -b + Math.sqrt(b ** 2 - (p[0] ** 2 + p[1] ** 2) + radius ** 2);
3889
+ };
3890
+ const along = (p, d) => [p[0] + d * dir[0], p[1] + d * dir[1]];
3891
+ const bOuter = [0, goalCircleRadius];
3892
+ const cOuter = along(bOuter, toCircle(bOuter, goalFanRadius));
3893
+ const base2 = [
3894
+ bOuter[0] + lineThickness * -1 / Math.sqrt(2),
3895
+ bOuter[1] + lineThickness * -1 / Math.sqrt(2)
3896
+ ];
3897
+ const bInner = along(base2, toCircle(base2, goalCircleRadius));
3898
+ const cInner = along(base2, toCircle(base2, goalFanRadius - lineThickness));
3899
+ const thetaOuter = Math.atan2(cOuter[1], cOuter[0]) / Math.PI;
3900
+ const thetaInner = Math.atan2(cInner[1], cInner[0]) / Math.PI;
3880
3901
  return [
3881
- [c * Math.cos(0.5 * pi), c * Math.sin(0.5 * pi)],
3882
- [c * Math.cos(0.5 * pi) + t * Math.cos(0.75 * pi), c * Math.sin(0.5 * pi) + t * Math.sin(0.75 * pi)],
3883
- ...circle5({ center: [c, 0], start: 0.75, end: 1.25, r: goalFanRadius + c, npoints }),
3884
- [c * Math.cos(1.5 * pi), c * Math.sin(1.5 * pi)],
3885
- [c * Math.cos(1.5 * pi) + t * Math.cos(1.25 * pi), c * Math.sin(1.5 * pi) - t * Math.sin(1.25 * pi)],
3886
- ...circle5({ center: [c, 0], start: 1.25 - inset, end: 0.75 + inset, r: goalFanRadius + c - t, npoints }),
3887
- [c * Math.cos(0.5 * pi) + t * Math.cos(0.75 * pi), c * Math.sin(0.5 * pi) - t * Math.sin(0.75 * pi)],
3888
- [c * Math.cos(0.5 * pi), c * Math.sin(0.5 * pi)]
3902
+ bOuter,
3903
+ cOuter,
3904
+ ...circle5({ center: [0, 0], start: thetaOuter, end: 2 - thetaOuter, r: goalFanRadius, npoints }),
3905
+ [cOuter[0], -cOuter[1]],
3906
+ [bOuter[0], -bOuter[1]],
3907
+ [bInner[0], -bInner[1]],
3908
+ [cInner[0], -cInner[1]],
3909
+ ...circle5({
3910
+ center: [0, 0],
3911
+ start: 2 - thetaInner,
3912
+ end: thetaInner,
3913
+ r: goalFanRadius - lineThickness,
3914
+ npoints
3915
+ }),
3916
+ cInner,
3917
+ bInner,
3918
+ bOuter
3889
3919
  ];
3890
3920
  }
3891
3921
  function goalFanHashMark({
@@ -4012,10 +4042,10 @@ function penaltyBoxOutline2({
4012
4042
  const h = s / 2;
4013
4043
  return [
4014
4044
  [0, -(2 * t + d)],
4015
- [h + l + t, -(2 * t + d)],
4045
+ [h + l + 2 * t, -(2 * t + d)],
4046
+ [h + l + 2 * t, -t],
4016
4047
  [h + l + t, -t],
4017
- [h + l, -t],
4018
- [h + l, -(t + d)],
4048
+ [h + l + t, -(t + d)],
4019
4049
  [h + t, -(t + d)],
4020
4050
  [h + t, -t],
4021
4051
  [h, -t],
@@ -4206,8 +4236,6 @@ var LACROSSE_DEFAULT_COLORS = {
4206
4236
 
4207
4237
  // src/lacrosse/field.ts
4208
4238
  var isOneOf6 = (list, v) => list.includes(v);
4209
- var NZONE_LENGTH = 0;
4210
- var BOARD_THICKNESS = 0;
4211
4239
  var CENTER_FACE_OFF_MARKER_RADIUS = 0;
4212
4240
  var CORNER_FACE_OFF_MARKER_BAR_WIDTH = 0;
4213
4241
  var CORNER_FACE_OFF_MARKER_BAR_LENGTH = 0;
@@ -4223,11 +4251,8 @@ function lacrosseField(league, opts = {}) {
4223
4251
  `Unknown lacrosse display range "${opts.displayRange}"; expected one of: ${LACROSSE_DISPLAY_RANGES.join(", ")}`
4224
4252
  );
4225
4253
  const p = mergeParams(LACROSSE_SPECS[key], opts.updates, ["goal_fan_hash_mark_separation_from_center"]);
4226
- const contrast = (p.center_face_off_marker_color_contrasting ?? false) && LACROSSE_DEFAULT_COLORS.center_face_off_marker === LACROSSE_DEFAULT_COLORS.center_line;
4227
- const colors = mergeColors(
4228
- LACROSSE_DEFAULT_COLORS,
4229
- contrast && opts.colorUpdates?.center_face_off_marker === void 0 ? { ...opts.colorUpdates, center_face_off_marker: "#ffcb05" } : opts.colorUpdates
4230
- );
4254
+ const merged = mergeColors(LACROSSE_DEFAULT_COLORS, opts.colorUpdates);
4255
+ const colors = (p.center_face_off_marker_color_contrasting ?? false) && opts.colorUpdates?.center_face_off_marker === void 0 && merged.center_face_off_marker === merged.center_line ? { ...merged, center_face_off_marker: "#ffcb05" } : merged;
4231
4256
  const col = (k) => colorAt(colors[k], 0);
4232
4257
  const npoints = arcResolution(opts.arcResolution);
4233
4258
  const from = normalizeUnit(p.field_units || "ft");
@@ -4251,7 +4276,7 @@ function lacrosseField(league, opts = {}) {
4251
4276
  fieldLength: L,
4252
4277
  fieldWidth: W,
4253
4278
  cornerRadius: p.corner_radius ?? 0,
4254
- nzoneLength: NZONE_LENGTH,
4279
+ nzoneLength: p.neutral_zone_length ?? 0,
4255
4280
  fieldShape: p.field_shape,
4256
4281
  npoints
4257
4282
  };
@@ -4282,7 +4307,7 @@ function lacrosseField(league, opts = {}) {
4282
4307
  );
4283
4308
  add(
4284
4309
  "neutral_zone",
4285
- neutralZone2({ nzoneLength: NZONE_LENGTH, fieldWidth: W }),
4310
+ neutralZone2({ nzoneLength: p.neutral_zone_length ?? 0, fieldWidth: W }),
4286
4311
  col("neutral_zone"),
4287
4312
  0,
4288
4313
  0,
@@ -4382,7 +4407,7 @@ function lacrosseField(league, opts = {}) {
4382
4407
  penaltyBoxLength: p.penalty_box_length ?? 0,
4383
4408
  penaltyBoxDepth: p.penalty_box_depth ?? 0
4384
4409
  };
4385
- const penaltyX = (p.penalty_box_separation ?? 0) / 2 + BOARD_THICKNESS + (p.penalty_box_length ?? 0) / 2;
4410
+ const penaltyX = (p.penalty_box_separation ?? 0) / 2 + (p.boards_thickness ?? 0) + (p.penalty_box_length ?? 0) / 2;
4386
4411
  const penaltyFill = penaltyBoxFill2(penaltyBox2);
4387
4412
  add("penalty_box_fill", penaltyFill, col("team_a_penalty_box"), -penaltyX, -W / 2, false, false);
4388
4413
  add("penalty_box_fill", penaltyFill, col("team_b_penalty_box"), penaltyX, -W / 2, false, false);
@@ -4483,8 +4508,8 @@ function lacrosseField(league, opts = {}) {
4483
4508
  goalArc({
4484
4509
  goalArcExtension: p.goal_arc_extension ?? 0,
4485
4510
  goalArcRadius: p.goal_arc_radius ?? 0,
4486
- lineThickness: p.goal_arc_line_thickness,
4487
- // R: no %or% — undefined reproduces its NULL recycling
4511
+ lineThickness: p.goal_arc_line_thickness ?? 0,
4512
+ goalArcParallelLineToCenter: p.goal_arc_parallel_line_to_center,
4488
4513
  npoints
4489
4514
  }),
4490
4515
  col("goal_arc"),
@@ -4493,24 +4518,17 @@ function lacrosseField(league, opts = {}) {
4493
4518
  true,
4494
4519
  false
4495
4520
  );
4496
- add(
4497
- "goal_fan",
4498
- goalFan({
4499
- goalFanRadius: p.goal_fan_radius ?? 0,
4500
- goalCircleRadius: p.goal_circle_radius,
4501
- lineThickness: p.goal_fan_line_thickness ?? 0,
4502
- npoints
4503
- }),
4504
- col("goal_fan"),
4505
- gx,
4506
- 0,
4507
- true,
4508
- false
4509
- );
4521
+ const fan = goalFan({
4522
+ goalFanRadius: p.goal_fan_radius ?? 0,
4523
+ goalCircleRadius: p.goal_circle_radius,
4524
+ lineThickness: p.goal_fan_line_thickness ?? 0,
4525
+ npoints
4526
+ });
4527
+ if (fan.length > 0) add("goal_fan", fan, col("goal_fan"), gx, 0, true, false);
4510
4528
  for (const sep of p.goal_fan_hash_mark_separation_from_center ?? []) {
4511
- const thetaBuild = sep / ((p.goal_fan_radius ?? 1) + p.goal_circle_radius);
4512
- const thetaPlace = sep / (p.goal_fan_radius ?? 1) / Math.PI;
4513
- const R = (p.goal_fan_radius ?? 0) + p.goal_circle_radius;
4529
+ const R = (p.goal_fan_radius ?? 1) - (p.goal_fan_line_thickness ?? 0) / 2;
4530
+ const thetaBuild = sep / R;
4531
+ const thetaPlace = thetaBuild / Math.PI;
4514
4532
  const mark = goalFanHashMark({
4515
4533
  goalFanHashMarkLength: p.goal_fan_hash_mark_length ?? 0,
4516
4534
  lineThickness: p.goal_fan_hash_mark_line_thickness ?? 0,
@@ -4520,7 +4538,7 @@ function lacrosseField(league, opts = {}) {
4520
4538
  "goal_fan_hash_mark",
4521
4539
  mark,
4522
4540
  col("goal_fan_hash_mark"),
4523
- gx + p.goal_circle_radius + R * Math.cos((1 - thetaPlace) * Math.PI),
4541
+ gx + R * Math.cos((1 - thetaPlace) * Math.PI),
4524
4542
  R * Math.sin((1 - thetaPlace) * Math.PI),
4525
4543
  true,
4526
4544
  true
@@ -4613,9 +4631,14 @@ function lacrosseField(league, opts = {}) {
4613
4631
  true,
4614
4632
  true
4615
4633
  );
4616
- const hfl = L / 2 + p.field_apron_thickness;
4617
- const hfw = W / 2 + p.field_apron_thickness;
4618
4634
  const boards3 = p.boards_thickness ?? 0;
4635
+ const hfl = Math.max(
4636
+ L / 2 + p.field_apron_thickness,
4637
+ (p.bench_separation ?? 0) / 2 + (p.bench_length ?? 0) + boards3,
4638
+ (p.penalty_box_separation ?? 0) / 2 + (p.penalty_box_length ?? 0) + 2 * boards3
4639
+ // #72: two walls
4640
+ );
4641
+ const hfw = W / 2 + Math.max(p.field_apron_thickness, 2 * boards3 + Math.max(p.bench_depth ?? 0, p.penalty_box_depth ?? 0));
4619
4642
  const inX = [-(L / 2 + boards3), L / 2 + boards3];
4620
4643
  const off = [0, hfl];
4621
4644
  const def = [-hfl, 0];
@@ -5102,6 +5125,364 @@ function soccerPitch(league, opts = {}) {
5102
5125
  };
5103
5126
  }
5104
5127
 
5128
+ // src/softball/features.ts
5129
+ var circle7 = (o) => {
5130
+ const { npoints, ...rest } = o;
5131
+ return npoints === void 0 ? createCircle(rest) : createCircle({ ...rest, npoints });
5132
+ };
5133
+ function battersBox2({
5134
+ battersBoxLength = 0,
5135
+ battersBoxWidth = 0,
5136
+ battersBoxYAdj = 0,
5137
+ battersBoxThickness: t = 0
5138
+ } = {}) {
5139
+ const w = battersBoxWidth / 2;
5140
+ const l = battersBoxLength / 2;
5141
+ const half = [
5142
+ [0, l],
5143
+ [w, l],
5144
+ [w, -l],
5145
+ [0, -l],
5146
+ [0, -l + t],
5147
+ [w - t, -l + t],
5148
+ [w - t, l - t],
5149
+ [0, l - t],
5150
+ [0, l]
5151
+ ];
5152
+ return [...half, ...reflectCoords(half, { overX: false, overY: true })].map(
5153
+ ([x, y]) => [x, y + battersBoxYAdj]
5154
+ );
5155
+ }
5156
+ function catchersBox2({
5157
+ catchersBoxDepth: depth = 0,
5158
+ catchersBoxWidth: width = 0,
5159
+ battersBoxLength = 0,
5160
+ battersBoxYAdj = 0,
5161
+ catchersBoxThickness: t = 0
5162
+ } = {}) {
5163
+ const w = width / 2;
5164
+ const front = -battersBoxLength / 2 + battersBoxYAdj;
5165
+ const back = front - depth;
5166
+ return [
5167
+ [w, front],
5168
+ [w, back],
5169
+ [-w, back],
5170
+ [-w, front],
5171
+ [-w + t, front],
5172
+ [-w + t, back + t],
5173
+ [w - t, back + t],
5174
+ [w - t, front],
5175
+ [w, front]
5176
+ ];
5177
+ }
5178
+ function foulLine2({
5179
+ isLine1b = false,
5180
+ lineDistance = 0,
5181
+ battersBoxLength = 0,
5182
+ battersBoxWidth = 0,
5183
+ battersBoxYAdj = 0,
5184
+ homePlateSideToBattersBox = 0,
5185
+ homePlateEdgeLength = 0,
5186
+ foulLineThickness: t = 0
5187
+ } = {}) {
5188
+ const start = Math.min(
5189
+ homePlateEdgeLength / 2 + homePlateSideToBattersBox + battersBoxWidth,
5190
+ battersBoxLength / 2 + battersBoxYAdj
5191
+ );
5192
+ const a = isLine1b ? Math.PI / 4 : 3 * Math.PI / 4;
5193
+ const ex = lineDistance * Math.cos(a);
5194
+ const ey = lineDistance * Math.sin(a);
5195
+ const sx = isLine1b ? start : -start;
5196
+ const dt = isLine1b ? -t : t;
5197
+ return [
5198
+ [sx, start],
5199
+ [ex, ey],
5200
+ [ex + dt, ey],
5201
+ [sx + dt, start],
5202
+ [sx, start]
5203
+ ];
5204
+ }
5205
+ var pitchersCircle = ({
5206
+ pitchersCircleRadius: r = 0,
5207
+ pitchersCircleThickness: t = 0,
5208
+ npoints
5209
+ } = {}) => [
5210
+ ...circle7({ center: [0, 0], start: 0, end: 2, r, npoints }),
5211
+ ...circle7({ center: [0, 0], start: 2, end: 0, r: r - t, npoints })
5212
+ ];
5213
+ function pitchersLane({
5214
+ pitchersLaneLength: len = 0,
5215
+ pitchersPlateLength = 0,
5216
+ pitchersPlateFrontToHomePlate = 0,
5217
+ homePlateEdgeLength = 0,
5218
+ homePlateSideToBattersBox = 0,
5219
+ battersBoxLength = 0,
5220
+ battersBoxYAdj = 0,
5221
+ pitchersLaneThickness: t = 0
5222
+ } = {}) {
5223
+ const sx = pitchersPlateLength / 2;
5224
+ const dx = homePlateEdgeLength / 2 + homePlateSideToBattersBox - sx;
5225
+ const dy = battersBoxLength / 2 + battersBoxYAdj - pitchersPlateFrontToHomePlate;
5226
+ const theta = dx === 0 && dy === 0 ? -Math.PI / 2 : Math.atan2(dy, dx);
5227
+ const ex = sx + len * Math.cos(theta);
5228
+ const ey = len * Math.sin(theta);
5229
+ return [
5230
+ [sx, 0],
5231
+ [ex, ey],
5232
+ [ex - t, ey],
5233
+ [sx - t, 0],
5234
+ [sx, 0]
5235
+ ];
5236
+ }
5237
+ function coachesBox({
5238
+ baselineDistance = 0,
5239
+ coachesBoxDepth = 0,
5240
+ coachesBoxLength = 0,
5241
+ coachesBoxWidth = 0,
5242
+ coachesBoxThickness: t = 0
5243
+ } = {}) {
5244
+ const aEnd = baselineDistance;
5245
+ const aStart = baselineDistance - coachesBoxLength;
5246
+ const dIn = coachesBoxDepth;
5247
+ const dOut = coachesBoxDepth + coachesBoxWidth;
5248
+ const ad = [
5249
+ [aEnd, dIn],
5250
+ [aStart, dIn],
5251
+ [aStart, dOut],
5252
+ [aStart + t, dOut],
5253
+ [aStart + t, dIn + t],
5254
+ [aEnd, dIn + t],
5255
+ [aEnd, dIn]
5256
+ ];
5257
+ return ad.map(([a, d]) => [(a + d) / Math.SQRT2, (a - d) / Math.SQRT2]);
5258
+ }
5259
+
5260
+ // src/softball/types.ts
5261
+ var SOFTBALL_FEATURES = [
5262
+ "infield_dirt",
5263
+ "home_plate",
5264
+ "base",
5265
+ "pitchers_plate",
5266
+ "batters_box",
5267
+ "catchers_box",
5268
+ "foul_line",
5269
+ "running_lane",
5270
+ "pitchers_circle",
5271
+ "pitchers_lane",
5272
+ "coaches_box"
5273
+ ];
5274
+ var SOFTBALL_DISPLAY_RANGES = ["full", "infield"];
5275
+ var SOFTBALL_COLOR_KEYS = [
5276
+ "plot_background",
5277
+ "infield_dirt",
5278
+ "base",
5279
+ "pitchers_plate",
5280
+ "batters_box",
5281
+ "catchers_box",
5282
+ "foul_line",
5283
+ "running_lane",
5284
+ "pitchers_circle",
5285
+ "pitchers_lane",
5286
+ "coaches_box"
5287
+ ];
5288
+ var SOFTBALL_DEFAULT_COLORS = {
5289
+ plot_background: "#395d33",
5290
+ infield_dirt: "#9b7653",
5291
+ base: "#ffffff",
5292
+ pitchers_plate: "#ffffff",
5293
+ batters_box: "#ffffff",
5294
+ catchers_box: "#ffffff",
5295
+ foul_line: "#ffffff",
5296
+ running_lane: "#ffffff",
5297
+ pitchers_circle: "#ffffff",
5298
+ pitchers_lane: "#ffffff",
5299
+ coaches_box: "#ffffff"
5300
+ };
5301
+
5302
+ // src/softball/field.ts
5303
+ var isOneOf8 = (list, v) => list.includes(v);
5304
+ function softballField(league, opts = {}) {
5305
+ const key = league.toLowerCase();
5306
+ if (!isOneOf8(SOFTBALL_LEAGUES, key))
5307
+ throw new UnknownLeagueError(
5308
+ `Unknown softball league "${league}"; expected one of: ${SOFTBALL_LEAGUES.join(", ")}`
5309
+ );
5310
+ const range = (opts.displayRange ?? "full").toLowerCase();
5311
+ if (!isOneOf8(SOFTBALL_DISPLAY_RANGES, range))
5312
+ throw new UnknownDisplayRangeError(
5313
+ `Unknown softball display range "${opts.displayRange}"; expected one of: ${SOFTBALL_DISPLAY_RANGES.join(", ")}`
5314
+ );
5315
+ const p = mergeParams(SOFTBALL_SPECS[key], opts.updates, []);
5316
+ const colors = mergeColors(SOFTBALL_DEFAULT_COLORS, opts.colorUpdates);
5317
+ const col = (k) => colorAt(colors[k], 0);
5318
+ const npoints = arcResolution(opts.arcResolution);
5319
+ const from = normalizeUnit(p.field_units || "ft");
5320
+ const units = normalizeUnit(opts.units ?? from);
5321
+ const conv = units === from ? void 0 : [from, units];
5322
+ const { rotation = 0, xTrans = 0, yTrans = 0 } = opts;
5323
+ const features2 = [];
5324
+ const add = (name, pts, fill, xAnchor, yAnchor, reflectX = false) => addFeature(
5325
+ features2,
5326
+ name,
5327
+ pts,
5328
+ fill,
5329
+ { xAnchor, yAnchor, reflectX, reflectY: false, xTrans, yTrans, rotation },
5330
+ conv ? { units: conv } : {}
5331
+ );
5332
+ const bl = p.baseline_distance;
5333
+ const ppf = p.pitchers_plate_front_to_home_plate;
5334
+ const box = {
5335
+ battersBoxLength: p.batters_box_length,
5336
+ battersBoxWidth: p.batters_box_width,
5337
+ battersBoxYAdj: p.batters_box_y_adj
5338
+ };
5339
+ const foul = {
5340
+ ...box,
5341
+ homePlateSideToBattersBox: p.home_plate_side_to_batters_box,
5342
+ homePlateEdgeLength: p.home_plate_edge_length,
5343
+ foulLineThickness: p.line_width
5344
+ };
5345
+ add(
5346
+ "infield_dirt",
5347
+ infieldDirt({
5348
+ homePlateCircleRadius: p.home_plate_circle_radius,
5349
+ foulLineToFoulGrass: p.foul_line_to_foul_grass,
5350
+ pitchersPlateDistance: ppf,
5351
+ infieldArcRadius: p.infield_arc_radius,
5352
+ npoints
5353
+ }),
5354
+ col("infield_dirt"),
5355
+ 0,
5356
+ 0
5357
+ );
5358
+ add("home_plate", homePlate({ homePlateEdgeLength: p.home_plate_edge_length }), col("base"), 0, 0);
5359
+ add(
5360
+ "base",
5361
+ base({ baseSideLength: p.base_side_length, adjustXLeft: true }),
5362
+ col("base"),
5363
+ bl * Math.cos(Math.PI / 4),
5364
+ bl * Math.sin(Math.PI / 4)
5365
+ );
5366
+ add("base", base({ baseSideLength: p.base_side_length }), col("base"), 0, bl * Math.SQRT2);
5367
+ add(
5368
+ "base",
5369
+ base({ baseSideLength: p.base_side_length, adjustXRight: true }),
5370
+ col("base"),
5371
+ bl * Math.cos(3 * Math.PI / 4),
5372
+ bl * Math.sin(3 * Math.PI / 4)
5373
+ );
5374
+ add(
5375
+ "pitchers_plate",
5376
+ pitchersPlate({
5377
+ pitchersPlateLength: p.pitchers_plate_length,
5378
+ pitchersPlateWidth: p.pitchers_plate_width
5379
+ }),
5380
+ col("pitchers_plate"),
5381
+ 0,
5382
+ ppf
5383
+ );
5384
+ add(
5385
+ "batters_box",
5386
+ battersBox2({ ...box, battersBoxThickness: p.line_width }),
5387
+ col("batters_box"),
5388
+ p.home_plate_edge_length / 2 + p.home_plate_side_to_batters_box + p.batters_box_width / 2,
5389
+ 0,
5390
+ true
5391
+ );
5392
+ add(
5393
+ "catchers_box",
5394
+ catchersBox2({
5395
+ catchersBoxDepth: p.catchers_box_depth,
5396
+ catchersBoxWidth: p.catchers_box_width,
5397
+ battersBoxLength: p.batters_box_length,
5398
+ battersBoxYAdj: p.batters_box_y_adj,
5399
+ catchersBoxThickness: p.line_width
5400
+ }),
5401
+ col("catchers_box"),
5402
+ 0,
5403
+ 0
5404
+ );
5405
+ add(
5406
+ "foul_line",
5407
+ foulLine2({ ...foul, isLine1b: true, lineDistance: p.right_field_distance }),
5408
+ col("foul_line"),
5409
+ 0,
5410
+ 0
5411
+ );
5412
+ add("foul_line", foulLine2({ ...foul, lineDistance: p.left_field_distance }), col("foul_line"), 0, 0);
5413
+ add(
5414
+ "running_lane",
5415
+ runningLane({
5416
+ runningLaneDepth: p.running_lane_depth,
5417
+ runningLaneLength: p.running_lane_length,
5418
+ runningLaneStartDistance: p.running_lane_start_distance,
5419
+ runningLaneThickness: p.line_width
5420
+ }),
5421
+ col("running_lane"),
5422
+ 0,
5423
+ 0
5424
+ );
5425
+ add(
5426
+ "pitchers_circle",
5427
+ pitchersCircle({
5428
+ pitchersCircleRadius: p.pitchers_circle_radius,
5429
+ pitchersCircleThickness: p.line_width,
5430
+ npoints
5431
+ }),
5432
+ col("pitchers_circle"),
5433
+ 0,
5434
+ ppf
5435
+ );
5436
+ add(
5437
+ "pitchers_lane",
5438
+ pitchersLane({
5439
+ pitchersLaneLength: p.pitchers_lane_length,
5440
+ pitchersPlateLength: p.pitchers_plate_length,
5441
+ pitchersPlateFrontToHomePlate: ppf,
5442
+ homePlateEdgeLength: p.home_plate_edge_length,
5443
+ homePlateSideToBattersBox: p.home_plate_side_to_batters_box,
5444
+ battersBoxLength: p.batters_box_length,
5445
+ battersBoxYAdj: p.batters_box_y_adj,
5446
+ pitchersLaneThickness: p.line_width
5447
+ }),
5448
+ col("pitchers_lane"),
5449
+ 0,
5450
+ ppf,
5451
+ true
5452
+ );
5453
+ add(
5454
+ "coaches_box",
5455
+ coachesBox({
5456
+ baselineDistance: bl,
5457
+ coachesBoxDepth: p.coaches_box_depth,
5458
+ coachesBoxLength: p.coaches_box_length,
5459
+ coachesBoxWidth: p.coaches_box_width,
5460
+ coachesBoxThickness: p.line_width
5461
+ }),
5462
+ col("coaches_box"),
5463
+ 0,
5464
+ 0,
5465
+ true
5466
+ );
5467
+ const pad = 5;
5468
+ const full = range === "full";
5469
+ const xr = full ? [p.left_field_distance * Math.cos(3 * Math.PI / 4), p.right_field_distance * Math.cos(Math.PI / 4)] : [-p.infield_arc_radius - pad, p.infield_arc_radius + pad];
5470
+ const yr = full ? [-p.backstop_radius - pad, p.center_field_distance + pad] : [-p.home_plate_circle_radius - pad, ppf + p.infield_arc_radius + pad];
5471
+ const [cx, cy] = convertLimits(xr, yr, from, units);
5472
+ const xlim = opts.xlim ?? [cx[0] + xTrans, cx[1] + xTrans];
5473
+ const ylim = opts.ylim ?? [cy[0] + yTrans, cy[1] + yTrans];
5474
+ const background = col("plot_background");
5475
+ return {
5476
+ sport: "softball",
5477
+ league: key,
5478
+ units,
5479
+ bbox: displayBbox(xlim, ylim, rotation),
5480
+ origin: "home_plate",
5481
+ .../^#[0-9a-f]{6}00$/i.test(background) ? {} : { background },
5482
+ features: features2
5483
+ };
5484
+ }
5485
+
5105
5486
  // src/tennis/features.ts
5106
5487
  var frontcourtHalf = ({
5107
5488
  servicelineDistance = 0,
@@ -5230,7 +5611,7 @@ var TENNIS_DEFAULT_COLORS = {
5230
5611
  };
5231
5612
 
5232
5613
  // src/tennis/court.ts
5233
- var isOneOf8 = (list, v) => list.includes(v);
5614
+ var isOneOf9 = (list, v) => list.includes(v);
5234
5615
  var SIDE = {
5235
5616
  full: "full",
5236
5617
  in_bounds_only: "in",
@@ -5257,12 +5638,12 @@ var SIDE = {
5257
5638
  };
5258
5639
  function tennisCourt(league, opts = {}) {
5259
5640
  const key = league.toLowerCase();
5260
- if (!isOneOf8(TENNIS_LEAGUES, key))
5641
+ if (!isOneOf9(TENNIS_LEAGUES, key))
5261
5642
  throw new UnknownLeagueError(
5262
5643
  `Unknown tennis league "${league}"; expected one of: ${TENNIS_LEAGUES.join(", ")}`
5263
5644
  );
5264
5645
  const range = (opts.displayRange ?? "full").toLowerCase();
5265
- if (!isOneOf8(TENNIS_DISPLAY_RANGES, range))
5646
+ if (!isOneOf9(TENNIS_DISPLAY_RANGES, range))
5266
5647
  throw new UnknownDisplayRangeError(
5267
5648
  `Unknown tennis display range "${opts.displayRange}"; expected one of: ${TENNIS_DISPLAY_RANGES.join(", ")}`
5268
5649
  );
@@ -5518,15 +5899,15 @@ var VOLLEYBALL_DEFAULT_COLORS = {
5518
5899
  };
5519
5900
 
5520
5901
  // src/volleyball/court.ts
5521
- var isOneOf9 = (list, v) => list.includes(v);
5902
+ var isOneOf10 = (list, v) => list.includes(v);
5522
5903
  function volleyballCourt(league, opts = {}) {
5523
5904
  const key = league.toLowerCase();
5524
- if (!isOneOf9(VOLLEYBALL_LEAGUES, key))
5905
+ if (!isOneOf10(VOLLEYBALL_LEAGUES, key))
5525
5906
  throw new UnknownLeagueError(
5526
5907
  `Unknown volleyball league "${league}"; expected one of: ${VOLLEYBALL_LEAGUES.join(", ")}`
5527
5908
  );
5528
5909
  const range = (opts.displayRange ?? "full").toLowerCase();
5529
- if (!isOneOf9(VOLLEYBALL_DISPLAY_RANGES, range))
5910
+ if (!isOneOf10(VOLLEYBALL_DISPLAY_RANGES, range))
5530
5911
  throw new UnknownDisplayRangeError(
5531
5912
  `Unknown volleyball display range "${opts.displayRange}"; expected one of: ${VOLLEYBALL_DISPLAY_RANGES.join(", ")}`
5532
5913
  );
@@ -5670,6 +6051,7 @@ var SPORTS = [
5670
6051
  "hockey",
5671
6052
  "lacrosse",
5672
6053
  "soccer",
6054
+ "softball",
5673
6055
  "tennis",
5674
6056
  "volleyball"
5675
6057
  ];
@@ -5690,6 +6072,8 @@ function surface(sport, league, opts = {}) {
5690
6072
  return lacrosseField(league, opts);
5691
6073
  case "soccer":
5692
6074
  return soccerPitch(league, opts);
6075
+ case "softball":
6076
+ return softballField(league, opts);
5693
6077
  case "tennis":
5694
6078
  return tennisCourt(league, opts);
5695
6079
  case "volleyball":
@@ -5741,6 +6125,12 @@ var DISCOVERY = {
5741
6125
  displayRanges: SOCCER_DISPLAY_RANGES,
5742
6126
  colorKeys: SOCCER_COLOR_KEYS
5743
6127
  },
6128
+ softball: {
6129
+ leagues: SOFTBALL_LEAGUES,
6130
+ features: SOFTBALL_FEATURES,
6131
+ displayRanges: SOFTBALL_DISPLAY_RANGES,
6132
+ colorKeys: SOFTBALL_COLOR_KEYS
6133
+ },
5744
6134
  tennis: {
5745
6135
  leagues: TENNIS_LEAGUES,
5746
6136
  features: TENNIS_FEATURES,
@@ -5950,6 +6340,6 @@ function basketballZones(league = "nba", o = {}) {
5950
6340
  ];
5951
6341
  }
5952
6342
 
5953
- export { BASEBALL_COLOR_KEYS, BASEBALL_DISPLAY_RANGES, BASEBALL_FEATURES, BASKETBALL_COLOR_KEYS, BASKETBALL_DISPLAY_RANGES, BASKETBALL_FEATURES, BASKETBALL_ZONES, BASKETBALL_ZONE_LABELS, CURLING_COLOR_KEYS, CURLING_DISPLAY_RANGES, CURLING_FEATURES, FOOTBALL_COLOR_KEYS, FOOTBALL_DISPLAY_RANGES, FOOTBALL_FEATURES, FRAMES, FT_PER_UNIT, HOCKEY_COLOR_KEYS, HOCKEY_DISPLAY_RANGES, HOCKEY_FEATURES, LACROSSE_COLOR_KEYS, LACROSSE_DISPLAY_RANGES, LACROSSE_FEATURES, SOCCER_COLOR_KEYS, SOCCER_DISPLAY_RANGES, SOCCER_FEATURES, SPORTS, TENNIS_COLOR_KEYS, TENNIS_DISPLAY_RANGES, TENNIS_FEATURES, VERSION, VOLLEYBALL_COLOR_KEYS, VOLLEYBALL_DISPLAY_RANGES, VOLLEYBALL_FEATURES, baseballField, basketballCourt, basketballZoneOf, basketballZones, colorKeys, convertPoints, convertUnits, createCircle, createDiamond, createRectangle, createSquare, createXShape, curlingSheet, displayRanges, features, footballField, frameBottomLeft, hockeyRink, lacrosseField, leagues, normalizeUnit, placeFeature, reflectCoords, rotateCoords, soccerPitch, surface, tennisCourt, toSurfaceFrame, volleyballCourt };
6343
+ export { BASEBALL_COLOR_KEYS, BASEBALL_DISPLAY_RANGES, BASEBALL_FEATURES, BASKETBALL_COLOR_KEYS, BASKETBALL_DISPLAY_RANGES, BASKETBALL_FEATURES, BASKETBALL_ZONES, BASKETBALL_ZONE_LABELS, CURLING_COLOR_KEYS, CURLING_DISPLAY_RANGES, CURLING_FEATURES, FOOTBALL_COLOR_KEYS, FOOTBALL_DISPLAY_RANGES, FOOTBALL_FEATURES, FRAMES, FT_PER_UNIT, HOCKEY_COLOR_KEYS, HOCKEY_DISPLAY_RANGES, HOCKEY_FEATURES, LACROSSE_COLOR_KEYS, LACROSSE_DISPLAY_RANGES, LACROSSE_FEATURES, SOCCER_COLOR_KEYS, SOCCER_DISPLAY_RANGES, SOCCER_FEATURES, SOFTBALL_COLOR_KEYS, SOFTBALL_DISPLAY_RANGES, SOFTBALL_FEATURES, SPORTS, TENNIS_COLOR_KEYS, TENNIS_DISPLAY_RANGES, TENNIS_FEATURES, VERSION, VOLLEYBALL_COLOR_KEYS, VOLLEYBALL_DISPLAY_RANGES, VOLLEYBALL_FEATURES, baseballField, basketballCourt, basketballZoneOf, basketballZones, colorKeys, convertPoints, convertUnits, createCircle, createDiamond, createRectangle, createSquare, createXShape, curlingSheet, displayRanges, features, footballField, frameBottomLeft, hockeyRink, lacrosseField, leagues, normalizeUnit, placeFeature, reflectCoords, rotateCoords, soccerPitch, softballField, surface, tennisCourt, toSurfaceFrame, volleyballCourt };
5954
6344
  //# sourceMappingURL=index.js.map
5955
6345
  //# sourceMappingURL=index.js.map