@seatlayer/core 0.15.1 → 0.16.1
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 +120 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +120 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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;
|
|
@@ -1589,6 +1590,24 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1589
1590
|
for (const id of ids) this.setSelected(id, false, true);
|
|
1590
1591
|
this.overlayLayer.batchDraw();
|
|
1591
1592
|
}
|
|
1593
|
+
setMaxSelection(maxSelection) {
|
|
1594
|
+
this.opts.maxSelection = Math.max(0, Math.floor(maxSelection));
|
|
1595
|
+
}
|
|
1596
|
+
select(seatIds) {
|
|
1597
|
+
const added = [];
|
|
1598
|
+
for (const id of seatIds) {
|
|
1599
|
+
if (this.selection.has(id) || !this.isSelectable(id)) continue;
|
|
1600
|
+
if (this.selection.size >= this.opts.maxSelection) {
|
|
1601
|
+
this.opts.onSelectionLimit?.(this.opts.maxSelection);
|
|
1602
|
+
break;
|
|
1603
|
+
}
|
|
1604
|
+
this.setSelected(id, true, true);
|
|
1605
|
+
const seat = this.seatById.get(id);
|
|
1606
|
+
if (seat) added.push(seat);
|
|
1607
|
+
}
|
|
1608
|
+
if (added.length) this.overlayLayer.batchDraw();
|
|
1609
|
+
return added;
|
|
1610
|
+
}
|
|
1592
1611
|
/** Switch organizer interaction in place so the host preserves camera, LOD,
|
|
1593
1612
|
* focus and live status state while moving between Monitor and Block. */
|
|
1594
1613
|
setManageInteraction(options) {
|
|
@@ -1917,6 +1936,40 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1917
1936
|
this.seatLayer.batchDraw();
|
|
1918
1937
|
}
|
|
1919
1938
|
}
|
|
1939
|
+
/** Frame the currently available inventory that survived a buyer price
|
|
1940
|
+
* filter. Clearing the filter glides back to the full venue. */
|
|
1941
|
+
focusCategories(keys) {
|
|
1942
|
+
if (!keys?.length) {
|
|
1943
|
+
this.focusRegion(this.bounds, { durationMs: CAMERA_GLIDE_MS });
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
const wanted = new Set(keys);
|
|
1947
|
+
const matching = this.seats.filter((seat) => {
|
|
1948
|
+
if (!wanted.has(seat.categoryKey) || this.seatInClosedSection(seat.id)) return false;
|
|
1949
|
+
const status = this.statusById.get(seat.id) ?? "free";
|
|
1950
|
+
return status === "free" || this.ownedHold.has(seat.id);
|
|
1951
|
+
});
|
|
1952
|
+
if (!matching.length) return;
|
|
1953
|
+
let minX = Infinity;
|
|
1954
|
+
let maxX = -Infinity;
|
|
1955
|
+
let minY = Infinity;
|
|
1956
|
+
let maxY = -Infinity;
|
|
1957
|
+
for (const seat of matching) {
|
|
1958
|
+
minX = Math.min(minX, seat.x);
|
|
1959
|
+
maxX = Math.max(maxX, seat.x);
|
|
1960
|
+
minY = Math.min(minY, seat.y);
|
|
1961
|
+
maxY = Math.max(maxY, seat.y);
|
|
1962
|
+
}
|
|
1963
|
+
const pad = Math.max(24, this.seatR * 3);
|
|
1964
|
+
minX -= pad;
|
|
1965
|
+
maxX += pad;
|
|
1966
|
+
minY -= pad;
|
|
1967
|
+
maxY += pad;
|
|
1968
|
+
this.focusRegion(
|
|
1969
|
+
{ x: minX, y: minY, width: Math.max(40, maxX - minX), height: Math.max(40, maxY - minY) },
|
|
1970
|
+
{ durationMs: CAMERA_GLIDE_MS }
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1920
1973
|
// ---- isometric ("3D") view mode -------------------------------------------
|
|
1921
1974
|
/**
|
|
1922
1975
|
* Switch the projection between flat top-down and the isometric "3D" view
|
|
@@ -3105,7 +3158,10 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3105
3158
|
if (seat) this.opts.onDeselect?.(seat);
|
|
3106
3159
|
} else {
|
|
3107
3160
|
if (!this.isSelectable(id)) return;
|
|
3108
|
-
if (this.selection.size >= this.opts.maxSelection)
|
|
3161
|
+
if (this.selection.size >= this.opts.maxSelection) {
|
|
3162
|
+
this.opts.onSelectionLimit?.(this.opts.maxSelection);
|
|
3163
|
+
return;
|
|
3164
|
+
}
|
|
3109
3165
|
this.setSelected(id, true);
|
|
3110
3166
|
const seat = this.seatById.get(id);
|
|
3111
3167
|
if (seat) this.opts.onSelect?.(seat);
|
|
@@ -3443,7 +3499,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3443
3499
|
}
|
|
3444
3500
|
/**
|
|
3445
3501
|
* Smoothly glide the camera to frame a section (by id) or a world-space bounds
|
|
3446
|
-
* rect — the Slice 5 "glide in". Pan+zoom tween over
|
|
3502
|
+
* rect — the Slice 5 "glide in". Pan+zoom tween over a calm easeInOutCubic; the
|
|
3447
3503
|
* melt/LOD rides the camera every frame. `prefers-reduced-motion` (or
|
|
3448
3504
|
* `opts.animate === false`) snaps via zoomToBounds. A grab (pointer-down) or a
|
|
3449
3505
|
* newer glide cancels an in-flight one.
|
|
@@ -3475,13 +3531,13 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3475
3531
|
return;
|
|
3476
3532
|
}
|
|
3477
3533
|
const start = performance.now();
|
|
3478
|
-
const
|
|
3534
|
+
const duration = Math.max(180, Math.min(1200, opts?.durationMs ?? CAMERA_GLIDE_MS));
|
|
3479
3535
|
const step = (now) => {
|
|
3480
3536
|
if (this.destroyed) {
|
|
3481
3537
|
this.glideRaf = 0;
|
|
3482
3538
|
return;
|
|
3483
3539
|
}
|
|
3484
|
-
const raw = Math.min(1, (now - start) /
|
|
3540
|
+
const raw = Math.min(1, (now - start) / duration);
|
|
3485
3541
|
const e = raw < 0.5 ? 4 * raw * raw * raw : 1 - Math.pow(-2 * raw + 2, 3) / 2;
|
|
3486
3542
|
const sc = fromScale + (toScale - fromScale) * e;
|
|
3487
3543
|
this.stage.scale({ x: sc, y: sc });
|
|
@@ -3606,15 +3662,49 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3606
3662
|
if (seat.kind === "booth") continue;
|
|
3607
3663
|
if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;
|
|
3608
3664
|
const status = this.statusById.get(seat.id) ?? "free";
|
|
3609
|
-
const
|
|
3665
|
+
const unavailable = status === "booked" || status === "held" && !this.ownedHold.has(seat.id);
|
|
3666
|
+
if (unavailable) {
|
|
3667
|
+
const cue = new import_Group.Group({ x: seat.x, y: seat.y, listening: false });
|
|
3668
|
+
if (status === "held") {
|
|
3669
|
+
cue.add(new import_Rect.Rect({
|
|
3670
|
+
x: -4.2,
|
|
3671
|
+
y: -0.7,
|
|
3672
|
+
width: 8.4,
|
|
3673
|
+
height: 6.5,
|
|
3674
|
+
cornerRadius: 1.3,
|
|
3675
|
+
stroke: "#ffffff",
|
|
3676
|
+
strokeWidth: 1.25,
|
|
3677
|
+
listening: false
|
|
3678
|
+
}));
|
|
3679
|
+
cue.add(new import_Line.Line({
|
|
3680
|
+
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],
|
|
3681
|
+
stroke: "#ffffff",
|
|
3682
|
+
strokeWidth: 1.2,
|
|
3683
|
+
lineCap: "round",
|
|
3684
|
+
lineJoin: "round",
|
|
3685
|
+
listening: false
|
|
3686
|
+
}));
|
|
3687
|
+
} else {
|
|
3688
|
+
cue.add(new import_Line.Line({
|
|
3689
|
+
points: [-4.2, 4.2, 4.2, -4.2],
|
|
3690
|
+
stroke: "#ffffff",
|
|
3691
|
+
strokeWidth: 1.8,
|
|
3692
|
+
lineCap: "round",
|
|
3693
|
+
listening: false
|
|
3694
|
+
}));
|
|
3695
|
+
}
|
|
3696
|
+
this.labelGroup.add(cue);
|
|
3697
|
+
if (++count >= MAX_LABELS) break;
|
|
3698
|
+
continue;
|
|
3699
|
+
}
|
|
3610
3700
|
const t2 = new import_Text.Text({
|
|
3611
3701
|
x: seat.x,
|
|
3612
3702
|
y: seat.y,
|
|
3613
|
-
text:
|
|
3614
|
-
fontSize:
|
|
3615
|
-
fontStyle:
|
|
3703
|
+
text: seat.label,
|
|
3704
|
+
fontSize: 7,
|
|
3705
|
+
fontStyle: "600",
|
|
3616
3706
|
fontFamily: this.labelFont(),
|
|
3617
|
-
fill:
|
|
3707
|
+
fill: this.theme.seatLabelColor ?? DEF_SEAT_LABEL,
|
|
3618
3708
|
listening: false,
|
|
3619
3709
|
perfectDrawEnabled: false
|
|
3620
3710
|
});
|
|
@@ -3838,6 +3928,7 @@ var PickerController = class {
|
|
|
3838
3928
|
this.opts.onDeselect?.(seat);
|
|
3839
3929
|
this.emitSelectionChange();
|
|
3840
3930
|
},
|
|
3931
|
+
onSelectionLimit: this.opts.onSelectionLimit,
|
|
3841
3932
|
onHover: (seat) => {
|
|
3842
3933
|
this.opts.onHover?.(seat);
|
|
3843
3934
|
if (this.opts.onSeatHover) this.opts.onSeatHover(seat ? this.describeSeat(seat) : null);
|
|
@@ -3905,6 +3996,15 @@ var PickerController = class {
|
|
|
3905
3996
|
this.renderer?.deselect(ids);
|
|
3906
3997
|
this.emitSelectionChange();
|
|
3907
3998
|
}
|
|
3999
|
+
setMaxSelection(maxSelection) {
|
|
4000
|
+
this.maxSelection = Math.max(0, Math.floor(maxSelection));
|
|
4001
|
+
this.renderer?.setMaxSelection?.(this.maxSelection);
|
|
4002
|
+
}
|
|
4003
|
+
select(ids) {
|
|
4004
|
+
const added = this.renderer?.select?.(ids) ?? [];
|
|
4005
|
+
if (added.length) this.emitSelectionChange();
|
|
4006
|
+
return added.map((seat) => this.toSeat(seat));
|
|
4007
|
+
}
|
|
3908
4008
|
// ---- booking machine ------------------------------------------------------
|
|
3909
4009
|
/**
|
|
3910
4010
|
* Hold the current selection (or a given label set). The controller does the
|
|
@@ -4271,6 +4371,17 @@ var PickerController = class {
|
|
|
4271
4371
|
setCategoryFilter(keys) {
|
|
4272
4372
|
this.renderer?.setCategoryFilter?.(keys);
|
|
4273
4373
|
}
|
|
4374
|
+
/** An explicit buyer price-filter action should not only dim the rest of the
|
|
4375
|
+
* chart: clear any older section drill-in and guide the camera to the seats
|
|
4376
|
+
* that remain relevant. Clearing the filter glides back to the full chart. */
|
|
4377
|
+
focusCategoryFilter(keys) {
|
|
4378
|
+
const renderer = this.renderer;
|
|
4379
|
+
if (!renderer) return;
|
|
4380
|
+
renderer.clearSectionFocus?.();
|
|
4381
|
+
this.opts.onSectionFocus?.(null);
|
|
4382
|
+
if (renderer.focusCategories) renderer.focusCategories(keys);
|
|
4383
|
+
else renderer.zoomToFit();
|
|
4384
|
+
}
|
|
4274
4385
|
/** World-space rect currently visible + full chart bounds (F3 minimap frame). */
|
|
4275
4386
|
getViewport() {
|
|
4276
4387
|
const r = this.renderer;
|