@seatlayer/core 0.51.0 → 0.52.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/{chunk-GD267BFB.js → chunk-UID7KN44.js} +75 -2
- package/dist/chunk-UID7KN44.js.map +1 -0
- package/dist/core/seatConfidence.d.cts +1 -1
- package/dist/core/seatConfidence.d.ts +1 -1
- package/dist/{de-V53JPFHN.js → de-YGODYJ3E.js} +3 -3
- package/dist/de-YGODYJ3E.js.map +1 -0
- package/dist/{es-37ISLCZA.js → es-VMBTGVFQ.js} +3 -3
- package/dist/es-VMBTGVFQ.js.map +1 -0
- package/dist/{fr-QKK2T64Q.js → fr-SLBE2ULB.js} +3 -3
- package/dist/fr-SLBE2ULB.js.map +1 -0
- package/dist/index.cjs +647 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +131 -17
- package/dist/index.d.ts +131 -17
- package/dist/index.js +575 -58
- package/dist/index.js.map +1 -1
- package/dist/picker/minimapGeometry.cjs +80 -0
- package/dist/picker/minimapGeometry.cjs.map +1 -0
- package/dist/picker/minimapGeometry.d.cts +37 -0
- package/dist/picker/minimapGeometry.d.ts +37 -0
- package/dist/picker/minimapGeometry.js +52 -0
- package/dist/picker/minimapGeometry.js.map +1 -0
- package/dist/{types-DR54nqKL.d.cts → types-tLOunI-B.d.cts} +131 -1
- package/dist/{types-DR54nqKL.d.ts → types-tLOunI-B.d.ts} +131 -1
- package/dist/view3d/crossfade/panorama.d.cts +1 -1
- package/dist/view3d/crossfade/panorama.d.ts +1 -1
- package/dist/view3d/index.cjs +1158 -123
- package/dist/view3d/index.cjs.map +1 -1
- package/dist/view3d/index.d.cts +20 -12
- package/dist/view3d/index.d.ts +20 -12
- package/dist/view3d/index.js +1158 -122
- package/dist/view3d/index.js.map +1 -1
- package/package.json +14 -1
- package/dist/chunk-GD267BFB.js.map +0 -1
- package/dist/de-V53JPFHN.js.map +0 -1
- package/dist/es-37ISLCZA.js.map +0 -1
- package/dist/fr-QKK2T64Q.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,8 @@ var init_es = __esm({
|
|
|
45
45
|
"picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
|
|
46
46
|
"picker.testMode": "MODO DE PRUEBA",
|
|
47
47
|
"picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
|
|
48
|
+
"picker.companionRequiresWheelchair": "Requiere la plaza accesible contigua",
|
|
49
|
+
"picker.companionPairRequired": "Selecciona la plaza accesible contigua con cada entrada de acompa\xF1ante.",
|
|
48
50
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
49
51
|
"map.aria": "Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.",
|
|
50
52
|
"map.seatsLeft": "{count} LIBRES",
|
|
@@ -156,8 +158,6 @@ var init_es = __esm({
|
|
|
156
158
|
"picker.fewerGuests": "Menos invitados",
|
|
157
159
|
"picker.fewerSeats": "Menos asientos",
|
|
158
160
|
"picker.filterAndFocusByPrice": "Filtrar y enfocar asientos por precio",
|
|
159
|
-
"picker.filteredSeat": "No disponible con los filtros actuales",
|
|
160
|
-
"picker.filteredSeatExplanation": "Cambia el filtro de precio o vista activo para poder seleccionar este asiento.",
|
|
161
161
|
"picker.filters": "Filtros",
|
|
162
162
|
"picker.findBestSeatsCount.one": "Buscar {count} mejor asiento",
|
|
163
163
|
"picker.findBestSeatsCount.other": "Buscar {count} mejores asientos",
|
|
@@ -344,6 +344,8 @@ var init_de = __esm({
|
|
|
344
344
|
"picker.poweredBy": "Bereitgestellt von SeatLayer",
|
|
345
345
|
"picker.testMode": "TESTMODUS",
|
|
346
346
|
"picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
|
|
347
|
+
"picker.companionRequiresWheelchair": "Benachbarter Rollstuhlplatz erforderlich",
|
|
348
|
+
"picker.companionPairRequired": "W\xE4hlen Sie zu jedem Begleitticket den benachbarten Rollstuhlplatz aus.",
|
|
347
349
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
348
350
|
"map.aria": "Sitzplan. Mit Pfeiltasten zwischen Pl\xE4tzen navigieren, Eingabe zum Ausw\xE4hlen.",
|
|
349
351
|
"map.seatsLeft": "{count} FREI",
|
|
@@ -455,8 +457,6 @@ var init_de = __esm({
|
|
|
455
457
|
"picker.fewerGuests": "Weniger G\xE4ste",
|
|
456
458
|
"picker.fewerSeats": "Weniger Pl\xE4tze",
|
|
457
459
|
"picker.filterAndFocusByPrice": "Pl\xE4tze nach Preis filtern und fokussieren",
|
|
458
|
-
"picker.filteredSeat": "Mit aktuellen Filtern nicht verf\xFCgbar",
|
|
459
|
-
"picker.filteredSeatExplanation": "\xC4ndern Sie den aktiven Preis- oder Ansichtsfilter, um diesen Platz ausw\xE4hlbar zu machen.",
|
|
460
460
|
"picker.filters": "Filter",
|
|
461
461
|
"picker.findBestSeatsCount.one": "{count} besten Platz finden",
|
|
462
462
|
"picker.findBestSeatsCount.other": "{count} beste Pl\xE4tze finden",
|
|
@@ -643,6 +643,8 @@ var init_fr = __esm({
|
|
|
643
643
|
"picker.poweredBy": "Propuls\xE9 par SeatLayer",
|
|
644
644
|
"picker.testMode": "MODE TEST",
|
|
645
645
|
"picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
|
|
646
|
+
"picker.companionRequiresWheelchair": "N\xE9cessite la place fauteuil roulant adjacente",
|
|
647
|
+
"picker.companionPairRequired": "S\xE9lectionnez la place fauteuil roulant adjacente avec chaque billet accompagnateur.",
|
|
646
648
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
647
649
|
"map.aria": "Plan de salle. Utilisez les fl\xE8ches pour naviguer entre les si\xE8ges, Entr\xE9e pour s\xE9lectionner.",
|
|
648
650
|
"map.seatsLeft": "{count} LIBRES",
|
|
@@ -754,8 +756,6 @@ var init_fr = __esm({
|
|
|
754
756
|
"picker.fewerGuests": "Moins d\u2019invit\xE9s",
|
|
755
757
|
"picker.fewerSeats": "Moins de places",
|
|
756
758
|
"picker.filterAndFocusByPrice": "Filtrer et cibler les places par prix",
|
|
757
|
-
"picker.filteredSeat": "Indisponible avec les filtres actuels",
|
|
758
|
-
"picker.filteredSeatExplanation": "Modifiez le filtre de prix ou de vue actif pour rendre cette place s\xE9lectionnable.",
|
|
759
759
|
"picker.filters": "Filtres",
|
|
760
760
|
"picker.findBestSeatsCount.one": "Trouver {count} meilleure place",
|
|
761
761
|
"picker.findBestSeatsCount.other": "Trouver {count} meilleures places",
|
|
@@ -935,6 +935,7 @@ __export(index_exports, {
|
|
|
935
935
|
MAX_EVENT_INVENTORY: () => MAX_EVENT_INVENTORY,
|
|
936
936
|
MAX_GA_CAPACITY: () => MAX_GA_CAPACITY,
|
|
937
937
|
PickerController: () => PickerController,
|
|
938
|
+
PickerSelectionError: () => PickerSelectionError,
|
|
938
939
|
RENDERED_QUALITY_REPORT_VERSION: () => RENDERED_QUALITY_REPORT_VERSION,
|
|
939
940
|
SEAT_COMMERCIAL_MARKS: () => SEAT_COMMERCIAL_MARKS,
|
|
940
941
|
SUPPORTED_LOCALES: () => SUPPORTED_LOCALES,
|
|
@@ -958,6 +959,7 @@ __export(index_exports, {
|
|
|
958
959
|
expandTable: () => expandTable,
|
|
959
960
|
expandTableSlots: () => expandTableSlots,
|
|
960
961
|
floorObjects: () => floorObjects,
|
|
962
|
+
floorOverviewTranslations: () => floorOverviewTranslations,
|
|
961
963
|
floorsOf: () => floorsOf,
|
|
962
964
|
formatDate: () => formatDate,
|
|
963
965
|
formatMinor: () => formatMinor,
|
|
@@ -976,6 +978,7 @@ __export(index_exports, {
|
|
|
976
978
|
isGaUnitLabel: () => isGaUnitLabel,
|
|
977
979
|
isSectionHidden: () => isSectionHidden,
|
|
978
980
|
layerOf: () => layerOf,
|
|
981
|
+
layoutFloorOverview: () => layoutFloorOverview,
|
|
979
982
|
loadLocale: () => loadLocale,
|
|
980
983
|
objectCenter: () => objectCenter,
|
|
981
984
|
owningSectionForObject: () => owningSectionForObject,
|
|
@@ -995,6 +998,7 @@ __export(index_exports, {
|
|
|
995
998
|
tCount: () => tCount,
|
|
996
999
|
tableInventoryCount: () => tableInventoryCount,
|
|
997
1000
|
tableSeatCountsBySide: () => tableSeatCountsBySide,
|
|
1001
|
+
translateObject: () => translateObject,
|
|
998
1002
|
validGAInventorySegments: () => validGAInventorySegments
|
|
999
1003
|
});
|
|
1000
1004
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -1345,7 +1349,7 @@ function resolveSegmentedRowGroups(objects) {
|
|
|
1345
1349
|
const expectedCount = ordered[0]?.segmentedRow?.componentCount ?? 0;
|
|
1346
1350
|
const first = ordered[0]?.segmentedRow;
|
|
1347
1351
|
if (!first) continue;
|
|
1348
|
-
const valid = expectedCount >= 2 && ordered.length === expectedCount && first?.boundaryBefore === "start" && ordered.every((row, index) => row.segmentedRow?.kind === "segmented-row-v1" && row.segmentedRow.groupId === groupId && row.segmentedRow.componentCount === expectedCount && row.segmentedRow.componentIndex === index && (index === 0 ? row.segmentedRow.boundaryBefore === "start" : row.segmentedRow.boundaryBefore !== "start") && row.segmentedRow.displayLabel === first.displayLabel);
|
|
1352
|
+
const valid = expectedCount >= 2 && ordered.length === expectedCount && first?.boundaryBefore === "start" && ordered.every((row, index) => row.segmentedRow?.kind === "segmented-row-v1" && row.segmentedRow.groupId === groupId && row.segmentedRow.componentCount === expectedCount && row.segmentedRow.componentIndex === index && row.segmentedRow.repeatLabelOnComponents === first.repeatLabelOnComponents && (index === 0 ? row.segmentedRow.boundaryBefore === "start" : row.segmentedRow.boundaryBefore !== "start") && row.segmentedRow.displayLabel === first.displayLabel);
|
|
1349
1353
|
if (!valid) continue;
|
|
1350
1354
|
const totalSeats = ordered.reduce((sum, row) => sum + row.seatCount, 0);
|
|
1351
1355
|
let adjacencyOffset = 0;
|
|
@@ -2239,6 +2243,75 @@ function stackFloors(doc, spread = 900) {
|
|
|
2239
2243
|
});
|
|
2240
2244
|
return { ...doc, objects, floors: void 0 };
|
|
2241
2245
|
}
|
|
2246
|
+
function layoutFloorOverview(doc) {
|
|
2247
|
+
const floors = doc.floors;
|
|
2248
|
+
if (!floors || floors.length < 2) return doc;
|
|
2249
|
+
const translations = floorOverviewTranslations(doc);
|
|
2250
|
+
const objects = [];
|
|
2251
|
+
floors.forEach((floor, index) => {
|
|
2252
|
+
const { x: dx, y: dy } = translations[index];
|
|
2253
|
+
for (const object of floor.objects) objects.push(translateObject(object, dx, dy));
|
|
2254
|
+
});
|
|
2255
|
+
return {
|
|
2256
|
+
...doc,
|
|
2257
|
+
objects,
|
|
2258
|
+
floors: void 0,
|
|
2259
|
+
referenceImage: void 0,
|
|
2260
|
+
backgroundImage: void 0
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
function floorOverviewTranslations(doc) {
|
|
2264
|
+
const floors = doc.floors;
|
|
2265
|
+
if (!floors?.length) return [{ x: 0, y: 0 }];
|
|
2266
|
+
if (floors.length < 2) return floors.map(() => ({ x: 0, y: 0 }));
|
|
2267
|
+
const bounds2 = floors.map((floor) => chartBounds({
|
|
2268
|
+
...doc,
|
|
2269
|
+
objects: floor.objects,
|
|
2270
|
+
floors: void 0,
|
|
2271
|
+
focalPoint: floor.focalPoint,
|
|
2272
|
+
referenceImage: void 0,
|
|
2273
|
+
backgroundImage: void 0
|
|
2274
|
+
}));
|
|
2275
|
+
const characteristic = Math.max(1, ...bounds2.map((bound) => Math.max(bound.width, bound.height)));
|
|
2276
|
+
const gap = Math.max(64, Math.min(240, characteristic * 0.08));
|
|
2277
|
+
const targetAspect = 16 / 10;
|
|
2278
|
+
let best = null;
|
|
2279
|
+
for (let columns2 = 1; columns2 <= floors.length; columns2 += 1) {
|
|
2280
|
+
const rows = Math.ceil(floors.length / columns2);
|
|
2281
|
+
const columnWidths2 = new Array(columns2).fill(0);
|
|
2282
|
+
const rowHeights2 = new Array(rows).fill(0);
|
|
2283
|
+
bounds2.forEach((bound, index) => {
|
|
2284
|
+
const column = index % columns2;
|
|
2285
|
+
const row = Math.floor(index / columns2);
|
|
2286
|
+
columnWidths2[column] = Math.max(columnWidths2[column], bound.width);
|
|
2287
|
+
rowHeights2[row] = Math.max(rowHeights2[row], bound.height);
|
|
2288
|
+
});
|
|
2289
|
+
const width = columnWidths2.reduce((sum, value) => sum + value, 0) + gap * (columns2 - 1);
|
|
2290
|
+
const height = rowHeights2.reduce((sum, value) => sum + value, 0) + gap * (rows - 1);
|
|
2291
|
+
const unusedCells = columns2 * rows - floors.length;
|
|
2292
|
+
const score = Math.abs(Math.log(width / Math.max(1, height) / targetAspect)) + unusedCells * 0.04;
|
|
2293
|
+
if (!best || score < best.score) best = { columns: columns2, columnWidths: columnWidths2, rowHeights: rowHeights2, score };
|
|
2294
|
+
}
|
|
2295
|
+
const { columns, columnWidths, rowHeights } = best;
|
|
2296
|
+
const columnOffsets = [];
|
|
2297
|
+
const rowOffsets = [];
|
|
2298
|
+
columnWidths.reduce((offset, width, index) => {
|
|
2299
|
+
columnOffsets[index] = offset;
|
|
2300
|
+
return offset + width + gap;
|
|
2301
|
+
}, 0);
|
|
2302
|
+
rowHeights.reduce((offset, height, index) => {
|
|
2303
|
+
rowOffsets[index] = offset;
|
|
2304
|
+
return offset + height + gap;
|
|
2305
|
+
}, 0);
|
|
2306
|
+
return floors.map((_floor, index) => {
|
|
2307
|
+
const bound = bounds2[index];
|
|
2308
|
+
const column = index % columns;
|
|
2309
|
+
const row = Math.floor(index / columns);
|
|
2310
|
+
const targetX = columnOffsets[column] + (columnWidths[column] - bound.width) / 2;
|
|
2311
|
+
const targetY = rowOffsets[row] + (rowHeights[row] - bound.height) / 2;
|
|
2312
|
+
return { x: targetX - bound.x, y: targetY - bound.y };
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2242
2315
|
function expandFloorObjects(objects, zones, fallbackFocal, activeConfigurationId, viewFallback, confidenceFallback) {
|
|
2243
2316
|
const out = [];
|
|
2244
2317
|
const segmented = resolveSegmentedRowGroups(objects);
|
|
@@ -3697,6 +3770,8 @@ var en = {
|
|
|
3697
3770
|
"picker.poweredBy": "Powered by SeatLayer",
|
|
3698
3771
|
"picker.testMode": "TEST MODE",
|
|
3699
3772
|
"picker.orphanHint": "This leaves a single seat stranded \u2014 consider shifting one seat over.",
|
|
3773
|
+
"picker.companionRequiresWheelchair": "Requires the adjacent wheelchair place",
|
|
3774
|
+
"picker.companionPairRequired": "Select the adjacent wheelchair place with each companion ticket.",
|
|
3700
3775
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
3701
3776
|
"map.aria": "Seating map. Use arrow keys to move between seats, Enter to select.",
|
|
3702
3777
|
"map.seatsLeft": "{count} LEFT",
|
|
@@ -3808,8 +3883,6 @@ var en = {
|
|
|
3808
3883
|
"picker.fewerGuests": "Fewer guests",
|
|
3809
3884
|
"picker.fewerSeats": "Fewer seats",
|
|
3810
3885
|
"picker.filterAndFocusByPrice": "Filter and focus seats by price",
|
|
3811
|
-
"picker.filteredSeat": "Unavailable with current filters",
|
|
3812
|
-
"picker.filteredSeatExplanation": "Change the active price or view filters to make this seat selectable.",
|
|
3813
3886
|
"picker.filters": "Filters",
|
|
3814
3887
|
"picker.findBestSeatsCount.one": "Find {count} best seat",
|
|
3815
3888
|
"picker.findBestSeatsCount.other": "Find {count} best seats",
|
|
@@ -4045,10 +4118,11 @@ var WHEELCHAIR_GLYPH_MIN_PX = 10;
|
|
|
4045
4118
|
var FILTERED_WHEELCHAIR_GLYPH_MIN_PX = 14;
|
|
4046
4119
|
var SECTION_PROMINENT_SCALE = 0.45 * SEAT_LEGIBLE_SCALE;
|
|
4047
4120
|
var BLOCK_MELT_TOP = 0.9 * SEAT_LEGIBLE_SCALE;
|
|
4048
|
-
var
|
|
4121
|
+
var SEAT_DETAIL_SCALE = Math.max(SEAT_LEGIBLE_SCALE * 1.1, BLOCK_MELT_TOP);
|
|
4049
4122
|
var PAN_START_SLOP_PX = 8;
|
|
4050
4123
|
var GHOST_CLICK_MS = 700;
|
|
4051
4124
|
var ROW_LABEL_CLEARANCE = 2;
|
|
4125
|
+
var FOCUSED_ROW_LABEL_MIN_PX = MIN_VISIBLE_BOOKABLE_LABEL_PX;
|
|
4052
4126
|
var ROW_LABEL_COLLISION_CELL = 64;
|
|
4053
4127
|
var ZONE_PROMINENT_SCALE = 0.55 * SECTION_PROMINENT_SCALE;
|
|
4054
4128
|
var MAX_LABELS = 700;
|
|
@@ -4444,6 +4518,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4444
4518
|
this.activeFloorId = "";
|
|
4445
4519
|
/** When true on a multi-floor chart, render ALL floors stacked (3D overview). */
|
|
4446
4520
|
this.stacked = false;
|
|
4521
|
+
/** Buyer-facing 2D overview: floors are rigidly arranged without altering topology. */
|
|
4522
|
+
this.floorOverview = false;
|
|
4447
4523
|
/** Interactive node per seat/booth — a Circle for seats, a Rect for booths. */
|
|
4448
4524
|
this.circleById = /* @__PURE__ */ new Map();
|
|
4449
4525
|
/** Booth block geometry, keyed by booth id (= the unit's rowId). */
|
|
@@ -4699,6 +4775,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4699
4775
|
return;
|
|
4700
4776
|
}
|
|
4701
4777
|
if (this.pinch && this.pointers.size >= 2) {
|
|
4778
|
+
this.releaseSectionFocusDim();
|
|
4702
4779
|
const [a, b] = [...this.pointers.values()];
|
|
4703
4780
|
const dist = Math.hypot(b.x - a.x, b.y - a.y);
|
|
4704
4781
|
if (this.pinch.startDist < 1) return;
|
|
@@ -4717,6 +4794,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4717
4794
|
if (!this.panStarted) {
|
|
4718
4795
|
if (this.moved <= PAN_START_SLOP_PX) return;
|
|
4719
4796
|
this.panStarted = true;
|
|
4797
|
+
this.releaseSectionFocusDim();
|
|
4720
4798
|
}
|
|
4721
4799
|
this.stage.position({
|
|
4722
4800
|
x: this.stage.x() + (p.x - this.panLast.x),
|
|
@@ -4837,13 +4915,23 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4837
4915
|
}
|
|
4838
4916
|
// ---- ISeatmapRenderer -----------------------------------------------------
|
|
4839
4917
|
setChart(doc, opts) {
|
|
4840
|
-
if (doc !== this.chartDoc)
|
|
4918
|
+
if (doc !== this.chartDoc) {
|
|
4919
|
+
this.stacked = false;
|
|
4920
|
+
this.floorOverview = false;
|
|
4921
|
+
}
|
|
4841
4922
|
this.cancelAssetLoads();
|
|
4842
4923
|
this.chartDoc = doc;
|
|
4843
4924
|
this.activeFloorId = opts?.floorId ?? floorsOf(doc)[0].id;
|
|
4844
4925
|
this.objectFloor.clear();
|
|
4845
4926
|
if (doc.floors && doc.floors.length > 1) {
|
|
4846
|
-
for (const f of doc.floors)
|
|
4927
|
+
for (const f of doc.floors) {
|
|
4928
|
+
for (const o of f.objects) {
|
|
4929
|
+
this.objectFloor.set(o.id, f.id);
|
|
4930
|
+
if (o.type === "section" && o.logicalSectionId) {
|
|
4931
|
+
this.objectFloor.set(o.logicalSectionId, f.id);
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4847
4935
|
}
|
|
4848
4936
|
const view = this.floorView(doc);
|
|
4849
4937
|
this.focusedId = null;
|
|
@@ -4941,7 +5029,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4941
5029
|
this.seats = expandChart(view, {
|
|
4942
5030
|
// A stacked overview is presentation-only and never opens a seat POV. The
|
|
4943
5031
|
// per-section renderer below still resolves each object's real floor base.
|
|
4944
|
-
floorBaseHeightM: this.stacked ? 0 : this.floorBaseHeightMFor()
|
|
5032
|
+
floorBaseHeightM: this.stacked || this.floorOverview ? 0 : this.floorBaseHeightMFor()
|
|
4945
5033
|
});
|
|
4946
5034
|
for (const s of this.seats) {
|
|
4947
5035
|
this.seatById.set(s.id, s);
|
|
@@ -4962,14 +5050,21 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4962
5050
|
this.overlayLayer.add(this.focusRing);
|
|
4963
5051
|
this.zoomToFit();
|
|
4964
5052
|
}
|
|
4965
|
-
/** The chart to render:
|
|
4966
|
-
* the whole chart for single-floor charts. */
|
|
5053
|
+
/** The chart to render: authored-coordinate overview, stacked 3D overview,
|
|
5054
|
+
* the active floor, or the whole chart for single-floor charts. */
|
|
4967
5055
|
floorView(doc) {
|
|
4968
5056
|
if (!doc.floors || !doc.floors.length) return {
|
|
4969
5057
|
...doc,
|
|
4970
5058
|
referenceImage: void 0,
|
|
4971
5059
|
backgroundImage: buyerBackgroundImage(doc)
|
|
4972
5060
|
};
|
|
5061
|
+
if (this.floorOverview && doc.floors.length >= 2) {
|
|
5062
|
+
return {
|
|
5063
|
+
...layoutFloorOverview(doc),
|
|
5064
|
+
referenceImage: void 0,
|
|
5065
|
+
backgroundImage: buyerBackgroundImage(doc)
|
|
5066
|
+
};
|
|
5067
|
+
}
|
|
4973
5068
|
if (this.stacked && doc.floors.length >= 2) {
|
|
4974
5069
|
return {
|
|
4975
5070
|
...stackFloors(doc),
|
|
@@ -5002,14 +5097,30 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5002
5097
|
const multi = !!this.chartDoc.floors && this.chartDoc.floors.length >= 2;
|
|
5003
5098
|
if (!multi) return;
|
|
5004
5099
|
this.stacked = on;
|
|
5100
|
+
if (on) this.floorOverview = false;
|
|
5005
5101
|
this.setChart(this.chartDoc, { floorId: this.activeFloorId });
|
|
5006
5102
|
}
|
|
5007
5103
|
isStacked() {
|
|
5008
5104
|
return this.stacked;
|
|
5009
5105
|
}
|
|
5106
|
+
/** Toggle the buyer's combined 2D floor overview. Every floor is translated
|
|
5107
|
+
* as one rigid group for clarity; its authored internal topology is exact. */
|
|
5108
|
+
setFloorOverview(on) {
|
|
5109
|
+
if (!this.chartDoc || on === this.floorOverview) return;
|
|
5110
|
+
const multi = !!this.chartDoc.floors && this.chartDoc.floors.length >= 2;
|
|
5111
|
+
if (!multi) return;
|
|
5112
|
+
this.floorOverview = on;
|
|
5113
|
+
if (on) this.stacked = false;
|
|
5114
|
+
this.setChart(this.chartDoc, { floorId: this.activeFloorId });
|
|
5115
|
+
}
|
|
5116
|
+
isFloorOverview() {
|
|
5117
|
+
return this.floorOverview;
|
|
5118
|
+
}
|
|
5010
5119
|
/** Switch which floor is shown (2D). Re-renders + re-fits; no-op if unchanged. */
|
|
5011
5120
|
setActiveFloor(floorId) {
|
|
5012
|
-
if (!this.chartDoc || floorId === this.activeFloorId) return;
|
|
5121
|
+
if (!this.chartDoc || floorId === this.activeFloorId && !this.floorOverview && !this.stacked) return;
|
|
5122
|
+
this.floorOverview = false;
|
|
5123
|
+
this.stacked = false;
|
|
5013
5124
|
this.setChart(this.chartDoc, { floorId });
|
|
5014
5125
|
}
|
|
5015
5126
|
/** Floors for the host's switcher (single-floor charts return one synthetic floor). */
|
|
@@ -5468,6 +5579,13 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5468
5579
|
const h = this.stage.height();
|
|
5469
5580
|
const b = this.viewMode === "perspective" && this.perspectiveBounds ? this.perspectiveBounds : this.bounds;
|
|
5470
5581
|
this.fitScale = Math.min(w / b.width, h / b.height) || 1;
|
|
5582
|
+
if (this.opts.portraitFitCrop && !this.exportMode) {
|
|
5583
|
+
const widthBound = w / b.width <= h / b.height;
|
|
5584
|
+
const projectedH = b.height * this.fitScale;
|
|
5585
|
+
if (widthBound && projectedH < 0.55 * h) {
|
|
5586
|
+
this.fitScale = Math.min(this.fitScale * 1.3, 0.62 * h / b.height);
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5471
5589
|
const s = this.fitScale;
|
|
5472
5590
|
this.stage.scale({ x: s, y: s });
|
|
5473
5591
|
this.stage.position({
|
|
@@ -5477,6 +5595,18 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5477
5595
|
this.afterViewChange();
|
|
5478
5596
|
this.stage.batchDraw();
|
|
5479
5597
|
}
|
|
5598
|
+
/**
|
|
5599
|
+
* Reframe after a host/layout resize without throwing away section context.
|
|
5600
|
+
* The stage already represents the usable map area (the picker side panel is
|
|
5601
|
+
* a sibling), so measuring it here naturally respects open/closed panels.
|
|
5602
|
+
*/
|
|
5603
|
+
refitCurrentView() {
|
|
5604
|
+
if (this.focusedSectionId && this.sectionBounds(this.focusedSectionId)) {
|
|
5605
|
+
this.focusRegion(this.focusedSectionId, { animate: false });
|
|
5606
|
+
return;
|
|
5607
|
+
}
|
|
5608
|
+
this.zoomToFit();
|
|
5609
|
+
}
|
|
5480
5610
|
zoomIn() {
|
|
5481
5611
|
const center = { x: this.stage.width() / 2, y: this.stage.height() / 2 };
|
|
5482
5612
|
this.zoomAbout(this.stage.scaleX() * _SeatmapRenderer.ZOOM_STEP, center);
|
|
@@ -6567,8 +6697,9 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6567
6697
|
}
|
|
6568
6698
|
/**
|
|
6569
6699
|
* AXS section-focus: dim + desaturate every other section, draw a calm backdrop
|
|
6570
|
-
* panel behind this section's seats, and glide the camera
|
|
6571
|
-
*
|
|
6700
|
+
* panel behind this section's seats, and glide the camera to a padded fit of
|
|
6701
|
+
* the whole section. A large section may therefore use smaller seat markers,
|
|
6702
|
+
* but it never clips its outer rows merely to meet a fixed detail scale.
|
|
6572
6703
|
*/
|
|
6573
6704
|
focusSection(id) {
|
|
6574
6705
|
if (!this.sections.some((section) => section.id === id || section.logicalId === id)) return;
|
|
@@ -6577,7 +6708,24 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6577
6708
|
this.bgLayer.batchDraw();
|
|
6578
6709
|
this.overlayLayer.batchDraw();
|
|
6579
6710
|
this.updateLOD();
|
|
6580
|
-
this.focusRegion(id
|
|
6711
|
+
this.focusRegion(id);
|
|
6712
|
+
}
|
|
6713
|
+
/**
|
|
6714
|
+
* Release only the focus dim + backdrop, keeping the focused-section state
|
|
6715
|
+
* (summary card, adjacent-section navigation, LOD) intact. Called on the
|
|
6716
|
+
* buyer's first manual pan/pinch/wheel after a section glide: the dim reads
|
|
6717
|
+
* as "everything else is disabled", but every seat outside the focus was
|
|
6718
|
+
* always hit-testable — free roaming across sections is the product
|
|
6719
|
+
* behaviour, the glide is only an entrance.
|
|
6720
|
+
*/
|
|
6721
|
+
releaseSectionFocusDim() {
|
|
6722
|
+
if (!this.focusBackdrop && !this.focusDimOverlay) return;
|
|
6723
|
+
this.focusBackdrop?.destroy();
|
|
6724
|
+
this.focusBackdrop = null;
|
|
6725
|
+
this.focusDimOverlay?.destroy();
|
|
6726
|
+
this.focusDimOverlay = null;
|
|
6727
|
+
this.bgLayer.batchDraw();
|
|
6728
|
+
this.overlayLayer.batchDraw();
|
|
6581
6729
|
}
|
|
6582
6730
|
/** Clear an AXS section focus — restore full-bowl brightness + drop the backdrop. */
|
|
6583
6731
|
clearSectionFocus() {
|
|
@@ -6715,6 +6863,44 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6715
6863
|
if (!Number.isFinite(minX)) return { x: 0, y: 0, width: 1, height: 1 };
|
|
6716
6864
|
return { x: minX, y: minY, width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };
|
|
6717
6865
|
}
|
|
6866
|
+
/** Live minimap geometry comes from the rendered scene, so a content-aware
|
|
6867
|
+
* all-floor layout cannot collapse back onto the source coordinate stack. */
|
|
6868
|
+
getMinimapSnapshot() {
|
|
6869
|
+
const sections = this.sections.map((section) => {
|
|
6870
|
+
const inactive = this.isSectionClosed(section) || section.free <= 0;
|
|
6871
|
+
const selected = section.memberIds.some((id) => this.selection.has(id));
|
|
6872
|
+
const active2 = this.focusedSectionId === section.id || this.focusedSectionId === section.logicalId;
|
|
6873
|
+
return {
|
|
6874
|
+
id: section.logicalId,
|
|
6875
|
+
label: section.label,
|
|
6876
|
+
outline: section.outline.map((point) => ({ ...point })),
|
|
6877
|
+
...this.objectFloor.get(section.id) ? { floorId: this.objectFloor.get(section.id) } : {},
|
|
6878
|
+
state: selected ? "selected" : inactive ? "inactive" : "available",
|
|
6879
|
+
active: active2
|
|
6880
|
+
};
|
|
6881
|
+
});
|
|
6882
|
+
return {
|
|
6883
|
+
sections,
|
|
6884
|
+
seats: sections.length ? [] : this.seats.map((seat) => ({
|
|
6885
|
+
x: seat.x,
|
|
6886
|
+
y: seat.y,
|
|
6887
|
+
categoryKey: seat.categoryKey,
|
|
6888
|
+
state: this.selection.has(seat.id) ? "selected" : this.statusById.get(seat.id) === "free" ? "available" : "inactive"
|
|
6889
|
+
}))
|
|
6890
|
+
};
|
|
6891
|
+
}
|
|
6892
|
+
/** Minimap drag/click navigation: preserve zoom and move one world point to
|
|
6893
|
+
* the viewport centre. Works for flat and projected views via worldToScreen. */
|
|
6894
|
+
panToWorld(point) {
|
|
6895
|
+
this.cancelGlide();
|
|
6896
|
+
const screen = this.worldToScreen(point);
|
|
6897
|
+
this.stage.position({
|
|
6898
|
+
x: this.stage.x() + this.stage.width() / 2 - screen.x,
|
|
6899
|
+
y: this.stage.y() + this.stage.height() / 2 - screen.y
|
|
6900
|
+
});
|
|
6901
|
+
this.afterViewChange();
|
|
6902
|
+
this.stage.batchDraw();
|
|
6903
|
+
}
|
|
6718
6904
|
/** Legend hover: highlight one category (dim the rest), or null to clear. */
|
|
6719
6905
|
setCategoryHighlight(key) {
|
|
6720
6906
|
if (this.categoryHighlight === key) return;
|
|
@@ -7483,7 +7669,15 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7483
7669
|
blockT = clamp((BLOCK_MELT_TOP - scale) / (BLOCK_MELT_TOP - SECTION_PROMINENT_SCALE), 0, 1);
|
|
7484
7670
|
zoneT = clamp((SECTION_PROMINENT_SCALE - scale) / (SECTION_PROMINENT_SCALE - ZONE_PROMINENT_SCALE), 0, 1);
|
|
7485
7671
|
}
|
|
7486
|
-
|
|
7672
|
+
if (this.floorOverview) {
|
|
7673
|
+
blockT = 0;
|
|
7674
|
+
zoneT = 0;
|
|
7675
|
+
}
|
|
7676
|
+
if (this.focusedSectionId) {
|
|
7677
|
+
blockT = 0;
|
|
7678
|
+
zoneT = 0;
|
|
7679
|
+
}
|
|
7680
|
+
const sectionOverview = !this.floorOverview && !this.focusedSectionId && scale < CACHE_THRESHOLD;
|
|
7487
7681
|
if (sectionOverview) blockT = 1;
|
|
7488
7682
|
if (!this.zones.length) zoneT = 0;
|
|
7489
7683
|
const deferPerspectiveSeatReveal = this.viewMode === "perspective" && this.glideInProgress && this.seats.length > 2500;
|
|
@@ -7682,6 +7876,14 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7682
7876
|
zone.back.offset({ x: width / 2, y: height / 2 });
|
|
7683
7877
|
zone.back.cornerRadius(7 * this.uiScale() / sx);
|
|
7684
7878
|
zone.back.strokeWidth(1 / sx);
|
|
7879
|
+
const abs = zone.back.getAbsolutePosition();
|
|
7880
|
+
const minScreenY = 62 + height * sx / 2;
|
|
7881
|
+
if (abs.y < minScreenY) {
|
|
7882
|
+
const dy = (minScreenY - abs.y) / sx;
|
|
7883
|
+
zone.label.y(zone.label.y() + dy);
|
|
7884
|
+
if (zone.sub) zone.sub.y(zone.sub.y() + dy);
|
|
7885
|
+
zone.back.y(zone.back.y() + dy);
|
|
7886
|
+
}
|
|
7685
7887
|
}
|
|
7686
7888
|
/**
|
|
7687
7889
|
* Map a container-relative screen point back to world coords. Inverts the
|
|
@@ -7906,7 +8108,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7906
8108
|
* must fall through and pick.
|
|
7907
8109
|
*/
|
|
7908
8110
|
sectionBounds(id) {
|
|
7909
|
-
const
|
|
8111
|
+
const matching = this.sections.filter((section) => section.id === id || section.logicalId === id);
|
|
8112
|
+
const bounds2 = matching.map((section) => {
|
|
7910
8113
|
if (this.viewMode === "perspective" && section.perspectiveAffine) {
|
|
7911
8114
|
return polyBounds(section.outline.map((point) => this.projectedSectionPoint(section, point)));
|
|
7912
8115
|
}
|
|
@@ -7918,11 +8121,77 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7918
8121
|
return polyBounds(points);
|
|
7919
8122
|
});
|
|
7920
8123
|
if (!bounds2.length) return null;
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
8124
|
+
let left = Math.min(...bounds2.map((box) => box.x));
|
|
8125
|
+
let top = Math.min(...bounds2.map((box) => box.y));
|
|
8126
|
+
let right = Math.max(...bounds2.map((box) => box.x + box.width));
|
|
8127
|
+
let bottom = Math.max(...bounds2.map((box) => box.y + box.height));
|
|
8128
|
+
const memberIds = new Set(matching.flatMap((section) => section.memberIds));
|
|
8129
|
+
for (const seatId of memberIds) {
|
|
8130
|
+
const seat = this.seatById.get(seatId);
|
|
8131
|
+
if (!seat) continue;
|
|
8132
|
+
const point = this.renderedSeatPoint(seat);
|
|
8133
|
+
left = Math.min(left, point.x - this.seatR);
|
|
8134
|
+
top = Math.min(top, point.y - this.seatR);
|
|
8135
|
+
right = Math.max(right, point.x + this.seatR);
|
|
8136
|
+
bottom = Math.max(bottom, point.y + this.seatR);
|
|
8137
|
+
}
|
|
8138
|
+
const includeBox = (box) => {
|
|
8139
|
+
if (![box.x, box.y, box.width, box.height].every(Number.isFinite)) return;
|
|
8140
|
+
left = Math.min(left, box.x);
|
|
8141
|
+
top = Math.min(top, box.y);
|
|
8142
|
+
right = Math.max(right, box.x + box.width);
|
|
8143
|
+
bottom = Math.max(bottom, box.y + box.height);
|
|
8144
|
+
};
|
|
8145
|
+
const belongsToSection = (box) => {
|
|
8146
|
+
const centre = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
|
|
8147
|
+
return matching.some((section) => pointInPolygonWithHoles(centre, section.outline, section.holes));
|
|
8148
|
+
};
|
|
8149
|
+
for (const { node, backdrop } of this.freeTextById.values()) {
|
|
8150
|
+
const nodeBox = node.getClientRect({ relativeTo: this.bgLayer, skipShadow: true });
|
|
8151
|
+
if (!belongsToSection(nodeBox)) continue;
|
|
8152
|
+
includeBox(nodeBox);
|
|
8153
|
+
if (backdrop) includeBox(backdrop.getClientRect({ relativeTo: this.bgLayer, skipShadow: true }));
|
|
8154
|
+
}
|
|
8155
|
+
for (const { node } of this.iconNodeById.values()) {
|
|
8156
|
+
const box = node.getClientRect({ relativeTo: this.bgLayer, skipShadow: true });
|
|
8157
|
+
if (belongsToSection(box)) includeBox(box);
|
|
8158
|
+
}
|
|
8159
|
+
const occupiedText = new WorldBoxIndex();
|
|
8160
|
+
for (const { node } of this.freeTextById.values()) {
|
|
8161
|
+
const box = node.getClientRect({ relativeTo: this.bgLayer, skipShadow: true, skipStroke: true });
|
|
8162
|
+
occupiedText.insert({
|
|
8163
|
+
x: box.x - ROW_LABEL_CLEARANCE,
|
|
8164
|
+
y: box.y - ROW_LABEL_CLEARANCE,
|
|
8165
|
+
width: box.width + ROW_LABEL_CLEARANCE * 2,
|
|
8166
|
+
height: box.height + ROW_LABEL_CLEARANCE * 2
|
|
8167
|
+
});
|
|
8168
|
+
}
|
|
8169
|
+
for (const plan of this.rowLabelPlan) {
|
|
8170
|
+
const relevant = plan.focusKeys?.some((key) => key === id || matching.some((section) => key === section.id || key === section.logicalId || key === section.zone)) ?? false;
|
|
8171
|
+
const label = new import_Text.Text({
|
|
8172
|
+
text: plan.text,
|
|
8173
|
+
fontSize: plan.fontSize,
|
|
8174
|
+
fontStyle: "700",
|
|
8175
|
+
fontFamily: this.labelFont(),
|
|
8176
|
+
rotation: plan.rotation,
|
|
8177
|
+
listening: false
|
|
8178
|
+
});
|
|
8179
|
+
label.offsetX(label.width() / 2);
|
|
8180
|
+
label.offsetY(label.height() / 2);
|
|
8181
|
+
const resolved = this.resolveAutomaticRowLabelPosition(label, plan, occupiedText);
|
|
8182
|
+
const box = this.rowLabelBox(label, resolved);
|
|
8183
|
+
if (relevant) includeBox(box);
|
|
8184
|
+
occupiedText.insert(box);
|
|
8185
|
+
label.destroy();
|
|
8186
|
+
}
|
|
8187
|
+
const span = Math.max(right - left, bottom - top);
|
|
8188
|
+
const padding = Math.max(this.seatR * 2, Math.min(24, span * 0.025));
|
|
8189
|
+
return {
|
|
8190
|
+
x: left - padding,
|
|
8191
|
+
y: top - padding,
|
|
8192
|
+
width: Math.max(1, right - left + padding * 2),
|
|
8193
|
+
height: Math.max(1, bottom - top + padding * 2)
|
|
8194
|
+
};
|
|
7926
8195
|
}
|
|
7927
8196
|
sectionFrameScale(id) {
|
|
7928
8197
|
const b = this.sectionBounds(id);
|
|
@@ -7933,7 +8202,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7933
8202
|
const margin = 1.12;
|
|
7934
8203
|
if (b.width <= 0 || b.height <= 0) return this.stage.scaleX();
|
|
7935
8204
|
const frameScale = Math.min(w / (b.width * margin), h / (b.height * margin));
|
|
7936
|
-
return clamp(
|
|
8205
|
+
return clamp(frameScale, min, max);
|
|
7937
8206
|
}
|
|
7938
8207
|
/**
|
|
7939
8208
|
* Resolve a seat tap: honour the 3D deck-drill and the AXS seat-pick gate,
|
|
@@ -7946,7 +8215,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
7946
8215
|
* fall through and PICK. This is the invariant: seats are never unpickable.
|
|
7947
8216
|
*/
|
|
7948
8217
|
handleSeatTap(id) {
|
|
7949
|
-
if (this.stacked && this.opts.onDeckTap) {
|
|
8218
|
+
if ((this.stacked || this.floorOverview) && this.opts.onDeckTap) {
|
|
7950
8219
|
const floorId = this.objectFloor.get(this.seatById.get(id)?.rowId ?? "");
|
|
7951
8220
|
if (floorId) {
|
|
7952
8221
|
this.opts.onDeckTap(floorId);
|
|
@@ -8021,6 +8290,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8021
8290
|
});
|
|
8022
8291
|
this.stage.on("wheel", (e) => {
|
|
8023
8292
|
e.evt.preventDefault();
|
|
8293
|
+
this.releaseSectionFocusDim();
|
|
8024
8294
|
const r = this.container.getBoundingClientRect();
|
|
8025
8295
|
const pointer = { x: e.evt.clientX - r.left, y: e.evt.clientY - r.top };
|
|
8026
8296
|
const factor = Math.exp(-e.evt.deltaY * 2e-3);
|
|
@@ -8037,8 +8307,9 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8037
8307
|
if (near) this.handleSeatTap(near);
|
|
8038
8308
|
return;
|
|
8039
8309
|
}
|
|
8040
|
-
if (this.stacked && this.opts.onDeckTap) {
|
|
8041
|
-
const
|
|
8310
|
+
if ((this.stacked || this.floorOverview) && this.opts.onDeckTap) {
|
|
8311
|
+
const sectionId = this.floorOverview ? this.sectionAt(pointer) : null;
|
|
8312
|
+
const floorId = (sectionId ? this.objectFloor.get(sectionId) : null) ?? this.deckFloorAt();
|
|
8042
8313
|
if (floorId) {
|
|
8043
8314
|
this.opts.onDeckTap(floorId);
|
|
8044
8315
|
return;
|
|
@@ -8436,6 +8707,28 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8436
8707
|
...hiddenReason ? { hiddenReason } : {}
|
|
8437
8708
|
};
|
|
8438
8709
|
});
|
|
8710
|
+
const rowLabels = this.labelGroup.find((node) => node.getAttr("rowLabel") === true).filter((node) => node instanceof import_Text.Text).map((node) => {
|
|
8711
|
+
const screenBounds = node.getClientRect({
|
|
8712
|
+
skipShadow: true,
|
|
8713
|
+
skipStroke: true
|
|
8714
|
+
});
|
|
8715
|
+
const outside = screenBounds.x + screenBounds.width < 0 || screenBounds.x > viewport.width || screenBounds.y + screenBounds.height < 0 || screenBounds.y > viewport.height;
|
|
8716
|
+
const ink = node.fill();
|
|
8717
|
+
return {
|
|
8718
|
+
text: node.text(),
|
|
8719
|
+
visible: node.isVisible() && !outside,
|
|
8720
|
+
renderedFontPx: rounded(node.fontSize() * effectiveScale),
|
|
8721
|
+
ink: typeof ink === "string" ? ink : "",
|
|
8722
|
+
...!outside ? {
|
|
8723
|
+
screenBox: {
|
|
8724
|
+
x: rounded(screenBounds.x),
|
|
8725
|
+
y: rounded(screenBounds.y),
|
|
8726
|
+
width: rounded(screenBounds.width),
|
|
8727
|
+
height: rounded(screenBounds.height)
|
|
8728
|
+
}
|
|
8729
|
+
} : {}
|
|
8730
|
+
};
|
|
8731
|
+
});
|
|
8439
8732
|
const palette = overviewPalette(this.canvasBackground);
|
|
8440
8733
|
const neutralSectionFills = new Set(
|
|
8441
8734
|
["normal", "nearly-gone", "sold-out", "closed"].map((state) => overviewStateFill(palette, state).toLowerCase())
|
|
@@ -8480,7 +8773,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8480
8773
|
labels,
|
|
8481
8774
|
gaAreas,
|
|
8482
8775
|
hierarchyLabels,
|
|
8483
|
-
freeTextLabels
|
|
8776
|
+
freeTextLabels,
|
|
8777
|
+
rowLabels
|
|
8484
8778
|
};
|
|
8485
8779
|
}
|
|
8486
8780
|
/** Jump the camera to a rung's zoom band (glided). */
|
|
@@ -8492,7 +8786,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8492
8786
|
}
|
|
8493
8787
|
const target = rung === "sections" ? (SECTION_PROMINENT_SCALE + CACHE_THRESHOLD) / 2 : Math.max(
|
|
8494
8788
|
this.seatLabelTargetScale() * 1.05,
|
|
8495
|
-
|
|
8789
|
+
SEAT_DETAIL_SCALE,
|
|
8496
8790
|
CACHE_THRESHOLD * 1.3
|
|
8497
8791
|
);
|
|
8498
8792
|
const w = this.stage.width();
|
|
@@ -8779,14 +9073,25 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8779
9073
|
for (const { objectId, node, backdrop, categoryKey, kind } of this.freeTextById.values()) {
|
|
8780
9074
|
const gaDimmed = categoryKey != null && (kind === "ga-label" || kind === "ga-capacity") && this.gaCategoryDimmed(categoryKey);
|
|
8781
9075
|
const gaOverviewHidden = objectId != null && (kind === "ga-label" || kind === "ga-capacity") && this.gaById.get(objectId)?.sectionId != null && effectiveScale < CACHE_THRESHOLD;
|
|
8782
|
-
const
|
|
9076
|
+
const focusedAnnotation = kind === "free-text" && this.nodeBelongsToFocusedSection(node);
|
|
9077
|
+
const visible = !gaDimmed && !gaOverviewHidden && (focusedAnnotation || isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));
|
|
8783
9078
|
node.visible(visible);
|
|
8784
9079
|
backdrop?.visible(visible);
|
|
8785
9080
|
}
|
|
8786
9081
|
for (const { node, fontSize } of this.iconNodeById.values()) {
|
|
8787
|
-
node.visible(isBookableLabelLegibleAtScale(fontSize, effectiveScale));
|
|
9082
|
+
node.visible(this.nodeBelongsToFocusedSection(node) || isBookableLabelLegibleAtScale(fontSize, effectiveScale));
|
|
8788
9083
|
}
|
|
8789
9084
|
}
|
|
9085
|
+
/** Geometric association only: importer data remains unchanged. */
|
|
9086
|
+
nodeBelongsToFocusedSection(node) {
|
|
9087
|
+
const focus = this.focusedSectionId;
|
|
9088
|
+
if (!focus) return false;
|
|
9089
|
+
const matching = this.sections.filter((section) => section.id === focus || section.logicalId === focus || section.zone === focus);
|
|
9090
|
+
if (!matching.length) return false;
|
|
9091
|
+
const box = node.getClientRect({ relativeTo: this.bgLayer, skipShadow: true });
|
|
9092
|
+
const centre = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
|
|
9093
|
+
return matching.some((section) => pointInPolygonWithHoles(centre, section.outline, section.holes));
|
|
9094
|
+
}
|
|
8790
9095
|
/** OV-45(a): resolve authored row-letter labels for the buyer/preview map, in
|
|
8791
9096
|
* world space, matching the Designer's placement contract (start/end/both/none
|
|
8792
9097
|
* preset, a free-drag `position` that wins over the preset, rotation, and
|
|
@@ -8796,18 +9101,25 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8796
9101
|
this.rowLabelPlan = [];
|
|
8797
9102
|
const background = this.theme.background ?? "#0e1117";
|
|
8798
9103
|
const seatsByRow = /* @__PURE__ */ new Map();
|
|
9104
|
+
const addSeat = (key, seat) => {
|
|
9105
|
+
const list = seatsByRow.get(key) ?? [];
|
|
9106
|
+
list.push(seat);
|
|
9107
|
+
seatsByRow.set(key, list);
|
|
9108
|
+
};
|
|
8799
9109
|
for (const seat of this.seats) {
|
|
8800
9110
|
if (seat.kind === "booth") continue;
|
|
8801
9111
|
const key = seat.logicalRowId ?? seat.rowId;
|
|
8802
|
-
(
|
|
9112
|
+
addSeat(key, seat);
|
|
9113
|
+
if (key !== seat.rowId) addSeat(seat.rowId, seat);
|
|
8803
9114
|
}
|
|
8804
9115
|
const seatOrder = (seat) => seat.logicalSeatIndex ?? Number(seat.id.split(":").pop() ?? 0);
|
|
8805
9116
|
for (const obj of view.objects) {
|
|
8806
9117
|
if (obj.type !== "row") continue;
|
|
8807
|
-
|
|
8808
|
-
|
|
9118
|
+
const repeatOnComponents = obj.segmentedRow?.repeatLabelOnComponents === true;
|
|
9119
|
+
if (obj.segmentedRow && !repeatOnComponents && obj.segmentedRow.componentIndex !== 0) continue;
|
|
9120
|
+
const presentation = repeatOnComponents ? obj.labelPresentation : obj.segmentedRow?.labelPresentation ?? obj.labelPresentation;
|
|
8809
9121
|
if (presentation?.visible === false || presentation?.positionPreset === "none") continue;
|
|
8810
|
-
const key = obj.segmentedRow ? obj.segmentedRow.groupId : obj.id;
|
|
9122
|
+
const key = obj.segmentedRow && !repeatOnComponents ? obj.segmentedRow.groupId : obj.id;
|
|
8811
9123
|
const seats = (seatsByRow.get(key) ?? []).slice().sort((a, b) => seatOrder(a) - seatOrder(b));
|
|
8812
9124
|
if (!seats.length) continue;
|
|
8813
9125
|
const first = seats[0];
|
|
@@ -8822,6 +9134,10 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8822
9134
|
const rotation = presentation?.rotation ?? 0;
|
|
8823
9135
|
const text = obj.segmentedRow?.displayLabel ?? obj.displayLabel ?? obj.label;
|
|
8824
9136
|
const opacity = this.objectFilteredOut(obj) ? 0.15 : 1;
|
|
9137
|
+
const containingSection = this.seatSection.get(first.id);
|
|
9138
|
+
const focusKeys = containingSection ? [...new Set([containingSection.id, containingSection.logicalId, containingSection.zone].filter(
|
|
9139
|
+
(value) => Boolean(value)
|
|
9140
|
+
))] : void 0;
|
|
8825
9141
|
const push = (x, y, automaticAway) => this.rowLabelPlan.push({
|
|
8826
9142
|
text,
|
|
8827
9143
|
x,
|
|
@@ -8830,6 +9146,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8830
9146
|
fontSize,
|
|
8831
9147
|
ink,
|
|
8832
9148
|
opacity,
|
|
9149
|
+
...focusKeys?.length ? { focusKeys } : {},
|
|
8833
9150
|
...automaticAway ? { automaticAway } : {}
|
|
8834
9151
|
});
|
|
8835
9152
|
if (presentation?.position) {
|
|
@@ -8849,6 +9166,18 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8849
9166
|
push(last.x + away.x * gap, last.y + away.y * gap, away);
|
|
8850
9167
|
}
|
|
8851
9168
|
}
|
|
9169
|
+
const mergeRadius = (this.seatR + 12) * 2.2;
|
|
9170
|
+
const merged = [];
|
|
9171
|
+
for (const entry of this.rowLabelPlan) {
|
|
9172
|
+
const partner = merged.find((candidate) => candidate.text === entry.text && Math.hypot(candidate.x - entry.x, candidate.y - entry.y) <= mergeRadius);
|
|
9173
|
+
if (partner) {
|
|
9174
|
+
partner.x = (partner.x + entry.x) / 2;
|
|
9175
|
+
partner.y = (partner.y + entry.y) / 2;
|
|
9176
|
+
continue;
|
|
9177
|
+
}
|
|
9178
|
+
merged.push(entry);
|
|
9179
|
+
}
|
|
9180
|
+
this.rowLabelPlan = merged;
|
|
8852
9181
|
}
|
|
8853
9182
|
/** Axis-aligned world bounds of a centred, potentially rotated row label. */
|
|
8854
9183
|
rowLabelBox(label, position, padding = ROW_LABEL_CLEARANCE) {
|
|
@@ -8925,12 +9254,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
8925
9254
|
this.labelGroup.destroyChildren();
|
|
8926
9255
|
this.labelLiftGroups.clear();
|
|
8927
9256
|
this.seatLabelById.clear();
|
|
8928
|
-
if (!show) {
|
|
8929
|
-
this.overlayLayer.batchDraw();
|
|
8930
|
-
return;
|
|
8931
|
-
}
|
|
8932
9257
|
let count = 0;
|
|
8933
|
-
for (const seat of this.visibleSeatCandidates()) {
|
|
9258
|
+
if (show) for (const seat of this.visibleSeatCandidates()) {
|
|
8934
9259
|
if (seat.kind === "booth") continue;
|
|
8935
9260
|
const screen = this.worldToScreen(seat);
|
|
8936
9261
|
if (screen.x < -20 || screen.x > this.stage.width() + 20 || screen.y < -20 || screen.y > this.stage.height() + 20) continue;
|
|
@@ -9021,13 +9346,16 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
9021
9346
|
});
|
|
9022
9347
|
}
|
|
9023
9348
|
for (const rl of this.rowLabelPlan) {
|
|
9349
|
+
const focused = this.focusedSectionId != null && rl.focusKeys?.includes(this.focusedSectionId);
|
|
9350
|
+
const renderedFontSize = focused ? Math.max(rl.fontSize, FOCUSED_ROW_LABEL_MIN_PX / Math.max(effectiveScale, 1e-4)) : rl.fontSize;
|
|
9351
|
+
if (!focused && !isBookableLabelLegibleAtScale(renderedFontSize, effectiveScale)) continue;
|
|
9024
9352
|
const screen = this.worldToScreen({ x: rl.x, y: rl.y });
|
|
9025
9353
|
if (screen.x < -40 || screen.x > this.stage.width() + 40 || screen.y < -40 || screen.y > this.stage.height() + 40) continue;
|
|
9026
9354
|
const t2 = new import_Text.Text({
|
|
9027
9355
|
x: rl.x,
|
|
9028
9356
|
y: rl.y,
|
|
9029
9357
|
text: rl.text,
|
|
9030
|
-
fontSize:
|
|
9358
|
+
fontSize: renderedFontSize,
|
|
9031
9359
|
fontStyle: "700",
|
|
9032
9360
|
fontFamily: this.labelFont(),
|
|
9033
9361
|
fill: rl.ink,
|
|
@@ -9056,7 +9384,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
9056
9384
|
const h = this.container.clientHeight || 1;
|
|
9057
9385
|
if (w === this.stage.width() && h === this.stage.height()) return;
|
|
9058
9386
|
this.stage.size({ width: w, height: h });
|
|
9059
|
-
this.
|
|
9387
|
+
this.refitCurrentView();
|
|
9060
9388
|
}
|
|
9061
9389
|
startFpsLoop() {
|
|
9062
9390
|
const tick = (now) => {
|
|
@@ -9214,6 +9542,99 @@ function pickBestAvailable(seats, available, opts) {
|
|
|
9214
9542
|
return { labels: ranked.slice(0, qty).map((r) => r.seat.label) };
|
|
9215
9543
|
}
|
|
9216
9544
|
|
|
9545
|
+
// src/core/ticketRestrictions.ts
|
|
9546
|
+
function ticketOptionNotApplicableIssue(labels) {
|
|
9547
|
+
return {
|
|
9548
|
+
code: "ticket_option_not_applicable",
|
|
9549
|
+
labels,
|
|
9550
|
+
message: "That ticket choice is not available for the selected seat."
|
|
9551
|
+
};
|
|
9552
|
+
}
|
|
9553
|
+
function ticketTierAppliesToSeat(tier, seat) {
|
|
9554
|
+
const applicability = tier.applicability;
|
|
9555
|
+
if (!applicability) return true;
|
|
9556
|
+
if (applicability.seatLabels?.length && !applicability.seatLabels.includes(seat.label)) return false;
|
|
9557
|
+
if (applicability.accessibility?.length && !applicability.accessibility.some((key) => seat.accessibility?.includes(key))) return false;
|
|
9558
|
+
return true;
|
|
9559
|
+
}
|
|
9560
|
+
function applicableTicketTiers(doc, seat) {
|
|
9561
|
+
return (doc.categories.find((category) => category.key === seat.categoryKey)?.tiers ?? []).filter((tier) => ticketTierAppliesToSeat(tier, seat));
|
|
9562
|
+
}
|
|
9563
|
+
function resolveTicketTierForSeat(doc, seat, tierId) {
|
|
9564
|
+
const tiers = doc.categories.find((category) => category.key === seat.categoryKey)?.tiers;
|
|
9565
|
+
if (!tiers?.length) return { kind: "none" };
|
|
9566
|
+
const tier = tierId == null ? tiers.find((candidate) => ticketTierAppliesToSeat(candidate, seat)) : tiers.find((candidate) => candidate.id === tierId && ticketTierAppliesToSeat(candidate, seat));
|
|
9567
|
+
return tier ? { kind: "resolved", tier } : { kind: "invalid" };
|
|
9568
|
+
}
|
|
9569
|
+
function sameLogicalRow(a, b) {
|
|
9570
|
+
return (a.logicalRowId ?? a.rowId) === (b.logicalRowId ?? b.rowId);
|
|
9571
|
+
}
|
|
9572
|
+
function authoredIndex(seat) {
|
|
9573
|
+
if (Number.isInteger(seat.logicalSeatIndex)) return seat.logicalSeatIndex;
|
|
9574
|
+
const raw = seat.id.slice(seat.id.lastIndexOf(":") + 1);
|
|
9575
|
+
const index = Number(raw);
|
|
9576
|
+
return Number.isInteger(index) ? index : void 0;
|
|
9577
|
+
}
|
|
9578
|
+
function observablyAdjacent(a, b) {
|
|
9579
|
+
if (!sameLogicalRow(a, b)) return false;
|
|
9580
|
+
const aIndex = authoredIndex(a);
|
|
9581
|
+
const bIndex = authoredIndex(b);
|
|
9582
|
+
return aIndex != null && bIndex != null && Math.abs(aIndex - bIndex) === 1;
|
|
9583
|
+
}
|
|
9584
|
+
function companionSelectionIssue(doc, selections) {
|
|
9585
|
+
if (!selections.length) return null;
|
|
9586
|
+
const byLabel = new Map(expandChart(doc, { resolveEyeHeights: false }).map((seat) => [seat.label, seat]));
|
|
9587
|
+
const selected = selections.flatMap((selection) => {
|
|
9588
|
+
const seat = byLabel.get(selection.label);
|
|
9589
|
+
return seat ? [{ selection, seat }] : [];
|
|
9590
|
+
});
|
|
9591
|
+
const wheelchair = selected.map(({ seat }) => seat).filter((seat) => seat.accessibility?.includes("wheelchair"));
|
|
9592
|
+
const unpaired = [];
|
|
9593
|
+
for (const { selection, seat } of selected) {
|
|
9594
|
+
const resolution = resolveTicketTierForSeat(doc, seat, selection.tierId);
|
|
9595
|
+
const tier = resolution.kind === "resolved" ? resolution.tier : void 0;
|
|
9596
|
+
const isCompanion = seat.accessibility?.includes("companion") || tier?.restriction === "companion";
|
|
9597
|
+
if (isCompanion && !wheelchair.some((candidate) => candidate.id !== seat.id && observablyAdjacent(seat, candidate))) {
|
|
9598
|
+
unpaired.push(seat.label);
|
|
9599
|
+
}
|
|
9600
|
+
}
|
|
9601
|
+
return unpaired.length ? {
|
|
9602
|
+
code: "companion_pair_required",
|
|
9603
|
+
labels: unpaired,
|
|
9604
|
+
message: "Select the adjacent wheelchair place with each companion ticket."
|
|
9605
|
+
} : null;
|
|
9606
|
+
}
|
|
9607
|
+
function ticketSelectionIssue(doc, selections) {
|
|
9608
|
+
if (!selections.length) return null;
|
|
9609
|
+
const byLabel = new Map(expandChart(doc, { resolveEyeHeights: false }).map((seat) => [seat.label, seat]));
|
|
9610
|
+
const notForSaleCategories = new Set(
|
|
9611
|
+
doc.categories.filter((category) => category.notForSale).map((category) => category.key)
|
|
9612
|
+
);
|
|
9613
|
+
const notForSale = [];
|
|
9614
|
+
const inapplicable = [];
|
|
9615
|
+
for (const selection of selections) {
|
|
9616
|
+
const seat = byLabel.get(selection.label);
|
|
9617
|
+
if (!seat) continue;
|
|
9618
|
+
if (notForSaleCategories.has(seat.categoryKey)) {
|
|
9619
|
+
notForSale.push(seat.label);
|
|
9620
|
+
continue;
|
|
9621
|
+
}
|
|
9622
|
+
const resolution = resolveTicketTierForSeat(doc, seat, selection.tierId);
|
|
9623
|
+
if (resolution.kind === "invalid") inapplicable.push(seat.label);
|
|
9624
|
+
}
|
|
9625
|
+
if (notForSale.length) {
|
|
9626
|
+
return {
|
|
9627
|
+
code: "not_for_sale",
|
|
9628
|
+
labels: notForSale,
|
|
9629
|
+
message: "These seats are not for sale."
|
|
9630
|
+
};
|
|
9631
|
+
}
|
|
9632
|
+
if (inapplicable.length) {
|
|
9633
|
+
return ticketOptionNotApplicableIssue(inapplicable);
|
|
9634
|
+
}
|
|
9635
|
+
return companionSelectionIssue(doc, selections);
|
|
9636
|
+
}
|
|
9637
|
+
|
|
9217
9638
|
// src/core/tableInventory.ts
|
|
9218
9639
|
var GroupedTableProjectionError = class extends Error {
|
|
9219
9640
|
constructor(objectId, message) {
|
|
@@ -9268,6 +9689,15 @@ function groupedTableInventory(doc, modelVersion) {
|
|
|
9268
9689
|
// src/picker/PickerController.ts
|
|
9269
9690
|
var DEFAULT_MAX_SELECTION = 10;
|
|
9270
9691
|
var MAX_BACKOFF_MS = 15e3;
|
|
9692
|
+
var PickerSelectionError = class extends Error {
|
|
9693
|
+
constructor(issue) {
|
|
9694
|
+
super(issue.message);
|
|
9695
|
+
this.status = 422;
|
|
9696
|
+
this.name = "PickerSelectionError";
|
|
9697
|
+
this.reason = issue.code;
|
|
9698
|
+
this.labels = issue.labels;
|
|
9699
|
+
}
|
|
9700
|
+
};
|
|
9271
9701
|
var MAP_THEME_KEYS = ["background", "rowLabelColor", "textColor", "selectionColor"];
|
|
9272
9702
|
function sameMapTheme(a, b) {
|
|
9273
9703
|
if (!a || !b) return !a && !b;
|
|
@@ -9397,7 +9827,9 @@ var PickerController = class {
|
|
|
9397
9827
|
if (!r) return true;
|
|
9398
9828
|
const selected = r.getSelection().map((seat) => seat.id);
|
|
9399
9829
|
const floorId = this.getActiveFloorId();
|
|
9830
|
+
const floorOverview = r.isFloorOverview?.() ?? false;
|
|
9400
9831
|
r.setChart(this.visibleDoc(), floorId ? { floorId } : void 0);
|
|
9832
|
+
if (floorOverview) r.setFloorOverview?.(true);
|
|
9401
9833
|
if (this.opts.colorblindSafe) r.setColorblindSafe?.(true);
|
|
9402
9834
|
if (this.closedSections.size) r.setClosedSections?.([...this.closedSections]);
|
|
9403
9835
|
this.applySeatsMap(Object.fromEntries(this.liveStatuses), this.liveDefault);
|
|
@@ -9409,7 +9841,9 @@ var PickerController = class {
|
|
|
9409
9841
|
const next = ids.filter((x) => typeof x === "string");
|
|
9410
9842
|
if (next.length === this.hidden.size && next.every((id) => this.hidden.has(id))) return false;
|
|
9411
9843
|
this.hidden = new Set(next);
|
|
9844
|
+
const floorOverview = this.renderer?.isFloorOverview?.() ?? false;
|
|
9412
9845
|
this.renderer?.setChart(this.visibleDoc());
|
|
9846
|
+
if (floorOverview) this.renderer?.setFloorOverview?.(true);
|
|
9413
9847
|
return true;
|
|
9414
9848
|
}
|
|
9415
9849
|
/** Adopt a new closed-section set; restyle (grey + non-pickable) if it differs.
|
|
@@ -9484,16 +9918,22 @@ var PickerController = class {
|
|
|
9484
9918
|
/** Fetch chart, build label maps, mount the renderer, seed statuses, go live. */
|
|
9485
9919
|
async render(host) {
|
|
9486
9920
|
if (this.renderer) return null;
|
|
9921
|
+
const renderStartedAt = performance.now();
|
|
9922
|
+
const profile = {};
|
|
9923
|
+
const duration = (startedAt) => Math.round((performance.now() - startedAt) * 100) / 100;
|
|
9487
9924
|
this.closed = false;
|
|
9488
9925
|
let res;
|
|
9926
|
+
const chartStartedAt = performance.now();
|
|
9489
9927
|
try {
|
|
9490
9928
|
res = await this.api.chart(this.key);
|
|
9491
9929
|
} catch (err) {
|
|
9492
9930
|
this.emitError(err);
|
|
9493
9931
|
return null;
|
|
9494
9932
|
}
|
|
9933
|
+
profile.loadChart = duration(chartStartedAt);
|
|
9495
9934
|
if (this.closed) return null;
|
|
9496
9935
|
this._doc = res.doc;
|
|
9936
|
+
const normalizeStartedAt = performance.now();
|
|
9497
9937
|
try {
|
|
9498
9938
|
const groups = groupedTableInventory(
|
|
9499
9939
|
res.doc,
|
|
@@ -9558,13 +9998,16 @@ var PickerController = class {
|
|
|
9558
9998
|
this.labelToId.set(group.label, representative.id);
|
|
9559
9999
|
this.labelToSeat.set(group.label, representative);
|
|
9560
10000
|
}
|
|
10001
|
+
profile.normalizeBuyerModel = duration(normalizeStartedAt);
|
|
9561
10002
|
const currency = res.event.currency ?? this.opts.currency;
|
|
9562
10003
|
this.currency = currency ?? "USD";
|
|
10004
|
+
const rendererStartedAt = performance.now();
|
|
9563
10005
|
const renderer = createRenderer(host, {
|
|
9564
10006
|
// Group chairs are selected together for paint, but count as one logical
|
|
9565
10007
|
// inventory line. The controller enforces the guest-weighted cap.
|
|
9566
10008
|
maxSelection: this.rendererSelectionCap(),
|
|
9567
10009
|
confirmSelection: this.opts.confirmSelection,
|
|
10010
|
+
portraitFitCrop: true,
|
|
9568
10011
|
currency,
|
|
9569
10012
|
onSelect: (seat) => {
|
|
9570
10013
|
this.handleRendererSelect(seat);
|
|
@@ -9585,6 +10028,7 @@ var PickerController = class {
|
|
|
9585
10028
|
onDeckTap: (floorId) => this.handleDeckTap(floorId),
|
|
9586
10029
|
onFps: this.opts.onFps
|
|
9587
10030
|
});
|
|
10031
|
+
profile.createRenderer = duration(rendererStartedAt);
|
|
9588
10032
|
if (this.closed) {
|
|
9589
10033
|
renderer.destroy();
|
|
9590
10034
|
return null;
|
|
@@ -9593,6 +10037,7 @@ var PickerController = class {
|
|
|
9593
10037
|
let seats = null;
|
|
9594
10038
|
let seatsDefault = "free";
|
|
9595
10039
|
let closedIds = [];
|
|
10040
|
+
const statusesStartedAt = performance.now();
|
|
9596
10041
|
try {
|
|
9597
10042
|
const objs = await this.api.objects(this.key);
|
|
9598
10043
|
this.hidden = new Set(objs.hidden ?? []);
|
|
@@ -9601,18 +10046,30 @@ var PickerController = class {
|
|
|
9601
10046
|
seatsDefault = objs.default ?? "free";
|
|
9602
10047
|
} catch {
|
|
9603
10048
|
}
|
|
10049
|
+
profile.loadStatuses = duration(statusesStartedAt);
|
|
9604
10050
|
if (this.closed) {
|
|
9605
10051
|
renderer.destroy();
|
|
9606
10052
|
this.renderer = null;
|
|
9607
10053
|
return null;
|
|
9608
10054
|
}
|
|
10055
|
+
const sceneStartedAt = performance.now();
|
|
9609
10056
|
renderer.setChart(this.visibleDoc());
|
|
10057
|
+
if ((res.doc.floors?.length ?? 0) > 1) renderer.setFloorOverview?.(true);
|
|
9610
10058
|
if (this.opts.colorblindSafe) renderer.setColorblindSafe?.(true);
|
|
10059
|
+
profile.buildScene = duration(sceneStartedAt);
|
|
9611
10060
|
this.closedSections = new Set(closedIds);
|
|
10061
|
+
const initialStateStartedAt = performance.now();
|
|
9612
10062
|
if (closedIds.length) renderer.setClosedSections?.(closedIds);
|
|
9613
10063
|
if (seats) this.applySeatsMap(seats, seatsDefault);
|
|
10064
|
+
profile.applyInitialState = duration(initialStateStartedAt);
|
|
10065
|
+
const firstPaintStartedAt = performance.now();
|
|
10066
|
+
renderer.forceDraw();
|
|
10067
|
+
profile.firstPaint = duration(firstPaintStartedAt);
|
|
10068
|
+
const realtimeStartedAt = performance.now();
|
|
9614
10069
|
this.attachVisibilityListener();
|
|
9615
10070
|
this.connect();
|
|
10071
|
+
profile.startRealtime = duration(realtimeStartedAt);
|
|
10072
|
+
profile.controllerTotal = duration(renderStartedAt);
|
|
9616
10073
|
return {
|
|
9617
10074
|
doc: res.doc,
|
|
9618
10075
|
salesClosed: !!res.event.salesClosed,
|
|
@@ -9623,7 +10080,8 @@ var PickerController = class {
|
|
|
9623
10080
|
currency,
|
|
9624
10081
|
// 'test' ⇒ sandbox event: hosts render a TEST MODE ribbon (Phase 11).
|
|
9625
10082
|
mode: res.event.mode ?? "live",
|
|
9626
|
-
posterUrl: res.event.posterUrl ?? null
|
|
10083
|
+
posterUrl: res.event.posterUrl ?? null,
|
|
10084
|
+
performanceProfile: profile
|
|
9627
10085
|
};
|
|
9628
10086
|
}
|
|
9629
10087
|
// ---- selection ------------------------------------------------------------
|
|
@@ -9679,11 +10137,23 @@ var PickerController = class {
|
|
|
9679
10137
|
select(ids) {
|
|
9680
10138
|
const before = new Set(this.getSelection().map((seat) => seat.label));
|
|
9681
10139
|
const expanded = /* @__PURE__ */ new Set();
|
|
10140
|
+
const rejected = [];
|
|
9682
10141
|
for (const id of ids) {
|
|
9683
10142
|
const table = this.groupedTableBySeatId.get(id) ?? this.groupedTablesByLabel.get(id);
|
|
9684
|
-
if (table)
|
|
9685
|
-
|
|
10143
|
+
if (table) {
|
|
10144
|
+
const resolution = this.tableTierResolution(table);
|
|
10145
|
+
if (resolution.kind === "invalid") rejected.push(table.label);
|
|
10146
|
+
else table.chairs.forEach((chair) => expanded.add(chair.id));
|
|
10147
|
+
} else {
|
|
10148
|
+
const seat = this.seatById.get(id);
|
|
10149
|
+
if (seat && this.seatTierResolution(seat).kind === "invalid") rejected.push(seat.label);
|
|
10150
|
+
else expanded.add(id);
|
|
10151
|
+
}
|
|
9686
10152
|
}
|
|
10153
|
+
if (rejected.length) {
|
|
10154
|
+
this.emitError(new PickerSelectionError(ticketOptionNotApplicableIssue(rejected)));
|
|
10155
|
+
}
|
|
10156
|
+
if (!expanded.size) return [];
|
|
9687
10157
|
this.renderer?.select?.([...expanded]);
|
|
9688
10158
|
if (this.selectionGuestCount() > this.maxSelection) {
|
|
9689
10159
|
this.renderer?.deselect([...expanded]);
|
|
@@ -9751,6 +10221,13 @@ var PickerController = class {
|
|
|
9751
10221
|
}
|
|
9752
10222
|
handleRendererSelect(seat) {
|
|
9753
10223
|
const table = this.groupedTableBySeatId.get(seat.id);
|
|
10224
|
+
const resolution = table ? this.tableTierResolution(table) : this.seatTierResolution(seat);
|
|
10225
|
+
if (resolution.kind === "invalid") {
|
|
10226
|
+
this.renderer?.deselect(table ? table.chairs.map((chair) => chair.id) : [seat.id]);
|
|
10227
|
+
this.emitError(new PickerSelectionError(ticketOptionNotApplicableIssue([table?.label ?? seat.label])));
|
|
10228
|
+
this.emitSelectionChange();
|
|
10229
|
+
return;
|
|
10230
|
+
}
|
|
9754
10231
|
if (table) {
|
|
9755
10232
|
if (this.selectionGuestCount() > this.maxSelection) {
|
|
9756
10233
|
this.renderer?.deselect(table.chairs.map((chair) => chair.id));
|
|
@@ -9832,6 +10309,8 @@ var PickerController = class {
|
|
|
9832
10309
|
const existingGA = (this.hold_?.items ?? []).filter((item) => item.objectType === "ga");
|
|
9833
10310
|
const combinedLabels = [.../* @__PURE__ */ new Set([...existingGA.map((item) => item.label), ...labels])];
|
|
9834
10311
|
if (!combinedLabels.length) return null;
|
|
10312
|
+
const restriction = this.ticketIssue(combinedLabels);
|
|
10313
|
+
if (restriction) throw new PickerSelectionError(restriction);
|
|
9835
10314
|
if (this.hold_ && this.holdCovers(combinedLabels)) return this.hold_;
|
|
9836
10315
|
try {
|
|
9837
10316
|
const selections = combinedLabels.map((label) => {
|
|
@@ -10003,6 +10482,7 @@ var PickerController = class {
|
|
|
10003
10482
|
const available = /* @__PURE__ */ new Set();
|
|
10004
10483
|
for (const seat of seats) {
|
|
10005
10484
|
if (held.has(seat.label)) continue;
|
|
10485
|
+
if (this.seatTierResolution(seat).kind === "invalid") continue;
|
|
10006
10486
|
const id = this.labelToId.get(seat.label);
|
|
10007
10487
|
const status = id ? this.getStatus(id) : void 0;
|
|
10008
10488
|
if ((status ?? "free") === "free") available.add(seat.label);
|
|
@@ -10084,6 +10564,8 @@ var PickerController = class {
|
|
|
10084
10564
|
if (!this.api.book) throw new Error("picker: transport has no book() \u2014 hold-only mode");
|
|
10085
10565
|
const labels = labelsArg ?? this.getSelection().map((seat) => seat.label);
|
|
10086
10566
|
if (!labels.length) return null;
|
|
10567
|
+
const restriction = this.ticketIssue(labels);
|
|
10568
|
+
if (restriction) throw new PickerSelectionError(restriction);
|
|
10087
10569
|
let holdId;
|
|
10088
10570
|
try {
|
|
10089
10571
|
if (this.hold_ && this.holdCovers(labels)) {
|
|
@@ -10210,6 +10692,20 @@ var PickerController = class {
|
|
|
10210
10692
|
getStatus(id) {
|
|
10211
10693
|
return this.renderer?.getStatus(id);
|
|
10212
10694
|
}
|
|
10695
|
+
/** Seat ids whose category the author marked not-for-sale. */
|
|
10696
|
+
notForSaleCategorySeatIds() {
|
|
10697
|
+
const doc = this.doc;
|
|
10698
|
+
if (!doc) return [];
|
|
10699
|
+
const flagged = new Set(
|
|
10700
|
+
doc.categories.filter((category) => category.notForSale).map((category) => category.key)
|
|
10701
|
+
);
|
|
10702
|
+
if (!flagged.size) return [];
|
|
10703
|
+
const ids = [];
|
|
10704
|
+
for (const [id, seat] of this.seatById) {
|
|
10705
|
+
if (flagged.has(seat.categoryKey)) ids.push(id);
|
|
10706
|
+
}
|
|
10707
|
+
return ids;
|
|
10708
|
+
}
|
|
10213
10709
|
flashSeat(id, color) {
|
|
10214
10710
|
this.renderer?.flashSeat(id, color);
|
|
10215
10711
|
}
|
|
@@ -10222,6 +10718,11 @@ var PickerController = class {
|
|
|
10222
10718
|
zoomToFit() {
|
|
10223
10719
|
this.renderer?.zoomToFit();
|
|
10224
10720
|
}
|
|
10721
|
+
/** Preserve section focus while the usable map viewport changes. */
|
|
10722
|
+
refitCurrentView() {
|
|
10723
|
+
if (this.renderer?.refitCurrentView) this.renderer.refitCurrentView();
|
|
10724
|
+
else this.renderer?.zoomToFit();
|
|
10725
|
+
}
|
|
10225
10726
|
worldToScreen(p) {
|
|
10226
10727
|
return this.renderer?.worldToScreen(p) ?? { x: 0, y: 0 };
|
|
10227
10728
|
}
|
|
@@ -10251,7 +10752,8 @@ var PickerController = class {
|
|
|
10251
10752
|
/** Switch the shown floor (2D), then re-apply live seat statuses onto it. */
|
|
10252
10753
|
setFloor(id) {
|
|
10253
10754
|
const r = this.renderer;
|
|
10254
|
-
if (!r?.setActiveFloor || id === r.getActiveFloorId?.()) return;
|
|
10755
|
+
if (!r?.setActiveFloor || id === r.getActiveFloorId?.() && !r.isFloorOverview?.()) return;
|
|
10756
|
+
r.setFloorOverview?.(false);
|
|
10255
10757
|
r.setStacked?.(false);
|
|
10256
10758
|
r.setActiveFloor(id);
|
|
10257
10759
|
void this.resnapshot();
|
|
@@ -10267,12 +10769,24 @@ var PickerController = class {
|
|
|
10267
10769
|
isMultiFloor() {
|
|
10268
10770
|
return (this._doc?.floors?.length ?? 0) > 1;
|
|
10269
10771
|
}
|
|
10772
|
+
/** Enter/leave the source-coordinate all-floor buyer overview. */
|
|
10773
|
+
setFloorOverview(on) {
|
|
10774
|
+
const r = this.renderer;
|
|
10775
|
+
if (!r?.setFloorOverview || on === r.isFloorOverview?.()) return;
|
|
10776
|
+
r.setFloorOverview(on);
|
|
10777
|
+
void this.resnapshot();
|
|
10778
|
+
this.emitSelectionChange();
|
|
10779
|
+
}
|
|
10780
|
+
isFloorOverview() {
|
|
10781
|
+
return this.renderer?.isFloorOverview?.() ?? false;
|
|
10782
|
+
}
|
|
10270
10783
|
/** Tap-a-deck-to-enter: leave the 3D stack, drop to flat 2D on `floorId`, and
|
|
10271
10784
|
* tell the host so it can sync its 2D/3D toggle + floor-switcher state. */
|
|
10272
10785
|
handleDeckTap(floorId) {
|
|
10273
10786
|
const r = this.renderer;
|
|
10274
10787
|
if (!r) return;
|
|
10275
10788
|
r.setViewMode?.("flat");
|
|
10789
|
+
r.setFloorOverview?.(false);
|
|
10276
10790
|
r.setStacked?.(false);
|
|
10277
10791
|
r.setActiveFloor?.(floorId);
|
|
10278
10792
|
void this.resnapshot();
|
|
@@ -10341,10 +10855,30 @@ var PickerController = class {
|
|
|
10341
10855
|
if (!r?.getVisibleWorldRect || !r.getWorldBounds) return null;
|
|
10342
10856
|
return { visible: r.getVisibleWorldRect(), bounds: r.getWorldBounds() };
|
|
10343
10857
|
}
|
|
10858
|
+
getMinimapSnapshot() {
|
|
10859
|
+
return this.renderer?.getMinimapSnapshot?.() ?? { sections: [], seats: [] };
|
|
10860
|
+
}
|
|
10861
|
+
panToWorld(point) {
|
|
10862
|
+
this.renderer?.panToWorld?.(point);
|
|
10863
|
+
}
|
|
10864
|
+
/** Leave section-focus dimming without changing the current zoom. Used when
|
|
10865
|
+
* the minimap viewport itself is dragged to a different part of the venue. */
|
|
10866
|
+
clearSectionFocus() {
|
|
10867
|
+
this.renderer?.clearSectionFocus?.();
|
|
10868
|
+
this.opts.onSectionFocus?.(null);
|
|
10869
|
+
}
|
|
10870
|
+
/** Read-only browser-render evidence for parity/performance audit tooling. */
|
|
10871
|
+
getRenderedQualityEvidence() {
|
|
10872
|
+
return this.renderer?.getRenderedQualityEvidence() ?? null;
|
|
10873
|
+
}
|
|
10344
10874
|
/** Glide in on a section and surface its summary (same path as a section tap). */
|
|
10345
10875
|
focusSection(id) {
|
|
10346
10876
|
this.handleSectionTap(id);
|
|
10347
10877
|
}
|
|
10878
|
+
/** Live seat membership count used by buyer section-navigation controls. */
|
|
10879
|
+
getSectionSeatCount(id) {
|
|
10880
|
+
return this.renderer?.sectionMembers?.(id)?.length ?? 0;
|
|
10881
|
+
}
|
|
10348
10882
|
/** Zoom back out to the whole chart and clear the section-summary card + focus. */
|
|
10349
10883
|
overview() {
|
|
10350
10884
|
this.renderer?.clearSectionFocus?.();
|
|
@@ -10397,15 +10931,21 @@ var PickerController = class {
|
|
|
10397
10931
|
}
|
|
10398
10932
|
const categories = [...byCat.entries()].map(([key, count]) => {
|
|
10399
10933
|
const cat = doc.categories.find((c) => c.key === key);
|
|
10934
|
+
const prices = cat?.tiers?.length ? cat.tiers.map((tier) => tier.price) : [cat?.price ?? 0];
|
|
10935
|
+
const priceMin = Math.min(...prices);
|
|
10936
|
+
const priceMax = Math.max(...prices);
|
|
10400
10937
|
return {
|
|
10401
10938
|
key,
|
|
10402
10939
|
count,
|
|
10403
10940
|
label: cat?.label ?? key,
|
|
10404
10941
|
color: cat?.color ?? "#6e7bff",
|
|
10405
|
-
price:
|
|
10942
|
+
price: priceMin,
|
|
10943
|
+
priceMin,
|
|
10944
|
+
priceMax
|
|
10406
10945
|
};
|
|
10407
10946
|
}).sort((a, b) => a.price - b.price);
|
|
10408
|
-
const
|
|
10947
|
+
const minimums = categories.map((c) => c.priceMin);
|
|
10948
|
+
const maximums = categories.map((c) => c.priceMax);
|
|
10409
10949
|
const zone = sec.zone ? doc.zones?.find((z) => z.id === sec.zone) : void 0;
|
|
10410
10950
|
const color = sec.color ?? zone?.color ?? categories[0]?.color ?? "#6e7bff";
|
|
10411
10951
|
return {
|
|
@@ -10415,8 +10955,8 @@ var PickerController = class {
|
|
|
10415
10955
|
...sec.entrance && sec.entrance.trim() ? { entrance: sec.entrance.trim() } : {},
|
|
10416
10956
|
color,
|
|
10417
10957
|
seatsLeft,
|
|
10418
|
-
priceMin:
|
|
10419
|
-
priceMax:
|
|
10958
|
+
priceMin: minimums.length ? Math.min(...minimums) : 0,
|
|
10959
|
+
priceMax: maximums.length ? Math.max(...maximums) : 0,
|
|
10420
10960
|
categories
|
|
10421
10961
|
};
|
|
10422
10962
|
}
|
|
@@ -10457,11 +10997,12 @@ var PickerController = class {
|
|
|
10457
10997
|
const accessibility = s.accessibility?.length ? { accessibility: s.accessibility } : void 0;
|
|
10458
10998
|
const wheelchair = s.wheelchairSpaceType ? { wheelchairSpaceType: s.wheelchairSpaceType } : void 0;
|
|
10459
10999
|
const context = this.seatContext.get(s.id);
|
|
10460
|
-
const tiers = this.
|
|
10461
|
-
|
|
10462
|
-
|
|
11000
|
+
const tiers = this.tiersForSeat(s);
|
|
11001
|
+
const resolution = this.seatTierResolution(s);
|
|
11002
|
+
if (resolution.kind !== "resolved" || !tiers) {
|
|
11003
|
+
return { id: s.id, label: s.label, ...display, ...context, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), currency: this.currency, ...commercial, ...accessibility, ...wheelchair };
|
|
10463
11004
|
}
|
|
10464
|
-
const chosen =
|
|
11005
|
+
const chosen = resolution.tier;
|
|
10465
11006
|
return {
|
|
10466
11007
|
id: s.id,
|
|
10467
11008
|
label: s.label,
|
|
@@ -10469,6 +11010,7 @@ var PickerController = class {
|
|
|
10469
11010
|
...context,
|
|
10470
11011
|
categoryKey: s.categoryKey,
|
|
10471
11012
|
price: chosen.price,
|
|
11013
|
+
currency: this.currency,
|
|
10472
11014
|
tiers,
|
|
10473
11015
|
tierId: chosen.id,
|
|
10474
11016
|
...commercial,
|
|
@@ -10478,8 +11020,9 @@ var PickerController = class {
|
|
|
10478
11020
|
}
|
|
10479
11021
|
toTableSeat(table) {
|
|
10480
11022
|
const representative = table.chairs[0];
|
|
10481
|
-
const tiers = this.tiersFor(table.categoryKey);
|
|
10482
|
-
const
|
|
11023
|
+
const tiers = this.tiersFor(table.categoryKey)?.filter((tier) => resolveTicketTierForSeat(this._doc, this.tableTierSeat(table), tier.id).kind === "resolved");
|
|
11024
|
+
const resolution = this.tableTierResolution(table);
|
|
11025
|
+
const chosen = resolution.kind === "resolved" ? resolution.tier : void 0;
|
|
10483
11026
|
return {
|
|
10484
11027
|
id: representative?.id ?? table.objectId,
|
|
10485
11028
|
label: table.label,
|
|
@@ -10490,6 +11033,7 @@ var PickerController = class {
|
|
|
10490
11033
|
rowLabel: table.displayLabel ?? table.label,
|
|
10491
11034
|
categoryKey: table.categoryKey,
|
|
10492
11035
|
price: chosen?.price ?? this.priceFor(table.categoryKey),
|
|
11036
|
+
currency: this.currency,
|
|
10493
11037
|
...tiers ? { tiers, tierId: chosen?.id } : {},
|
|
10494
11038
|
objectType: "table",
|
|
10495
11039
|
bookingMode: table.mode,
|
|
@@ -10519,6 +11063,27 @@ var PickerController = class {
|
|
|
10519
11063
|
const t2 = this._doc?.categories.find((c) => c.key === categoryKey)?.tiers;
|
|
10520
11064
|
return t2 && t2.length ? t2 : void 0;
|
|
10521
11065
|
}
|
|
11066
|
+
tiersForSeat(seat) {
|
|
11067
|
+
if (!this._doc) return void 0;
|
|
11068
|
+
const tiers = applicableTicketTiers(this._doc, seat);
|
|
11069
|
+
return tiers.length ? tiers : void 0;
|
|
11070
|
+
}
|
|
11071
|
+
seatTierResolution(seat) {
|
|
11072
|
+
if (!this._doc) return { kind: "none" };
|
|
11073
|
+
return resolveTicketTierForSeat(this._doc, seat, this.seatTiers.get(seat.id));
|
|
11074
|
+
}
|
|
11075
|
+
tableTierSeat(table) {
|
|
11076
|
+
return {
|
|
11077
|
+
label: table.label,
|
|
11078
|
+
categoryKey: table.categoryKey,
|
|
11079
|
+
accessibility: table.chairs.flatMap((chair) => chair.accessibility ?? [])
|
|
11080
|
+
};
|
|
11081
|
+
}
|
|
11082
|
+
tableTierResolution(table) {
|
|
11083
|
+
if (!this._doc) return { kind: "none" };
|
|
11084
|
+
const representativeId = table.chairs[0]?.id ?? "";
|
|
11085
|
+
return resolveTicketTierForSeat(this._doc, this.tableTierSeat(table), this.seatTiers.get(representativeId));
|
|
11086
|
+
}
|
|
10522
11087
|
/**
|
|
10523
11088
|
* Choose a ticket tier for a selected seat (e.g. Adult → Child). Re-emits the
|
|
10524
11089
|
* selection so the host's cart + the eventual hold carry the new tier + price.
|
|
@@ -10528,7 +11093,7 @@ var PickerController = class {
|
|
|
10528
11093
|
setSeatTier(seatId, tierId) {
|
|
10529
11094
|
const seat = this.seatById.get(seatId);
|
|
10530
11095
|
if (!seat) return;
|
|
10531
|
-
const tiers = this.
|
|
11096
|
+
const tiers = this.tiersForSeat(seat);
|
|
10532
11097
|
if (!tiers) return;
|
|
10533
11098
|
if (tierId == null) this.seatTiers.delete(seatId);
|
|
10534
11099
|
else if (tiers.some((t2) => t2.id === tierId)) this.seatTiers.set(seatId, tierId);
|
|
@@ -10549,6 +11114,16 @@ var PickerController = class {
|
|
|
10549
11114
|
this.opts.onSelectionChange?.(this.getSelection());
|
|
10550
11115
|
this.emitOrphanHint();
|
|
10551
11116
|
}
|
|
11117
|
+
/** Check explicit tier applicability and companion relationships for the
|
|
11118
|
+
* current (or supplied) seats. Ticket display names are never semantic input. */
|
|
11119
|
+
ticketIssue(labels) {
|
|
11120
|
+
if (!this._doc) return null;
|
|
11121
|
+
const seats = labels ? this.seatsForLabels(labels) : this.getSelection();
|
|
11122
|
+
return ticketSelectionIssue(this._doc, seats.map((seat) => ({
|
|
11123
|
+
label: seat.label,
|
|
11124
|
+
...seat.tierId ? { tierId: seat.tierId } : {}
|
|
11125
|
+
})));
|
|
11126
|
+
}
|
|
10552
11127
|
/**
|
|
10553
11128
|
* Orphan-seat advice on manual selection: when the buyer's current picks
|
|
10554
11129
|
* strand one (or more) single free seats between unavailable same-row
|
|
@@ -10559,6 +11134,12 @@ var PickerController = class {
|
|
|
10559
11134
|
if (!this.opts.onHint) return;
|
|
10560
11135
|
const r = this.renderer;
|
|
10561
11136
|
if (!r) return;
|
|
11137
|
+
const restriction = this.ticketIssue();
|
|
11138
|
+
if (restriction) {
|
|
11139
|
+
this.hintShown = true;
|
|
11140
|
+
this.opts.onHint(restriction.code === "companion_pair_required" ? t("picker.companionPairRequired") : "That ticket choice is not available for the selected seat.");
|
|
11141
|
+
return;
|
|
11142
|
+
}
|
|
10562
11143
|
const selected = new Set(r.getSelection().map((s) => s.id));
|
|
10563
11144
|
const stranded = selected.size ? strandedSingles(this.seatById.values(), (id) => r.getStatus(id), selected) : [];
|
|
10564
11145
|
if (stranded.length > 0) {
|
|
@@ -10680,6 +11261,8 @@ var PickerController = class {
|
|
|
10680
11261
|
["free", "held", "booked", "not_for_sale"].forEach((st) => {
|
|
10681
11262
|
if (st !== defaultSeatStatus && byStatus[st].length) r.setStatus(byStatus[st], st);
|
|
10682
11263
|
});
|
|
11264
|
+
const notForSaleCategoryIds = this.notForSaleCategorySeatIds();
|
|
11265
|
+
if (notForSaleCategoryIds.length) r.setStatus(notForSaleCategoryIds, "not_for_sale");
|
|
10683
11266
|
this.clearBookedHoldIfSettled();
|
|
10684
11267
|
this.opts.onStatusChange?.();
|
|
10685
11268
|
}
|
|
@@ -12065,6 +12648,7 @@ async function loadLocale(code) {
|
|
|
12065
12648
|
MAX_EVENT_INVENTORY,
|
|
12066
12649
|
MAX_GA_CAPACITY,
|
|
12067
12650
|
PickerController,
|
|
12651
|
+
PickerSelectionError,
|
|
12068
12652
|
RENDERED_QUALITY_REPORT_VERSION,
|
|
12069
12653
|
SEAT_COMMERCIAL_MARKS,
|
|
12070
12654
|
SUPPORTED_LOCALES,
|
|
@@ -12088,6 +12672,7 @@ async function loadLocale(code) {
|
|
|
12088
12672
|
expandTable,
|
|
12089
12673
|
expandTableSlots,
|
|
12090
12674
|
floorObjects,
|
|
12675
|
+
floorOverviewTranslations,
|
|
12091
12676
|
floorsOf,
|
|
12092
12677
|
formatDate,
|
|
12093
12678
|
formatMinor,
|
|
@@ -12106,6 +12691,7 @@ async function loadLocale(code) {
|
|
|
12106
12691
|
isGaUnitLabel,
|
|
12107
12692
|
isSectionHidden,
|
|
12108
12693
|
layerOf,
|
|
12694
|
+
layoutFloorOverview,
|
|
12109
12695
|
loadLocale,
|
|
12110
12696
|
objectCenter,
|
|
12111
12697
|
owningSectionForObject,
|
|
@@ -12125,6 +12711,7 @@ async function loadLocale(code) {
|
|
|
12125
12711
|
tCount,
|
|
12126
12712
|
tableInventoryCount,
|
|
12127
12713
|
tableSeatCountsBySide,
|
|
12714
|
+
translateObject,
|
|
12128
12715
|
validGAInventorySegments
|
|
12129
12716
|
});
|
|
12130
12717
|
//# sourceMappingURL=index.cjs.map
|