@seatlayer/core 0.26.0 → 0.27.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/{de-73TIXYJH.js → de-UHAOVDS3.js} +3 -2
- package/dist/de-UHAOVDS3.js.map +1 -0
- package/dist/{es-SKAODLTR.js → es-6TJS2L7S.js} +3 -2
- package/dist/es-6TJS2L7S.js.map +1 -0
- package/dist/{fr-J4637T6V.js → fr-MMSY7FPE.js} +3 -2
- package/dist/fr-MMSY7FPE.js.map +1 -0
- package/dist/index.cjs +396 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +393 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/de-73TIXYJH.js.map +0 -1
- package/dist/es-SKAODLTR.js.map +0 -1
- package/dist/fr-J4637T6V.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -48,6 +48,7 @@ var init_es = __esm({
|
|
|
48
48
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
49
49
|
"map.aria": "Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.",
|
|
50
50
|
"map.seatsLeft": "{count} LIBRES",
|
|
51
|
+
"map.soldOut": "AGOTADO",
|
|
51
52
|
"map.statusHeld": "En espera",
|
|
52
53
|
"map.statusTaken": "Ocupado",
|
|
53
54
|
"map.fromPrice": "DESDE {price}",
|
|
@@ -55,7 +56,7 @@ var init_es = __esm({
|
|
|
55
56
|
"picker.floor": "Piso",
|
|
56
57
|
"picker.zoomLevel": "Nivel de zoom",
|
|
57
58
|
"picker.rungTip.zones": "Vista general \u2014 grupos de secciones como Grada norte o VIP",
|
|
58
|
-
"picker.rungTip.sections": "Bloques de secci\xF3n \u2014
|
|
59
|
+
"picker.rungTip.sections": "Bloques de secci\xF3n \u2014 las secciones agotadas y casi llenas se aten\xFAan para ver la disponibilidad de un vistazo",
|
|
59
60
|
"picker.rungTip.seats": "Asientos individuales \u2014 los bloques se convierten en puntos",
|
|
60
61
|
"picker.rungLabel.zones": "ZONAS",
|
|
61
62
|
"picker.rungLabel.sections": "SECCIONES",
|
|
@@ -107,6 +108,7 @@ var init_de = __esm({
|
|
|
107
108
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
108
109
|
"map.aria": "Sitzplan. Mit Pfeiltasten zwischen Pl\xE4tzen navigieren, Eingabe zum Ausw\xE4hlen.",
|
|
109
110
|
"map.seatsLeft": "{count} FREI",
|
|
111
|
+
"map.soldOut": "AUSVERKAUFT",
|
|
110
112
|
"map.statusHeld": "Reserviert",
|
|
111
113
|
"map.statusTaken": "Vergeben",
|
|
112
114
|
"map.fromPrice": "AB {price}",
|
|
@@ -114,7 +116,7 @@ var init_de = __esm({
|
|
|
114
116
|
"picker.floor": "Etage",
|
|
115
117
|
"picker.zoomLevel": "Zoomstufe",
|
|
116
118
|
"picker.rungTip.zones": "\xDCbersicht \u2014 Bereichsgruppen wie Nordtrib\xFCne oder VIP",
|
|
117
|
-
"picker.rungTip.sections": "Bereichs-Bl\xF6cke \u2014
|
|
119
|
+
"picker.rungTip.sections": "Bereichs-Bl\xF6cke \u2014 ausverkaufte und fast volle Bereiche werden abgedunkelt, um die Verf\xFCgbarkeit auf einen Blick zu zeigen",
|
|
118
120
|
"picker.rungTip.seats": "Einzelne Pl\xE4tze \u2014 Bl\xF6cke l\xF6sen sich zu Punkten auf",
|
|
119
121
|
"picker.rungLabel.zones": "ZONEN",
|
|
120
122
|
"picker.rungLabel.sections": "BEREICHE",
|
|
@@ -166,6 +168,7 @@ var init_fr = __esm({
|
|
|
166
168
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
167
169
|
"map.aria": "Plan de salle. Utilisez les fl\xE8ches pour naviguer entre les si\xE8ges, Entr\xE9e pour s\xE9lectionner.",
|
|
168
170
|
"map.seatsLeft": "{count} LIBRES",
|
|
171
|
+
"map.soldOut": "COMPLET",
|
|
169
172
|
"map.statusHeld": "En attente",
|
|
170
173
|
"map.statusTaken": "Pris",
|
|
171
174
|
"map.fromPrice": "D\xC8S {price}",
|
|
@@ -173,7 +176,7 @@ var init_fr = __esm({
|
|
|
173
176
|
"picker.floor": "\xC9tage",
|
|
174
177
|
"picker.zoomLevel": "Niveau de zoom",
|
|
175
178
|
"picker.rungTip.zones": "Vue g\xE9n\xE9rale \u2014 groupes de sections comme Tribune nord ou VIP",
|
|
176
|
-
"picker.rungTip.sections": "Blocs de sections \u2014
|
|
179
|
+
"picker.rungTip.sections": "Blocs de sections \u2014 les sections compl\xE8tes ou presque pleines sont estomp\xE9es pour voir la disponibilit\xE9 en un coup d\u2019\u0153il",
|
|
177
180
|
"picker.rungTip.seats": "Si\xE8ges individuels \u2014 les blocs se transforment en points",
|
|
178
181
|
"picker.rungLabel.zones": "ZONES",
|
|
179
182
|
"picker.rungLabel.sections": "SECTIONS",
|
|
@@ -1823,6 +1826,169 @@ function buyerBackgroundImage(owner) {
|
|
|
1823
1826
|
return background?.url && !background.assetId ? background : void 0;
|
|
1824
1827
|
}
|
|
1825
1828
|
|
|
1829
|
+
// src/core/icons.ts
|
|
1830
|
+
var VENUE_ICON_VIEWBOX = 24;
|
|
1831
|
+
var VENUE_ICON_STROKE = 2;
|
|
1832
|
+
var WHEELCHAIR = "M13 4.6a1.6 1.6 0 1 0-3.2 0 1.6 1.6 0 0 0 3.2 0 M11 6.5V13h5l2.4 6 M15 16.4A5 5 0 1 1 9 11.3";
|
|
1833
|
+
var VENUE_ICONS = [
|
|
1834
|
+
// ---- Facilities --------------------------------------------------------
|
|
1835
|
+
{
|
|
1836
|
+
key: "restroom-men",
|
|
1837
|
+
label: "Men's restroom",
|
|
1838
|
+
group: "facilities",
|
|
1839
|
+
path: "M16 7a4 4 0 1 0-8 0 4 4 0 0 0 8 0 M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
key: "restroom-women",
|
|
1843
|
+
label: "Women's restroom",
|
|
1844
|
+
group: "facilities",
|
|
1845
|
+
path: "M15 5a3 3 0 1 0-6 0 3 3 0 0 0 6 0 M12 8l-4 10h8l-4-10 M10 18v4 M14 18v4"
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
key: "restroom-accessible",
|
|
1849
|
+
label: "Accessible restroom",
|
|
1850
|
+
group: "facilities",
|
|
1851
|
+
path: WHEELCHAIR
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
key: "first-aid",
|
|
1855
|
+
label: "First aid",
|
|
1856
|
+
group: "facilities",
|
|
1857
|
+
path: "M5 4h14a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z M12 8v8 M8 12h8"
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
key: "coat-check",
|
|
1861
|
+
label: "Coat check",
|
|
1862
|
+
group: "facilities",
|
|
1863
|
+
path: "M12 6a2 2 0 0 1 0-4 2 2 0 0 1 1.6 3.2L21 13H3l8.4-7.8 M3 13h18"
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
key: "atm",
|
|
1867
|
+
label: "ATM / cash",
|
|
1868
|
+
group: "facilities",
|
|
1869
|
+
path: "M2 6h20v12H2V6Z M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0 M6 9h.01 M18 15h.01"
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
key: "info",
|
|
1873
|
+
label: "Info point",
|
|
1874
|
+
group: "facilities",
|
|
1875
|
+
path: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M12 11v5 M12 8h.01"
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
key: "lost-found",
|
|
1879
|
+
label: "Lost & found",
|
|
1880
|
+
group: "facilities",
|
|
1881
|
+
path: "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14 M16 16l5 5 M9 8.5a2 2 0 1 1 3 1.7c-.8.5-1 .8-1 1.8 M11 15h.01"
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
key: "charging",
|
|
1885
|
+
label: "Charging point",
|
|
1886
|
+
group: "facilities",
|
|
1887
|
+
path: "M3 8h13v8H3V8Z M16 10h3v4h-3 M9.6 9l-2 3.5h2.5l-1.5 3"
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
key: "smoking",
|
|
1891
|
+
label: "Smoking area",
|
|
1892
|
+
group: "facilities",
|
|
1893
|
+
path: "M2 15h13v3H2v-3Z M18 16h2 M19 8c0 1 1 1.5 1 2.5S19 12 19 13"
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
key: "no-smoking",
|
|
1897
|
+
label: "No smoking",
|
|
1898
|
+
group: "facilities",
|
|
1899
|
+
path: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M5.6 5.6l12.8 12.8 M7 13h6v2H7v-2Z"
|
|
1900
|
+
},
|
|
1901
|
+
// ---- Food & drink ------------------------------------------------------
|
|
1902
|
+
{
|
|
1903
|
+
key: "food",
|
|
1904
|
+
label: "Food",
|
|
1905
|
+
group: "food-drink",
|
|
1906
|
+
path: "M7 3v6a2 2 0 0 0 4 0V3 M9 11v10 M17 3c-1.6 1-2.2 3-2.2 6 0 2 .9 3.2 2.2 3.6V21"
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
key: "bar",
|
|
1910
|
+
label: "Bar",
|
|
1911
|
+
group: "food-drink",
|
|
1912
|
+
path: "M4 5h16l-8 8-8-8Z M12 13v6 M8 20h8"
|
|
1913
|
+
},
|
|
1914
|
+
{
|
|
1915
|
+
key: "coffee",
|
|
1916
|
+
label: "Caf\xE9 / coffee",
|
|
1917
|
+
group: "food-drink",
|
|
1918
|
+
path: "M4 8h13v4a5 5 0 0 1-5 5H9a5 5 0 0 1-5-5V8Z M17 9h2a2 2 0 0 1 0 4h-2 M8 2v2 M11 2v2 M4 21h14"
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
key: "water",
|
|
1922
|
+
label: "Water / drinks",
|
|
1923
|
+
group: "food-drink",
|
|
1924
|
+
path: "M12 22a7 7 0 0 1-7-7c0-5 7-12 7-12s7 7 7 12a7 7 0 0 1-7 7Z"
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
key: "merch",
|
|
1928
|
+
label: "Merch / shop",
|
|
1929
|
+
group: "food-drink",
|
|
1930
|
+
path: "M6 8h12l-1 12H7L6 8Z M9 8V6a3 3 0 0 1 6 0v2"
|
|
1931
|
+
},
|
|
1932
|
+
// ---- Getting around ----------------------------------------------------
|
|
1933
|
+
{
|
|
1934
|
+
key: "entrance",
|
|
1935
|
+
label: "Entrance",
|
|
1936
|
+
group: "navigation",
|
|
1937
|
+
path: "M14 3h5a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-5 M3 12h11 M10 8l4 4-4 4"
|
|
1938
|
+
},
|
|
1939
|
+
{
|
|
1940
|
+
key: "exit",
|
|
1941
|
+
label: "Exit",
|
|
1942
|
+
group: "navigation",
|
|
1943
|
+
path: "M10 3H5a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h5 M14 12h7 M17 8l4 4-4 4"
|
|
1944
|
+
},
|
|
1945
|
+
{
|
|
1946
|
+
key: "emergency-exit",
|
|
1947
|
+
label: "Emergency exit",
|
|
1948
|
+
group: "navigation",
|
|
1949
|
+
path: "M14 4.6a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0 M12.5 8l-3.5 2 1.6 3.6-2 4.4 M12.5 10l3.5 1.5 M9 10.5l-3.5 1 M15 12h6 M18 9l3 3-3 3"
|
|
1950
|
+
},
|
|
1951
|
+
{
|
|
1952
|
+
key: "stairs",
|
|
1953
|
+
label: "Stairs",
|
|
1954
|
+
group: "navigation",
|
|
1955
|
+
path: "M3 20v-4h4v-4h4v-4h4V4h5"
|
|
1956
|
+
},
|
|
1957
|
+
{
|
|
1958
|
+
key: "elevator",
|
|
1959
|
+
label: "Elevator",
|
|
1960
|
+
group: "navigation",
|
|
1961
|
+
path: "M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M8 11l1.5-2 1.5 2 M8 14l1.5 2 1.5-2 M15 8v8"
|
|
1962
|
+
},
|
|
1963
|
+
{
|
|
1964
|
+
key: "parking",
|
|
1965
|
+
label: "Parking",
|
|
1966
|
+
group: "navigation",
|
|
1967
|
+
path: "M5 3h14a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M9 17V7h4a3 3 0 0 1 0 6H9"
|
|
1968
|
+
},
|
|
1969
|
+
// ---- Accessibility -----------------------------------------------------
|
|
1970
|
+
{
|
|
1971
|
+
key: "wheelchair",
|
|
1972
|
+
label: "Wheelchair access",
|
|
1973
|
+
group: "accessibility",
|
|
1974
|
+
path: WHEELCHAIR
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
key: "hearing",
|
|
1978
|
+
label: "Hearing assistance",
|
|
1979
|
+
group: "accessibility",
|
|
1980
|
+
path: "M8 20a4 4 0 0 1-2-3c0-1 .5-2 .5-3a4.5 4.5 0 1 1 9 0c0 1.4-1 2-2 2.4-1.2.5-1.5 1-1.5 2.2 M17 6a5 5 0 0 1 1 6 M19.5 4a8 8 0 0 1 1.2 9"
|
|
1981
|
+
}
|
|
1982
|
+
];
|
|
1983
|
+
var BY_KEY = new Map(VENUE_ICONS.map((icon) => [icon.key, icon]));
|
|
1984
|
+
function venueIcon(key) {
|
|
1985
|
+
return key ? BY_KEY.get(key) : void 0;
|
|
1986
|
+
}
|
|
1987
|
+
function venueIconPath(key) {
|
|
1988
|
+
return venueIcon(key)?.path;
|
|
1989
|
+
}
|
|
1990
|
+
var VENUE_ICON_KEYS = VENUE_ICONS.map((icon) => icon.key);
|
|
1991
|
+
|
|
1826
1992
|
// src/core/spatialIndex.ts
|
|
1827
1993
|
var DEFAULT_SEAT_RADIUS = 9;
|
|
1828
1994
|
function halfExtents(shape) {
|
|
@@ -2160,6 +2326,7 @@ var en = {
|
|
|
2160
2326
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
2161
2327
|
"map.aria": "Seating map. Use arrow keys to move between seats, Enter to select.",
|
|
2162
2328
|
"map.seatsLeft": "{count} LEFT",
|
|
2329
|
+
"map.soldOut": "SOLD OUT",
|
|
2163
2330
|
"map.fromPrice": "FROM {price}",
|
|
2164
2331
|
"map.statusHeld": "On hold",
|
|
2165
2332
|
"map.statusTaken": "Taken",
|
|
@@ -2167,7 +2334,7 @@ var en = {
|
|
|
2167
2334
|
"picker.floor": "Floor",
|
|
2168
2335
|
"picker.zoomLevel": "Zoom level",
|
|
2169
2336
|
"picker.rungTip.zones": "Venue overview \u2014 groups of sections such as North Stand or VIP",
|
|
2170
|
-
"picker.rungTip.sections": "Section blocks \u2014
|
|
2337
|
+
"picker.rungTip.sections": "Section blocks \u2014 sold-out and nearly-gone sections shade to show availability at a glance",
|
|
2171
2338
|
"picker.rungTip.seats": "Individual seats \u2014 blocks melt into dots",
|
|
2172
2339
|
"picker.rungLabel.zones": "ZONES",
|
|
2173
2340
|
"picker.rungLabel.sections": "SECTIONS",
|
|
@@ -2368,6 +2535,22 @@ function overviewPalette(canvasBackground) {
|
|
|
2368
2535
|
focalStroke: DARK_OVERVIEW_FOCAL_STROKE
|
|
2369
2536
|
};
|
|
2370
2537
|
}
|
|
2538
|
+
var SECTION_NEARLY_GONE_RATIO = 0.1;
|
|
2539
|
+
function overviewStateFill(palette, state) {
|
|
2540
|
+
const base = palette.sectionFill;
|
|
2541
|
+
const soldOut = desaturate(darken(base, 0.2), 0.85);
|
|
2542
|
+
switch (state) {
|
|
2543
|
+
case "closed":
|
|
2544
|
+
return darken(base, 0.12);
|
|
2545
|
+
case "sold-out":
|
|
2546
|
+
return soldOut;
|
|
2547
|
+
case "nearly-gone":
|
|
2548
|
+
return lerpColor(base, soldOut, 0.4);
|
|
2549
|
+
case "normal":
|
|
2550
|
+
default:
|
|
2551
|
+
return base;
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2371
2554
|
var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
2372
2555
|
function seatIdOf(target) {
|
|
2373
2556
|
const n = target;
|
|
@@ -2390,6 +2573,13 @@ function darken(hex, amt) {
|
|
|
2390
2573
|
const mix = (c) => Math.round(c * (1 - amt));
|
|
2391
2574
|
return `#${(1 << 24 | mix(n >> 16 & 255) << 16 | mix(n >> 8 & 255) << 8 | mix(n & 255)).toString(16).slice(1)}`;
|
|
2392
2575
|
}
|
|
2576
|
+
function desaturate(hex, amt) {
|
|
2577
|
+
const rgb2 = hexToRgb(hex);
|
|
2578
|
+
if (!rgb2) return hex;
|
|
2579
|
+
const [r, g, b] = rgb2;
|
|
2580
|
+
const grey = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
2581
|
+
return toHex(r + (grey - r) * amt, g + (grey - g) * amt, b + (grey - b) * amt);
|
|
2582
|
+
}
|
|
2393
2583
|
function polyBounds(pts) {
|
|
2394
2584
|
let minX = Infinity;
|
|
2395
2585
|
let minY = Infinity;
|
|
@@ -2453,18 +2643,36 @@ function polygonLabelCandidates(outer, holes, preferred) {
|
|
|
2453
2643
|
}
|
|
2454
2644
|
return points.sort((left, right) => Math.hypot(left.x - centre.x, left.y - centre.y) - Math.hypot(right.x - centre.x, right.y - centre.y)).filter((point, index, all) => index === all.findIndex((other) => Math.abs(other.x - point.x) < 1e-6 && Math.abs(other.y - point.y) < 1e-6));
|
|
2455
2645
|
}
|
|
2646
|
+
function roundedPolygonSubpath(context, points, radius) {
|
|
2647
|
+
const n = points.length;
|
|
2648
|
+
const start = { x: (points[n - 1].x + points[0].x) / 2, y: (points[n - 1].y + points[0].y) / 2 };
|
|
2649
|
+
context.moveTo(start.x, start.y);
|
|
2650
|
+
for (let i = 0; i < n; i += 1) {
|
|
2651
|
+
const curr = points[i];
|
|
2652
|
+
const next = points[(i + 1) % n];
|
|
2653
|
+
const prev = points[(i - 1 + n) % n];
|
|
2654
|
+
const rMax = Math.min(
|
|
2655
|
+
Math.hypot(curr.x - prev.x, curr.y - prev.y) / 2,
|
|
2656
|
+
Math.hypot(next.x - curr.x, next.y - curr.y) / 2
|
|
2657
|
+
);
|
|
2658
|
+
context.arcTo(curr.x, curr.y, next.x, next.y, Math.max(0, Math.min(radius, rMax)));
|
|
2659
|
+
}
|
|
2660
|
+
context.closePath();
|
|
2661
|
+
}
|
|
2456
2662
|
function polygonWithHolesShape(outer, holes, attrs, outerPath) {
|
|
2457
2663
|
const signedArea = (points) => points.reduce((sum, point, index) => {
|
|
2458
2664
|
const next = points[(index + 1) % points.length];
|
|
2459
2665
|
return sum + point.x * next.y - next.x * point.y;
|
|
2460
2666
|
}, 0);
|
|
2461
2667
|
const outerClockwise = signedArea(outer) > 0;
|
|
2668
|
+
const cornerRadius = attrs.cornerRadius && attrs.cornerRadius > 0 ? attrs.cornerRadius : 0;
|
|
2462
2669
|
return new import_Shape.Shape({
|
|
2463
2670
|
...attrs,
|
|
2464
2671
|
sceneFunc(context, shape) {
|
|
2465
2672
|
context.beginPath();
|
|
2466
2673
|
const polygonPath = (points) => {
|
|
2467
2674
|
if (!points.length) return;
|
|
2675
|
+
if (cornerRadius > 0 && points.length >= 3) return roundedPolygonSubpath(context, points, cornerRadius);
|
|
2468
2676
|
context.moveTo(points[0].x, points[0].y);
|
|
2469
2677
|
for (let index = 1; index < points.length; index += 1) context.lineTo(points[index].x, points[index].y);
|
|
2470
2678
|
context.closePath();
|
|
@@ -2599,6 +2807,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2599
2807
|
this.accessGlyphById = /* @__PURE__ */ new Map();
|
|
2600
2808
|
/** Authored free-text nodes obey the same rendered-size visibility floor. */
|
|
2601
2809
|
this.freeTextById = /* @__PURE__ */ new Map();
|
|
2810
|
+
/** Vector venue-icon Path nodes + authored size; obey the free-text size floor. */
|
|
2811
|
+
this.iconNodeById = /* @__PURE__ */ new Map();
|
|
2602
2812
|
/** Stage/rink landmarks retain a readable screen-space caption at overview. */
|
|
2603
2813
|
this.primaryFocalLabels = /* @__PURE__ */ new Map();
|
|
2604
2814
|
/** GA paint and text share price/highlight filter state. */
|
|
@@ -2612,6 +2822,12 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2612
2822
|
this.effSelection = DEF_SELECTION;
|
|
2613
2823
|
/** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */
|
|
2614
2824
|
this.colorblind = false;
|
|
2825
|
+
/** Stable per-category-KEY colorblind hue (OV-46) — order-independent. */
|
|
2826
|
+
this.cbHueByKey = /* @__PURE__ */ new Map();
|
|
2827
|
+
/** OV-45(a): authored row-letter labels for the buyer/preview map, resolved in
|
|
2828
|
+
* world space (matching seat labels) and honouring each row's labelPresentation
|
|
2829
|
+
* (position/rotation/visibility/style). Painted at the seats LOD rung. */
|
|
2830
|
+
this.rowLabelPlan = [];
|
|
2615
2831
|
/** Category order from the doc — the stable index into the CB palette. */
|
|
2616
2832
|
this.catOrder = [];
|
|
2617
2833
|
this.selection = /* @__PURE__ */ new Set();
|
|
@@ -2981,6 +3197,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2981
3197
|
this.accessRingById.clear();
|
|
2982
3198
|
this.accessGlyphById.clear();
|
|
2983
3199
|
this.freeTextById.clear();
|
|
3200
|
+
this.iconNodeById.clear();
|
|
2984
3201
|
this.primaryFocalLabels.clear();
|
|
2985
3202
|
this.gaById.clear();
|
|
2986
3203
|
for (const marker of this.selectionMarkers.values()) marker.destroy();
|
|
@@ -3035,13 +3252,22 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3035
3252
|
this.catColor.clear();
|
|
3036
3253
|
this.catPrice.clear();
|
|
3037
3254
|
this.catOrder = doc.categories.map((c) => c.key);
|
|
3255
|
+
this.cbHueByKey.clear();
|
|
3256
|
+
[...this.catOrder].sort().forEach((key, i) => {
|
|
3257
|
+
this.cbHueByKey.set(key, CB_PALETTE[i % CB_PALETTE.length]);
|
|
3258
|
+
});
|
|
3038
3259
|
for (const c of doc.categories) {
|
|
3039
3260
|
this.catColor.set(c.key, c.color);
|
|
3040
3261
|
if (typeof c.price === "number") this.catPrice.set(c.key, c.price);
|
|
3041
3262
|
}
|
|
3042
3263
|
for (const obj of view.objects) {
|
|
3043
3264
|
if (obj.type === "booth") {
|
|
3044
|
-
this.boothDims.set(obj.id, {
|
|
3265
|
+
this.boothDims.set(obj.id, {
|
|
3266
|
+
width: obj.width,
|
|
3267
|
+
height: obj.height,
|
|
3268
|
+
rotation: obj.rotation,
|
|
3269
|
+
...obj.points && obj.points.length >= 3 ? { points: obj.points.map((p) => ({ x: p.x, y: p.y })) } : {}
|
|
3270
|
+
});
|
|
3045
3271
|
}
|
|
3046
3272
|
}
|
|
3047
3273
|
this.seats = expandChart(view, {
|
|
@@ -3061,6 +3287,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
3061
3287
|
this.unsectionedSeatGroup = new import_Group.Group({ listening: true });
|
|
3062
3288
|
this.seatLayer.add(this.unsectionedSeatGroup);
|
|
3063
3289
|
this.renderSeats();
|
|
3290
|
+
this.buildRowLabelPlan(view);
|
|
3064
3291
|
this.overlayLayer.add(this.labelGroup);
|
|
3065
3292
|
this.overlayLayer.add(this.fgDecorGroup);
|
|
3066
3293
|
this.overlayLayer.add(this.hoverRing);
|
|
@@ -4372,25 +4599,42 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4372
4599
|
renderBoothUnit(seat) {
|
|
4373
4600
|
const target = this.seatContainer(seat.id);
|
|
4374
4601
|
const dims = this.boothDims.get(seat.rowId) ?? { width: 40, height: 30, rotation: 0 };
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4602
|
+
let labelX = seat.x;
|
|
4603
|
+
let labelY = seat.y;
|
|
4604
|
+
let node;
|
|
4605
|
+
if (dims.points && dims.points.length >= 3) {
|
|
4606
|
+
node = new import_Line.Line({
|
|
4607
|
+
x: seat.x,
|
|
4608
|
+
y: seat.y,
|
|
4609
|
+
points: dims.points.flatMap((p) => [p.x, p.y]),
|
|
4610
|
+
closed: true,
|
|
4611
|
+
perfectDrawEnabled: false,
|
|
4612
|
+
shadowForStrokeEnabled: false,
|
|
4613
|
+
hitStrokeWidth: 0
|
|
4614
|
+
});
|
|
4615
|
+
labelX = seat.x + dims.points.reduce((a, p) => a + p.x, 0) / dims.points.length;
|
|
4616
|
+
labelY = seat.y + dims.points.reduce((a, p) => a + p.y, 0) / dims.points.length;
|
|
4617
|
+
} else {
|
|
4618
|
+
node = new import_Rect.Rect({
|
|
4619
|
+
x: seat.x,
|
|
4620
|
+
y: seat.y,
|
|
4621
|
+
width: dims.width,
|
|
4622
|
+
height: dims.height,
|
|
4623
|
+
offsetX: dims.width / 2,
|
|
4624
|
+
offsetY: dims.height / 2,
|
|
4625
|
+
rotation: dims.rotation,
|
|
4626
|
+
cornerRadius: 4,
|
|
4627
|
+
perfectDrawEnabled: false,
|
|
4628
|
+
shadowForStrokeEnabled: false,
|
|
4629
|
+
hitStrokeWidth: 0
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
node.setAttr("seatId", seat.id);
|
|
4633
|
+
this.circleById.set(seat.id, node);
|
|
4634
|
+
target.add(node);
|
|
4391
4635
|
const t2 = new import_Text.Text({
|
|
4392
|
-
x:
|
|
4393
|
-
y:
|
|
4636
|
+
x: labelX,
|
|
4637
|
+
y: labelY,
|
|
4394
4638
|
text: seat.displayLabel ?? seat.label,
|
|
4395
4639
|
fontSize: BOOTH_LABEL_FONT_SIZE,
|
|
4396
4640
|
fontStyle: "600",
|
|
@@ -4405,7 +4649,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4405
4649
|
this.hasBoothText = true;
|
|
4406
4650
|
this.boothLabelById.set(seat.id, t2);
|
|
4407
4651
|
target.add(t2);
|
|
4408
|
-
this.paintSeat(
|
|
4652
|
+
this.paintSeat(node, seat.id);
|
|
4409
4653
|
}
|
|
4410
4654
|
/**
|
|
4411
4655
|
* Build the centred accessibility glyph for a seat. Sized relative to the seat
|
|
@@ -4473,8 +4717,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4473
4717
|
/** The category's display color — Okabe-Ito hue when colorblind-safe is on. */
|
|
4474
4718
|
seatBaseColor(categoryKey) {
|
|
4475
4719
|
if (!this.colorblind) return this.catColor.get(categoryKey) ?? "#6e7bff";
|
|
4476
|
-
|
|
4477
|
-
return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];
|
|
4720
|
+
return this.cbHueByKey.get(categoryKey) ?? CB_PALETTE[0];
|
|
4478
4721
|
}
|
|
4479
4722
|
/** Per-seat authored label size relative to the neutral default (1 = default),
|
|
4480
4723
|
* mirroring the section convention (labelStyle.size ?? 18) / 18. Only real
|
|
@@ -4945,6 +5188,28 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4945
5188
|
renderText(obj) {
|
|
4946
5189
|
const background = this.canvasBackground;
|
|
4947
5190
|
const preferredInk = obj.color ?? this.theme.textColor ?? DEF_TEXT;
|
|
5191
|
+
const iconPath = obj.semanticKind === "icon" ? venueIconPath(obj.iconKey) : void 0;
|
|
5192
|
+
if (iconPath) {
|
|
5193
|
+
const scale = obj.fontSize / VENUE_ICON_VIEWBOX;
|
|
5194
|
+
const iconNode = new import_Path.Path({
|
|
5195
|
+
x: obj.position.x,
|
|
5196
|
+
y: obj.position.y,
|
|
5197
|
+
data: iconPath,
|
|
5198
|
+
rotation: obj.rotation,
|
|
5199
|
+
scaleX: scale,
|
|
5200
|
+
scaleY: scale,
|
|
5201
|
+
stroke: stateAwareBookableLabelInk(background, preferredInk),
|
|
5202
|
+
strokeWidth: VENUE_ICON_STROKE,
|
|
5203
|
+
lineCap: "round",
|
|
5204
|
+
lineJoin: "round",
|
|
5205
|
+
fillEnabled: false,
|
|
5206
|
+
listening: false,
|
|
5207
|
+
perfectDrawEnabled: false
|
|
5208
|
+
});
|
|
5209
|
+
this.iconNodeById.set(obj.id, { node: iconNode, fontSize: obj.fontSize });
|
|
5210
|
+
this.bgLayer.add(iconNode);
|
|
5211
|
+
return;
|
|
5212
|
+
}
|
|
4948
5213
|
const node = new import_Text.Text({
|
|
4949
5214
|
x: obj.position.x,
|
|
4950
5215
|
y: obj.position.y,
|
|
@@ -5112,7 +5377,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5112
5377
|
fill: color,
|
|
5113
5378
|
opacity: GA_FILL_OPACITY,
|
|
5114
5379
|
stroke: color,
|
|
5115
|
-
strokeWidth: 1.5
|
|
5380
|
+
strokeWidth: 1.5,
|
|
5381
|
+
cornerRadius: obj.cornerRadius
|
|
5116
5382
|
});
|
|
5117
5383
|
poly.setAttr("gaId", obj.id);
|
|
5118
5384
|
poly.on("click tap", (e) => {
|
|
@@ -5324,20 +5590,33 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5324
5590
|
sec.outlinePoly.shadowBlur(4 + raw * 12);
|
|
5325
5591
|
sec.outlinePoly.shadowOpacity(0.25 + raw * 0.45);
|
|
5326
5592
|
}
|
|
5327
|
-
/** Recompute a section's
|
|
5593
|
+
/** Recompute a section's availability shading + retained availability text. */
|
|
5328
5594
|
refreshSectionFill(sec) {
|
|
5329
5595
|
sec.blockPoly.fill(this.sectionBlockFill(sec));
|
|
5330
|
-
sec.subLabel.text(
|
|
5596
|
+
sec.subLabel.text(
|
|
5597
|
+
this.sectionAvailabilityState(sec) === "sold-out" ? t("map.soldOut") : t("map.seatsLeft", { count: sec.free })
|
|
5598
|
+
);
|
|
5331
5599
|
sec.subLabel.offsetX(sec.subLabel.width() / 2);
|
|
5332
5600
|
}
|
|
5333
5601
|
/** True when a section/zone is currently in the `closed` event-state. */
|
|
5334
5602
|
isSectionClosed(sec) {
|
|
5335
5603
|
return this.closedSections.has(sec.id) || this.closedSections.has(sec.logicalId) || sec.zone != null && this.closedSections.has(sec.zone);
|
|
5336
5604
|
}
|
|
5337
|
-
/**
|
|
5605
|
+
/** Resolve the four-bucket overview availability state for a section (OV-69).
|
|
5606
|
+
* `closed` (operator) outranks live availability; the availability buckets
|
|
5607
|
+
* only apply to seated sections (GA-only shells have no seat capacity here). */
|
|
5608
|
+
sectionAvailabilityState(sec) {
|
|
5609
|
+
if (this.isSectionClosed(sec)) return "closed";
|
|
5610
|
+
if (sec.total <= 0) return "normal";
|
|
5611
|
+
if (sec.free <= 0) return "sold-out";
|
|
5612
|
+
if (sec.free <= sec.total * SECTION_NEARLY_GONE_RATIO) return "nearly-gone";
|
|
5613
|
+
return "normal";
|
|
5614
|
+
}
|
|
5615
|
+
/** Overview shells stay neutral except for the bounded availability shading
|
|
5616
|
+
* (nearly-gone / sold-out) and the operator `closed` slab — never category
|
|
5617
|
+
* or price paint, which is deferred to section focus/seat detail. */
|
|
5338
5618
|
sectionBlockFill(sec) {
|
|
5339
|
-
|
|
5340
|
-
return this.isSectionClosed(sec) ? darken(fill, 0.12) : fill;
|
|
5619
|
+
return overviewStateFill(overviewPalette(this.canvasBackground), this.sectionAvailabilityState(sec));
|
|
5341
5620
|
}
|
|
5342
5621
|
/**
|
|
5343
5622
|
* Zone rung: one giant screen-constant label per zone (+ optional "FROM $n"),
|
|
@@ -6343,10 +6622,9 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6343
6622
|
};
|
|
6344
6623
|
});
|
|
6345
6624
|
const palette = overviewPalette(this.canvasBackground);
|
|
6346
|
-
const neutralSectionFills =
|
|
6347
|
-
palette.
|
|
6348
|
-
|
|
6349
|
-
]);
|
|
6625
|
+
const neutralSectionFills = new Set(
|
|
6626
|
+
["normal", "nearly-gone", "sold-out", "closed"].map((state) => overviewStateFill(palette, state).toLowerCase())
|
|
6627
|
+
);
|
|
6350
6628
|
const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);
|
|
6351
6629
|
return {
|
|
6352
6630
|
viewport,
|
|
@@ -6570,6 +6848,63 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6570
6848
|
const gaOverviewHidden = objectId != null && (kind === "ga-label" || kind === "ga-capacity") && this.gaById.get(objectId)?.sectionId != null && effectiveScale < CACHE_THRESHOLD;
|
|
6571
6849
|
node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));
|
|
6572
6850
|
}
|
|
6851
|
+
for (const { node, fontSize } of this.iconNodeById.values()) {
|
|
6852
|
+
node.visible(isBookableLabelLegibleAtScale(fontSize, effectiveScale));
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
/** OV-45(a): resolve authored row-letter labels for the buyer/preview map, in
|
|
6856
|
+
* world space, matching the Designer's placement contract (start/end/both/none
|
|
6857
|
+
* preset, a free-drag `position` that wins over the preset, rotation, and
|
|
6858
|
+
* labelStyle colour/size fed through the same auto-contrast guard). Segmented
|
|
6859
|
+
* rows keep their own logical-label handling and are resolved by their owner. */
|
|
6860
|
+
buildRowLabelPlan(view) {
|
|
6861
|
+
this.rowLabelPlan = [];
|
|
6862
|
+
const background = this.theme.background ?? "#0e1117";
|
|
6863
|
+
const seatsByRow = /* @__PURE__ */ new Map();
|
|
6864
|
+
for (const seat of this.seats) {
|
|
6865
|
+
if (seat.kind === "booth") continue;
|
|
6866
|
+
const key = seat.logicalRowId ?? seat.rowId;
|
|
6867
|
+
(seatsByRow.get(key) ?? seatsByRow.set(key, []).get(key)).push(seat);
|
|
6868
|
+
}
|
|
6869
|
+
const seatOrder = (seat) => seat.logicalSeatIndex ?? Number(seat.id.split(":").pop() ?? 0);
|
|
6870
|
+
for (const obj of view.objects) {
|
|
6871
|
+
if (obj.type !== "row") continue;
|
|
6872
|
+
if (obj.segmentedRow && obj.segmentedRow.componentIndex !== 0) continue;
|
|
6873
|
+
const presentation = obj.segmentedRow?.labelPresentation ?? obj.labelPresentation;
|
|
6874
|
+
if (presentation?.visible === false || presentation?.positionPreset === "none") continue;
|
|
6875
|
+
const key = obj.segmentedRow ? obj.segmentedRow.groupId : obj.id;
|
|
6876
|
+
const seats = (seatsByRow.get(key) ?? []).slice().sort((a, b) => seatOrder(a) - seatOrder(b));
|
|
6877
|
+
if (!seats.length) continue;
|
|
6878
|
+
const first = seats[0];
|
|
6879
|
+
const last = seats[seats.length - 1];
|
|
6880
|
+
const labelStyle = presentation?.labelStyle;
|
|
6881
|
+
const ink = stateAwareBookableLabelInk(
|
|
6882
|
+
background,
|
|
6883
|
+
labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? "#e6e9f0"
|
|
6884
|
+
);
|
|
6885
|
+
const fontSize = labelStyle?.size ?? 12;
|
|
6886
|
+
const rotation = presentation?.rotation ?? 0;
|
|
6887
|
+
const text = obj.segmentedRow?.displayLabel ?? obj.displayLabel ?? obj.label;
|
|
6888
|
+
const opacity = this.objectFilteredOut(obj) ? 0.15 : 1;
|
|
6889
|
+
const push = (x, y) => this.rowLabelPlan.push({ text, x, y, rotation, fontSize, ink, opacity });
|
|
6890
|
+
if (presentation?.position) {
|
|
6891
|
+
push(presentation.position.x, presentation.position.y);
|
|
6892
|
+
continue;
|
|
6893
|
+
}
|
|
6894
|
+
const radians = obj.rotation * Math.PI / 180;
|
|
6895
|
+
const along = { x: Math.cos(radians), y: Math.sin(radians) };
|
|
6896
|
+
const gap = this.seatR + 12;
|
|
6897
|
+
const preset = presentation?.positionPreset ?? "start";
|
|
6898
|
+
if (preset === "start" || preset === "both") push(first.x - along.x * gap, first.y - along.y * gap);
|
|
6899
|
+
if (preset === "end" || preset === "both") push(last.x + along.x * gap, last.y + along.y * gap);
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
/** Row labels never carry status; the buyer just dims them under the same
|
|
6903
|
+
* category/price filters that dim their seats. */
|
|
6904
|
+
objectFilteredOut(obj) {
|
|
6905
|
+
const key = obj.categoryKey;
|
|
6906
|
+
if (!key) return false;
|
|
6907
|
+
return Boolean(this.categoryHighlight && key !== this.categoryHighlight || this.categoryFilter && !this.categoryFilter.has(key));
|
|
6573
6908
|
}
|
|
6574
6909
|
updateLabels() {
|
|
6575
6910
|
const effectiveScale = this.effScale();
|
|
@@ -6663,6 +6998,30 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6663
6998
|
this.seatLabelById.set(seat.id, t2);
|
|
6664
6999
|
if (++count >= MAX_LABELS) break;
|
|
6665
7000
|
}
|
|
7001
|
+
for (const rl of this.rowLabelPlan) {
|
|
7002
|
+
const screen = this.worldToScreen({ x: rl.x, y: rl.y });
|
|
7003
|
+
if (screen.x < -40 || screen.x > this.stage.width() + 40 || screen.y < -40 || screen.y > this.stage.height() + 40) continue;
|
|
7004
|
+
const t2 = new import_Text.Text({
|
|
7005
|
+
x: rl.x,
|
|
7006
|
+
y: rl.y,
|
|
7007
|
+
text: rl.text,
|
|
7008
|
+
fontSize: rl.fontSize,
|
|
7009
|
+
fontStyle: "700",
|
|
7010
|
+
fontFamily: this.labelFont(),
|
|
7011
|
+
fill: rl.ink,
|
|
7012
|
+
rotation: rl.rotation,
|
|
7013
|
+
opacity: rl.opacity,
|
|
7014
|
+
shadowColor: "#05070c",
|
|
7015
|
+
shadowBlur: rl.ink.toLowerCase() === "#ffffff" ? 5 : 0,
|
|
7016
|
+
shadowOpacity: rl.ink.toLowerCase() === "#ffffff" ? 0.8 : 0,
|
|
7017
|
+
shadowForStrokeEnabled: false,
|
|
7018
|
+
listening: false,
|
|
7019
|
+
perfectDrawEnabled: false
|
|
7020
|
+
});
|
|
7021
|
+
t2.offsetX(t2.width() / 2);
|
|
7022
|
+
t2.offsetY(t2.height() / 2);
|
|
7023
|
+
this.labelGroup.add(t2);
|
|
7024
|
+
}
|
|
6666
7025
|
if (this.isoT > 0 && this.viewMode !== "perspective") this.applyUprightLabels();
|
|
6667
7026
|
this.overlayLayer.batchDraw();
|
|
6668
7027
|
}
|
|
@@ -7909,7 +8268,7 @@ var PickerController = class {
|
|
|
7909
8268
|
const color = sec.color ?? zone?.color ?? categories[0]?.color ?? "#6e7bff";
|
|
7910
8269
|
return {
|
|
7911
8270
|
id,
|
|
7912
|
-
label: sec.label,
|
|
8271
|
+
label: sec.displayLabel ?? sec.label,
|
|
7913
8272
|
zoneLabel: zone?.label ?? "",
|
|
7914
8273
|
...sec.entrance && sec.entrance.trim() ? { entrance: sec.entrance.trim() } : {},
|
|
7915
8274
|
color,
|