@seatlayer/core 0.15.0 → 0.16.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.cjs CHANGED
@@ -963,6 +963,7 @@ var ISO_ANGLE_DEG = -11.5;
963
963
  var ISO_SQUASH = 0.58;
964
964
  var LIFT_PER_STEP = 58;
965
965
  var ISO_TWEEN_MS = 320;
966
+ var CAMERA_GLIDE_MS = 650;
966
967
  var BLOCK_FILL_ALPHA = 0.85;
967
968
  var SOLD_DARKEN = 0.5;
968
969
  var SECTION_LABEL_PX = 20;
@@ -1917,6 +1918,40 @@ var _SeatmapRenderer = class _SeatmapRenderer {
1917
1918
  this.seatLayer.batchDraw();
1918
1919
  }
1919
1920
  }
1921
+ /** Frame the currently available inventory that survived a buyer price
1922
+ * filter. Clearing the filter glides back to the full venue. */
1923
+ focusCategories(keys) {
1924
+ if (!keys?.length) {
1925
+ this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });
1926
+ return;
1927
+ }
1928
+ const wanted = new Set(keys);
1929
+ const matching = this.seats.filter((seat) => {
1930
+ if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;
1931
+ const status = this.statusById.get(seat.id) ?? "free";
1932
+ return status === "free" || this.ownedHold.has(seat.id);
1933
+ });
1934
+ if (!matching.length) return;
1935
+ let minX = Infinity;
1936
+ let maxX = -Infinity;
1937
+ let minY = Infinity;
1938
+ let maxY = -Infinity;
1939
+ for (const seat of matching) {
1940
+ minX = Math.min(minX, seat.x);
1941
+ maxX = Math.max(maxX, seat.x);
1942
+ minY = Math.min(minY, seat.y);
1943
+ maxY = Math.max(maxY, seat.y);
1944
+ }
1945
+ const pad = Math.max(24, this.seatR * 3);
1946
+ minX -= pad;
1947
+ maxX += pad;
1948
+ minY -= pad;
1949
+ maxY += pad;
1950
+ this.focusRegion(
1951
+ { x: minX, y: minY, width: Math.max(40, maxX - minX), height: Math.max(40, maxY - minY) },
1952
+ { durationMs: CAMERA_GLIDE_MS }
1953
+ );
1954
+ }
1920
1955
  // ---- isometric ("3D") view mode -------------------------------------------
1921
1956
  /**
1922
1957
  * Switch the projection between flat top-down and the isometric "3D" view
@@ -2246,8 +2281,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
2246
2281
  break;
2247
2282
  }
2248
2283
  if (boothLabel) {
2249
- const owned = status === "held" && this.ownedHold.has(id);
2250
- boothLabel.text(status === "booked" ? "SOLD" : status === "held" ? owned ? "HELD BY YOU" : "HELD" : seat.label);
2284
+ boothLabel.text(status === "booked" ? "SOLD" : status === "held" ? "HELD" : seat.label);
2251
2285
  boothLabel.fontSize(status === "free" ? 10 : Math.min(10, Math.max(6, this.boothDims.get(seat.rowId)?.width ?? 40) / 6));
2252
2286
  boothLabel.fontStyle(status === "free" ? "600" : "800");
2253
2287
  boothLabel.fill(status === "free" ? this.theme.seatLabelColor ?? DEF_SEAT_LABEL : "#ffffff");
@@ -3444,7 +3478,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
3444
3478
  }
3445
3479
  /**
3446
3480
  * Smoothly glide the camera to frame a section (by id) or a world-space bounds
3447
- * rect — the Slice 5 "glide in". Pan+zoom tween over ~450ms easeInOutCubic; the
3481
+ * rect — the Slice 5 "glide in". Pan+zoom tween over a calm easeInOutCubic; the
3448
3482
  * melt/LOD rides the camera every frame. `prefers-reduced-motion` (or
3449
3483
  * `opts.animate === false`) snaps via zoomToBounds. A grab (pointer-down) or a
3450
3484
  * newer glide cancels an in-flight one.
@@ -3476,13 +3510,13 @@ var _SeatmapRenderer = class _SeatmapRenderer {
3476
3510
  return;
3477
3511
  }
3478
3512
  const start = performance.now();
3479
- const DUR = 450;
3513
+ const duration = Math.max(180, Math.min(1200, opts?.durationMs ?? CAMERA_GLIDE_MS));
3480
3514
  const step = (now) => {
3481
3515
  if (this.destroyed) {
3482
3516
  this.glideRaf = 0;
3483
3517
  return;
3484
3518
  }
3485
- const raw = Math.min(1, (now - start) / DUR);
3519
+ const raw = Math.min(1, (now - start) / duration);
3486
3520
  const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;
3487
3521
  const sc = fromScale + (toScale - fromScale) * e;
3488
3522
  this.stage.scale({ x: sc, y: sc });
@@ -3607,15 +3641,49 @@ var _SeatmapRenderer = class _SeatmapRenderer {
3607
3641
  if (seat.kind === "booth") continue;
3608
3642
  if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;
3609
3643
  const status = this.statusById.get(seat.id) ?? "free";
3610
- const statusCue = status === "booked" ? "\xD7" : status === "held" && !this.ownedHold.has(seat.id) ? "H" : null;
3644
+ const unavailable = status === "booked" || status === "held" && !this.ownedHold.has(seat.id);
3645
+ if (unavailable) {
3646
+ const cue = new import_Group.Group({ x: seat.x, y: seat.y, listening: false });
3647
+ if (status === "held") {
3648
+ cue.add(new import_Rect.Rect({
3649
+ x: -4.2,
3650
+ y: -0.7,
3651
+ width: 8.4,
3652
+ height: 6.5,
3653
+ cornerRadius: 1.3,
3654
+ stroke: "#ffffff",
3655
+ strokeWidth: 1.25,
3656
+ listening: false
3657
+ }));
3658
+ cue.add(new import_Line.Line({
3659
+ points: [-2.4, -0.8, -2.4, -2.7, -1.2, -4, 0, -4.35, 1.2, -4, 2.4, -2.7, 2.4, -0.8],
3660
+ stroke: "#ffffff",
3661
+ strokeWidth: 1.2,
3662
+ lineCap: "round",
3663
+ lineJoin: "round",
3664
+ listening: false
3665
+ }));
3666
+ } else {
3667
+ cue.add(new import_Line.Line({
3668
+ points: [-4.2, 4.2, 4.2, -4.2],
3669
+ stroke: "#ffffff",
3670
+ strokeWidth: 1.8,
3671
+ lineCap: "round",
3672
+ listening: false
3673
+ }));
3674
+ }
3675
+ this.labelGroup.add(cue);
3676
+ if (++count >= MAX_LABELS) break;
3677
+ continue;
3678
+ }
3611
3679
  const t2 = new import_Text.Text({
3612
3680
  x: seat.x,
3613
3681
  y: seat.y,
3614
- text: statusCue ?? seat.label,
3615
- fontSize: statusCue ? status === "booked" ? 13 : 8 : 7,
3616
- fontStyle: statusCue ? "800" : "600",
3682
+ text: seat.label,
3683
+ fontSize: 7,
3684
+ fontStyle: "600",
3617
3685
  fontFamily: this.labelFont(),
3618
- fill: statusCue ? "#ffffff" : this.theme.seatLabelColor ?? DEF_SEAT_LABEL,
3686
+ fill: this.theme.seatLabelColor ?? DEF_SEAT_LABEL,
3619
3687
  listening: false,
3620
3688
  perfectDrawEnabled: false
3621
3689
  });
@@ -4272,6 +4340,17 @@ var PickerController = class {
4272
4340
  setCategoryFilter(keys) {
4273
4341
  this.renderer?.setCategoryFilter?.(keys);
4274
4342
  }
4343
+ /** An explicit buyer price-filter action should not only dim the rest of the
4344
+ * chart: clear any older section drill-in and guide the camera to the seats
4345
+ * that remain relevant. Clearing the filter glides back to the full chart. */
4346
+ focusCategoryFilter(keys) {
4347
+ const renderer = this.renderer;
4348
+ if (!renderer) return;
4349
+ renderer.clearSectionFocus?.();
4350
+ this.opts.onSectionFocus?.(null);
4351
+ if (renderer.focusCategories) renderer.focusCategories(keys);
4352
+ else renderer.zoomToFit();
4353
+ }
4275
4354
  /** World-space rect currently visible + full chart bounds (F3 minimap frame). */
4276
4355
  getViewport() {
4277
4356
  const r = this.renderer;