@seatlayer/core 0.26.0 → 0.28.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 +496 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -2
- package/dist/index.d.ts +79 -2
- package/dist/index.js +493 -42
- 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.js
CHANGED
|
@@ -1034,7 +1034,30 @@ function isBookableLabelLegibleAtScale(fontSize, effectiveScale) {
|
|
|
1034
1034
|
return fontSize * effectiveScale >= MIN_VISIBLE_BOOKABLE_LABEL_PX;
|
|
1035
1035
|
}
|
|
1036
1036
|
var ACCESS_GLYPH_VIEWBOX = 24;
|
|
1037
|
-
var
|
|
1037
|
+
var ACCESS_TYPE_GLYPH_PATHS = {
|
|
1038
|
+
// ISO-style wheelchair: seated figure (head + L-shaped body) over a ring wheel.
|
|
1039
|
+
wheelchair: "M7.8 4.5a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0zM8 7L10.5 7L10.5 15L8 15ZM8 12.5L18 12.5L18 15L8 15ZM16 15L18 15L18 18L16 18ZM5.5 16a5.5 5.5 0 1 0 11 0a5.5 5.5 0 1 0 -11 0zM8 16a3 3 0 1 1 6 0a3 3 0 1 1 -6 0z",
|
|
1040
|
+
// Companion: two overlapping head-and-shoulders figures (seat + a guest).
|
|
1041
|
+
companion: "M5.5 6.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0zM4.5 18.5L6 11.5L11 11.5L12.5 18.5ZM12.5 7.5a3 3 0 1 0 6 0a3 3 0 1 0 -6 0zM11.5 19L13 12.5L18 12.5L19.5 19Z",
|
|
1042
|
+
// Semi-ambulatory: walking figure leaning on a cane at its right side.
|
|
1043
|
+
"semi-ambulatory": "M8.3 3.8a2.2 2.2 0 1 0 4.4 0a2.2 2.2 0 1 0 -4.4 0zM9 6.2L12 6.6L11 13.5L8.6 13L9 6.2ZM8.6 13L11 13L9.5 21L7 21ZM10.4 13L12.6 13L13.6 21L11.2 21ZM11.2 7.2L14 8L14.6 9.6L11.9 8.9ZM14.4 6.8L15.9 6.8L16.4 21L14.8 21Z",
|
|
1044
|
+
// Hearing: a bold ear silhouette (assistive listening).
|
|
1045
|
+
hearing: "M15.5 3.5C9 2.2 5.5 6 5.5 11.5C5.5 16 8 19.5 10.5 21C13.2 22.6 16.4 20.8 15.4 18C14.8 16.4 12.9 16.1 13 14C13.1 11.9 15.8 11.4 15.8 8.5C15.8 5.4 13 4 15.5 3.5Z",
|
|
1046
|
+
// CART captions: a rounded caption bubble with two bold caption bars cut out.
|
|
1047
|
+
cart: "M5.5 6L18.5 6a2.5 2.5 0 0 1 2.5 2.5L21 15.5a2.5 2.5 0 0 1 -2.5 2.5L11 18L7 20.5L7.5 18L5.5 18a2.5 2.5 0 0 1 -2.5 -2.5L3 8.5a2.5 2.5 0 0 1 2.5 -2.5zM6.5 11L17.5 11L17.5 12.6L6.5 12.6zM6.5 14L17.5 14L17.5 15.6L6.5 15.6z",
|
|
1048
|
+
// Sign language: a raised open hand (palm with four fingers and a thumb).
|
|
1049
|
+
"sign-language": "M7 11L17 11L17 18a2 2 0 0 1 -2 2L9 20a2 2 0 0 1 -2 -2zM7.6 5L9.4 5L9.4 12L7.6 12zM9.9 3.5L11.7 3.5L11.7 12L9.9 12zM12.3 3.5L14.1 3.5L14.1 12L12.3 12zM14.6 5L16.4 5L16.4 12L14.6 12zM7.2 12.5L5 10.2L6.4 8.9L8.6 11.2Z",
|
|
1050
|
+
// Plus-size: a broad-shouldered wide figure.
|
|
1051
|
+
"plus-size": "M9.4 4.3a2.6 2.6 0 1 0 5.2 0a2.6 2.6 0 1 0 -5.2 0zM5 20L4 13C4 10.5 7 9.5 12 9.5C17 9.5 20 10.5 20 13L19 20Z",
|
|
1052
|
+
// Lift-up armrest: a chair side-profile with an up arrow over the armrest.
|
|
1053
|
+
"lift-armrest": "M5 6L8 6L8 19L5 19zM5 16L18 16L18 19L5 19zM8 12L17 12L17 14.5L8 14.5zM14 7L16 7L16 12L14 12zM12 7L18 7L15 3Z"
|
|
1054
|
+
};
|
|
1055
|
+
var ACCESS_GLYPH_PATH = ACCESS_TYPE_GLYPH_PATHS.wheelchair;
|
|
1056
|
+
function accessGlyphPath(accessibility) {
|
|
1057
|
+
if (!accessibility?.length) return null;
|
|
1058
|
+
const primary = accessibility.includes("wheelchair") ? "wheelchair" : accessibility[0];
|
|
1059
|
+
return ACCESS_TYPE_GLYPH_PATHS[primary] ?? null;
|
|
1060
|
+
}
|
|
1038
1061
|
function bookableMarkerLabel(publicLabel) {
|
|
1039
1062
|
return /-(\d{1,5})$/.exec(publicLabel)?.[1] ?? publicLabel;
|
|
1040
1063
|
}
|
|
@@ -1547,6 +1570,187 @@ function buyerBackgroundImage(owner) {
|
|
|
1547
1570
|
return background?.url && !background.assetId ? background : void 0;
|
|
1548
1571
|
}
|
|
1549
1572
|
|
|
1573
|
+
// src/core/icons.ts
|
|
1574
|
+
var VENUE_ICON_VIEWBOX = 24;
|
|
1575
|
+
var VENUE_ICON_STROKE = 2;
|
|
1576
|
+
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";
|
|
1577
|
+
var VENUE_ICONS = [
|
|
1578
|
+
// ---- Facilities --------------------------------------------------------
|
|
1579
|
+
{
|
|
1580
|
+
key: "restroom-men",
|
|
1581
|
+
label: "Men's restroom",
|
|
1582
|
+
group: "facilities",
|
|
1583
|
+
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"
|
|
1584
|
+
},
|
|
1585
|
+
{
|
|
1586
|
+
key: "restroom-women",
|
|
1587
|
+
label: "Women's restroom",
|
|
1588
|
+
group: "facilities",
|
|
1589
|
+
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"
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
key: "restroom-accessible",
|
|
1593
|
+
label: "Accessible restroom",
|
|
1594
|
+
group: "facilities",
|
|
1595
|
+
path: WHEELCHAIR
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
key: "first-aid",
|
|
1599
|
+
label: "First aid",
|
|
1600
|
+
group: "facilities",
|
|
1601
|
+
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"
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
key: "coat-check",
|
|
1605
|
+
label: "Coat check",
|
|
1606
|
+
group: "facilities",
|
|
1607
|
+
path: "M12 6a2 2 0 0 1 0-4 2 2 0 0 1 1.6 3.2L21 13H3l8.4-7.8 M3 13h18"
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
key: "atm",
|
|
1611
|
+
label: "ATM / cash",
|
|
1612
|
+
group: "facilities",
|
|
1613
|
+
path: "M2 6h20v12H2V6Z M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0 M6 9h.01 M18 15h.01"
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
key: "info",
|
|
1617
|
+
label: "Info point",
|
|
1618
|
+
group: "facilities",
|
|
1619
|
+
path: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18 M12 11v5 M12 8h.01"
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
key: "lost-found",
|
|
1623
|
+
label: "Lost & found",
|
|
1624
|
+
group: "facilities",
|
|
1625
|
+
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"
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
key: "restrooms",
|
|
1629
|
+
label: "Restrooms",
|
|
1630
|
+
group: "facilities",
|
|
1631
|
+
path: "M6 3h12a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M9 18v-3.5a3 3 0 0 1 6 0V18"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
key: "charging",
|
|
1635
|
+
label: "Charging point",
|
|
1636
|
+
group: "facilities",
|
|
1637
|
+
path: "M3 8h13v8H3V8Z M16 10h3v4h-3 M9.6 9l-2 3.5h2.5l-1.5 3"
|
|
1638
|
+
},
|
|
1639
|
+
{
|
|
1640
|
+
key: "smoking",
|
|
1641
|
+
label: "Smoking area",
|
|
1642
|
+
group: "facilities",
|
|
1643
|
+
path: "M2 15h13v3H2v-3Z M18 16h2 M19 8c0 1 1 1.5 1 2.5S19 12 19 13"
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
key: "no-smoking",
|
|
1647
|
+
label: "No smoking",
|
|
1648
|
+
group: "facilities",
|
|
1649
|
+
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"
|
|
1650
|
+
},
|
|
1651
|
+
// ---- Food & drink ------------------------------------------------------
|
|
1652
|
+
{
|
|
1653
|
+
key: "food",
|
|
1654
|
+
label: "Food",
|
|
1655
|
+
group: "food-drink",
|
|
1656
|
+
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"
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
key: "bar",
|
|
1660
|
+
label: "Bar",
|
|
1661
|
+
group: "food-drink",
|
|
1662
|
+
path: "M4 5h16l-8 8-8-8Z M12 13v6 M8 20h8"
|
|
1663
|
+
},
|
|
1664
|
+
{
|
|
1665
|
+
key: "coffee",
|
|
1666
|
+
label: "Caf\xE9 / coffee",
|
|
1667
|
+
group: "food-drink",
|
|
1668
|
+
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"
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
key: "water",
|
|
1672
|
+
label: "Water / drinks",
|
|
1673
|
+
group: "food-drink",
|
|
1674
|
+
path: "M12 22a7 7 0 0 1-7-7c0-5 7-12 7-12s7 7 7 12a7 7 0 0 1-7 7Z"
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
key: "merch",
|
|
1678
|
+
label: "Merch / shop",
|
|
1679
|
+
group: "food-drink",
|
|
1680
|
+
path: "M6 8h12l-1 12H7L6 8Z M9 8V6a3 3 0 0 1 6 0v2"
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
key: "screen",
|
|
1684
|
+
label: "Screen",
|
|
1685
|
+
group: "facilities",
|
|
1686
|
+
path: "M3 4h18v12H3V4Z M9 20h6 M12 16v4 M10 8l4 2-4 2V8Z"
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
key: "sound-booth",
|
|
1690
|
+
label: "Sound booth",
|
|
1691
|
+
group: "facilities",
|
|
1692
|
+
path: "M6 4v16 M6 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4 M12 4v16 M12 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4 M18 4v16 M18 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4"
|
|
1693
|
+
},
|
|
1694
|
+
// ---- Getting around ----------------------------------------------------
|
|
1695
|
+
{
|
|
1696
|
+
key: "entrance",
|
|
1697
|
+
label: "Entrance",
|
|
1698
|
+
group: "navigation",
|
|
1699
|
+
path: "M14 3h5a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1h-5 M3 12h11 M10 8l4 4-4 4"
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
key: "exit",
|
|
1703
|
+
label: "Exit",
|
|
1704
|
+
group: "navigation",
|
|
1705
|
+
path: "M10 3H5a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h5 M14 12h7 M17 8l4 4-4 4"
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
key: "emergency-exit",
|
|
1709
|
+
label: "Emergency exit",
|
|
1710
|
+
group: "navigation",
|
|
1711
|
+
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"
|
|
1712
|
+
},
|
|
1713
|
+
{
|
|
1714
|
+
key: "stairs",
|
|
1715
|
+
label: "Stairs",
|
|
1716
|
+
group: "navigation",
|
|
1717
|
+
path: "M3 20v-4h4v-4h4v-4h4V4h5"
|
|
1718
|
+
},
|
|
1719
|
+
{
|
|
1720
|
+
key: "elevator",
|
|
1721
|
+
label: "Elevator",
|
|
1722
|
+
group: "navigation",
|
|
1723
|
+
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"
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
key: "parking",
|
|
1727
|
+
label: "Parking",
|
|
1728
|
+
group: "navigation",
|
|
1729
|
+
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"
|
|
1730
|
+
},
|
|
1731
|
+
// ---- Accessibility -----------------------------------------------------
|
|
1732
|
+
{
|
|
1733
|
+
key: "wheelchair",
|
|
1734
|
+
label: "Wheelchair access",
|
|
1735
|
+
group: "accessibility",
|
|
1736
|
+
path: WHEELCHAIR
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
key: "hearing",
|
|
1740
|
+
label: "Hearing assistance",
|
|
1741
|
+
group: "accessibility",
|
|
1742
|
+
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"
|
|
1743
|
+
}
|
|
1744
|
+
];
|
|
1745
|
+
var BY_KEY = new Map(VENUE_ICONS.map((icon) => [icon.key, icon]));
|
|
1746
|
+
function venueIcon(key) {
|
|
1747
|
+
return key ? BY_KEY.get(key) : void 0;
|
|
1748
|
+
}
|
|
1749
|
+
function venueIconPath(key) {
|
|
1750
|
+
return venueIcon(key)?.path;
|
|
1751
|
+
}
|
|
1752
|
+
var VENUE_ICON_KEYS = VENUE_ICONS.map((icon) => icon.key);
|
|
1753
|
+
|
|
1550
1754
|
// src/core/spatialIndex.ts
|
|
1551
1755
|
var DEFAULT_SEAT_RADIUS = 9;
|
|
1552
1756
|
function halfExtents(shape) {
|
|
@@ -1884,6 +2088,7 @@ var en = {
|
|
|
1884
2088
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
1885
2089
|
"map.aria": "Seating map. Use arrow keys to move between seats, Enter to select.",
|
|
1886
2090
|
"map.seatsLeft": "{count} LEFT",
|
|
2091
|
+
"map.soldOut": "SOLD OUT",
|
|
1887
2092
|
"map.fromPrice": "FROM {price}",
|
|
1888
2093
|
"map.statusHeld": "On hold",
|
|
1889
2094
|
"map.statusTaken": "Taken",
|
|
@@ -1891,7 +2096,7 @@ var en = {
|
|
|
1891
2096
|
"picker.floor": "Floor",
|
|
1892
2097
|
"picker.zoomLevel": "Zoom level",
|
|
1893
2098
|
"picker.rungTip.zones": "Venue overview \u2014 groups of sections such as North Stand or VIP",
|
|
1894
|
-
"picker.rungTip.sections": "Section blocks \u2014
|
|
2099
|
+
"picker.rungTip.sections": "Section blocks \u2014 sold-out and nearly-gone sections shade to show availability at a glance",
|
|
1895
2100
|
"picker.rungTip.seats": "Individual seats \u2014 blocks melt into dots",
|
|
1896
2101
|
"picker.rungLabel.zones": "ZONES",
|
|
1897
2102
|
"picker.rungLabel.sections": "SECTIONS",
|
|
@@ -2092,6 +2297,22 @@ function overviewPalette(canvasBackground) {
|
|
|
2092
2297
|
focalStroke: DARK_OVERVIEW_FOCAL_STROKE
|
|
2093
2298
|
};
|
|
2094
2299
|
}
|
|
2300
|
+
var SECTION_NEARLY_GONE_RATIO = 0.1;
|
|
2301
|
+
function overviewStateFill(palette, state) {
|
|
2302
|
+
const base = palette.sectionFill;
|
|
2303
|
+
const soldOut = desaturate(darken(base, 0.2), 0.85);
|
|
2304
|
+
switch (state) {
|
|
2305
|
+
case "closed":
|
|
2306
|
+
return darken(base, 0.12);
|
|
2307
|
+
case "sold-out":
|
|
2308
|
+
return soldOut;
|
|
2309
|
+
case "nearly-gone":
|
|
2310
|
+
return lerpColor(base, soldOut, 0.4);
|
|
2311
|
+
case "normal":
|
|
2312
|
+
default:
|
|
2313
|
+
return base;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2095
2316
|
var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
2096
2317
|
function seatIdOf(target) {
|
|
2097
2318
|
const n = target;
|
|
@@ -2114,6 +2335,13 @@ function darken(hex, amt) {
|
|
|
2114
2335
|
const mix = (c) => Math.round(c * (1 - amt));
|
|
2115
2336
|
return `#${(1 << 24 | mix(n >> 16 & 255) << 16 | mix(n >> 8 & 255) << 8 | mix(n & 255)).toString(16).slice(1)}`;
|
|
2116
2337
|
}
|
|
2338
|
+
function desaturate(hex, amt) {
|
|
2339
|
+
const rgb2 = hexToRgb(hex);
|
|
2340
|
+
if (!rgb2) return hex;
|
|
2341
|
+
const [r, g, b] = rgb2;
|
|
2342
|
+
const grey = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
2343
|
+
return toHex(r + (grey - r) * amt, g + (grey - g) * amt, b + (grey - b) * amt);
|
|
2344
|
+
}
|
|
2117
2345
|
function polyBounds(pts) {
|
|
2118
2346
|
let minX = Infinity;
|
|
2119
2347
|
let minY = Infinity;
|
|
@@ -2177,18 +2405,36 @@ function polygonLabelCandidates(outer, holes, preferred) {
|
|
|
2177
2405
|
}
|
|
2178
2406
|
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));
|
|
2179
2407
|
}
|
|
2408
|
+
function roundedPolygonSubpath(context, points, radius) {
|
|
2409
|
+
const n = points.length;
|
|
2410
|
+
const start = { x: (points[n - 1].x + points[0].x) / 2, y: (points[n - 1].y + points[0].y) / 2 };
|
|
2411
|
+
context.moveTo(start.x, start.y);
|
|
2412
|
+
for (let i = 0; i < n; i += 1) {
|
|
2413
|
+
const curr = points[i];
|
|
2414
|
+
const next = points[(i + 1) % n];
|
|
2415
|
+
const prev = points[(i - 1 + n) % n];
|
|
2416
|
+
const rMax = Math.min(
|
|
2417
|
+
Math.hypot(curr.x - prev.x, curr.y - prev.y) / 2,
|
|
2418
|
+
Math.hypot(next.x - curr.x, next.y - curr.y) / 2
|
|
2419
|
+
);
|
|
2420
|
+
context.arcTo(curr.x, curr.y, next.x, next.y, Math.max(0, Math.min(radius, rMax)));
|
|
2421
|
+
}
|
|
2422
|
+
context.closePath();
|
|
2423
|
+
}
|
|
2180
2424
|
function polygonWithHolesShape(outer, holes, attrs, outerPath) {
|
|
2181
2425
|
const signedArea = (points) => points.reduce((sum, point, index) => {
|
|
2182
2426
|
const next = points[(index + 1) % points.length];
|
|
2183
2427
|
return sum + point.x * next.y - next.x * point.y;
|
|
2184
2428
|
}, 0);
|
|
2185
2429
|
const outerClockwise = signedArea(outer) > 0;
|
|
2430
|
+
const cornerRadius = attrs.cornerRadius && attrs.cornerRadius > 0 ? attrs.cornerRadius : 0;
|
|
2186
2431
|
return new Shape({
|
|
2187
2432
|
...attrs,
|
|
2188
2433
|
sceneFunc(context, shape) {
|
|
2189
2434
|
context.beginPath();
|
|
2190
2435
|
const polygonPath = (points) => {
|
|
2191
2436
|
if (!points.length) return;
|
|
2437
|
+
if (cornerRadius > 0 && points.length >= 3) return roundedPolygonSubpath(context, points, cornerRadius);
|
|
2192
2438
|
context.moveTo(points[0].x, points[0].y);
|
|
2193
2439
|
for (let index = 1; index < points.length; index += 1) context.lineTo(points[index].x, points[index].y);
|
|
2194
2440
|
context.closePath();
|
|
@@ -2323,6 +2569,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2323
2569
|
this.accessGlyphById = /* @__PURE__ */ new Map();
|
|
2324
2570
|
/** Authored free-text nodes obey the same rendered-size visibility floor. */
|
|
2325
2571
|
this.freeTextById = /* @__PURE__ */ new Map();
|
|
2572
|
+
/** Vector venue-icon Path nodes + authored size; obey the free-text size floor. */
|
|
2573
|
+
this.iconNodeById = /* @__PURE__ */ new Map();
|
|
2326
2574
|
/** Stage/rink landmarks retain a readable screen-space caption at overview. */
|
|
2327
2575
|
this.primaryFocalLabels = /* @__PURE__ */ new Map();
|
|
2328
2576
|
/** GA paint and text share price/highlight filter state. */
|
|
@@ -2336,6 +2584,12 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2336
2584
|
this.effSelection = DEF_SELECTION;
|
|
2337
2585
|
/** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */
|
|
2338
2586
|
this.colorblind = false;
|
|
2587
|
+
/** Stable per-category-KEY colorblind hue (OV-46) — order-independent. */
|
|
2588
|
+
this.cbHueByKey = /* @__PURE__ */ new Map();
|
|
2589
|
+
/** OV-45(a): authored row-letter labels for the buyer/preview map, resolved in
|
|
2590
|
+
* world space (matching seat labels) and honouring each row's labelPresentation
|
|
2591
|
+
* (position/rotation/visibility/style). Painted at the seats LOD rung. */
|
|
2592
|
+
this.rowLabelPlan = [];
|
|
2339
2593
|
/** Category order from the doc — the stable index into the CB palette. */
|
|
2340
2594
|
this.catOrder = [];
|
|
2341
2595
|
this.selection = /* @__PURE__ */ new Set();
|
|
@@ -2705,6 +2959,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2705
2959
|
this.accessRingById.clear();
|
|
2706
2960
|
this.accessGlyphById.clear();
|
|
2707
2961
|
this.freeTextById.clear();
|
|
2962
|
+
this.iconNodeById.clear();
|
|
2708
2963
|
this.primaryFocalLabels.clear();
|
|
2709
2964
|
this.gaById.clear();
|
|
2710
2965
|
for (const marker of this.selectionMarkers.values()) marker.destroy();
|
|
@@ -2759,13 +3014,22 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2759
3014
|
this.catColor.clear();
|
|
2760
3015
|
this.catPrice.clear();
|
|
2761
3016
|
this.catOrder = doc.categories.map((c) => c.key);
|
|
3017
|
+
this.cbHueByKey.clear();
|
|
3018
|
+
[...this.catOrder].sort().forEach((key, i) => {
|
|
3019
|
+
this.cbHueByKey.set(key, CB_PALETTE[i % CB_PALETTE.length]);
|
|
3020
|
+
});
|
|
2762
3021
|
for (const c of doc.categories) {
|
|
2763
3022
|
this.catColor.set(c.key, c.color);
|
|
2764
3023
|
if (typeof c.price === "number") this.catPrice.set(c.key, c.price);
|
|
2765
3024
|
}
|
|
2766
3025
|
for (const obj of view.objects) {
|
|
2767
3026
|
if (obj.type === "booth") {
|
|
2768
|
-
this.boothDims.set(obj.id, {
|
|
3027
|
+
this.boothDims.set(obj.id, {
|
|
3028
|
+
width: obj.width,
|
|
3029
|
+
height: obj.height,
|
|
3030
|
+
rotation: obj.rotation,
|
|
3031
|
+
...obj.points && obj.points.length >= 3 ? { points: obj.points.map((p) => ({ x: p.x, y: p.y })) } : {}
|
|
3032
|
+
});
|
|
2769
3033
|
}
|
|
2770
3034
|
}
|
|
2771
3035
|
this.seats = expandChart(view, {
|
|
@@ -2785,6 +3049,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2785
3049
|
this.unsectionedSeatGroup = new Group({ listening: true });
|
|
2786
3050
|
this.seatLayer.add(this.unsectionedSeatGroup);
|
|
2787
3051
|
this.renderSeats();
|
|
3052
|
+
this.buildRowLabelPlan(view);
|
|
2788
3053
|
this.overlayLayer.add(this.labelGroup);
|
|
2789
3054
|
this.overlayLayer.add(this.fgDecorGroup);
|
|
2790
3055
|
this.overlayLayer.add(this.hoverRing);
|
|
@@ -4084,7 +4349,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4084
4349
|
this.accessRingById.set(seat.id, ring);
|
|
4085
4350
|
target.add(ring);
|
|
4086
4351
|
}
|
|
4087
|
-
if (seat.accessibility
|
|
4352
|
+
if (accessGlyphPath(seat.accessibility ?? [])) {
|
|
4088
4353
|
const glyph = this.buildAccessGlyph(seat, typeof c.fill() === "string" ? c.fill() : "");
|
|
4089
4354
|
this.accessGlyphById.set(seat.id, glyph);
|
|
4090
4355
|
target.add(glyph);
|
|
@@ -4096,25 +4361,42 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4096
4361
|
renderBoothUnit(seat) {
|
|
4097
4362
|
const target = this.seatContainer(seat.id);
|
|
4098
4363
|
const dims = this.boothDims.get(seat.rowId) ?? { width: 40, height: 30, rotation: 0 };
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4364
|
+
let labelX = seat.x;
|
|
4365
|
+
let labelY = seat.y;
|
|
4366
|
+
let node;
|
|
4367
|
+
if (dims.points && dims.points.length >= 3) {
|
|
4368
|
+
node = new Line({
|
|
4369
|
+
x: seat.x,
|
|
4370
|
+
y: seat.y,
|
|
4371
|
+
points: dims.points.flatMap((p) => [p.x, p.y]),
|
|
4372
|
+
closed: true,
|
|
4373
|
+
perfectDrawEnabled: false,
|
|
4374
|
+
shadowForStrokeEnabled: false,
|
|
4375
|
+
hitStrokeWidth: 0
|
|
4376
|
+
});
|
|
4377
|
+
labelX = seat.x + dims.points.reduce((a, p) => a + p.x, 0) / dims.points.length;
|
|
4378
|
+
labelY = seat.y + dims.points.reduce((a, p) => a + p.y, 0) / dims.points.length;
|
|
4379
|
+
} else {
|
|
4380
|
+
node = new Rect({
|
|
4381
|
+
x: seat.x,
|
|
4382
|
+
y: seat.y,
|
|
4383
|
+
width: dims.width,
|
|
4384
|
+
height: dims.height,
|
|
4385
|
+
offsetX: dims.width / 2,
|
|
4386
|
+
offsetY: dims.height / 2,
|
|
4387
|
+
rotation: dims.rotation,
|
|
4388
|
+
cornerRadius: 4,
|
|
4389
|
+
perfectDrawEnabled: false,
|
|
4390
|
+
shadowForStrokeEnabled: false,
|
|
4391
|
+
hitStrokeWidth: 0
|
|
4392
|
+
});
|
|
4393
|
+
}
|
|
4394
|
+
node.setAttr("seatId", seat.id);
|
|
4395
|
+
this.circleById.set(seat.id, node);
|
|
4396
|
+
target.add(node);
|
|
4115
4397
|
const t2 = new Text({
|
|
4116
|
-
x:
|
|
4117
|
-
y:
|
|
4398
|
+
x: labelX,
|
|
4399
|
+
y: labelY,
|
|
4118
4400
|
text: seat.displayLabel ?? seat.label,
|
|
4119
4401
|
fontSize: BOOTH_LABEL_FONT_SIZE,
|
|
4120
4402
|
fontStyle: "600",
|
|
@@ -4129,7 +4411,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4129
4411
|
this.hasBoothText = true;
|
|
4130
4412
|
this.boothLabelById.set(seat.id, t2);
|
|
4131
4413
|
target.add(t2);
|
|
4132
|
-
this.paintSeat(
|
|
4414
|
+
this.paintSeat(node, seat.id);
|
|
4133
4415
|
}
|
|
4134
4416
|
/**
|
|
4135
4417
|
* Build the centred accessibility glyph for a seat. Sized relative to the seat
|
|
@@ -4141,7 +4423,9 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4141
4423
|
return new Path({
|
|
4142
4424
|
x: seat.x,
|
|
4143
4425
|
y: seat.y,
|
|
4144
|
-
|
|
4426
|
+
// Non-null: buildAccessGlyph is only called for seats the gate confirmed
|
|
4427
|
+
// resolve to a primary-accommodation glyph.
|
|
4428
|
+
data: accessGlyphPath(seat.accessibility ?? []) ?? "",
|
|
4145
4429
|
offsetX: ACCESS_GLYPH_VIEWBOX / 2,
|
|
4146
4430
|
offsetY: ACCESS_GLYPH_VIEWBOX / 2,
|
|
4147
4431
|
scaleX: k,
|
|
@@ -4197,8 +4481,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4197
4481
|
/** The category's display color — Okabe-Ito hue when colorblind-safe is on. */
|
|
4198
4482
|
seatBaseColor(categoryKey) {
|
|
4199
4483
|
if (!this.colorblind) return this.catColor.get(categoryKey) ?? "#6e7bff";
|
|
4200
|
-
|
|
4201
|
-
return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];
|
|
4484
|
+
return this.cbHueByKey.get(categoryKey) ?? CB_PALETTE[0];
|
|
4202
4485
|
}
|
|
4203
4486
|
/** Per-seat authored label size relative to the neutral default (1 = default),
|
|
4204
4487
|
* mirroring the section convention (labelStyle.size ?? 18) / 18. Only real
|
|
@@ -4669,6 +4952,28 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4669
4952
|
renderText(obj) {
|
|
4670
4953
|
const background = this.canvasBackground;
|
|
4671
4954
|
const preferredInk = obj.color ?? this.theme.textColor ?? DEF_TEXT;
|
|
4955
|
+
const iconPath = obj.semanticKind === "icon" ? venueIconPath(obj.iconKey) : void 0;
|
|
4956
|
+
if (iconPath) {
|
|
4957
|
+
const scale = obj.fontSize / VENUE_ICON_VIEWBOX;
|
|
4958
|
+
const iconNode = new Path({
|
|
4959
|
+
x: obj.position.x,
|
|
4960
|
+
y: obj.position.y,
|
|
4961
|
+
data: iconPath,
|
|
4962
|
+
rotation: obj.rotation,
|
|
4963
|
+
scaleX: scale,
|
|
4964
|
+
scaleY: scale,
|
|
4965
|
+
stroke: stateAwareBookableLabelInk(background, preferredInk),
|
|
4966
|
+
strokeWidth: VENUE_ICON_STROKE,
|
|
4967
|
+
lineCap: "round",
|
|
4968
|
+
lineJoin: "round",
|
|
4969
|
+
fillEnabled: false,
|
|
4970
|
+
listening: false,
|
|
4971
|
+
perfectDrawEnabled: false
|
|
4972
|
+
});
|
|
4973
|
+
this.iconNodeById.set(obj.id, { node: iconNode, fontSize: obj.fontSize });
|
|
4974
|
+
this.bgLayer.add(iconNode);
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4672
4977
|
const node = new Text({
|
|
4673
4978
|
x: obj.position.x,
|
|
4674
4979
|
y: obj.position.y,
|
|
@@ -4836,7 +5141,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4836
5141
|
fill: color,
|
|
4837
5142
|
opacity: GA_FILL_OPACITY,
|
|
4838
5143
|
stroke: color,
|
|
4839
|
-
strokeWidth: 1.5
|
|
5144
|
+
strokeWidth: 1.5,
|
|
5145
|
+
cornerRadius: obj.cornerRadius
|
|
4840
5146
|
});
|
|
4841
5147
|
poly.setAttr("gaId", obj.id);
|
|
4842
5148
|
poly.on("click tap", (e) => {
|
|
@@ -5048,20 +5354,33 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
5048
5354
|
sec.outlinePoly.shadowBlur(4 + raw * 12);
|
|
5049
5355
|
sec.outlinePoly.shadowOpacity(0.25 + raw * 0.45);
|
|
5050
5356
|
}
|
|
5051
|
-
/** Recompute a section's
|
|
5357
|
+
/** Recompute a section's availability shading + retained availability text. */
|
|
5052
5358
|
refreshSectionFill(sec) {
|
|
5053
5359
|
sec.blockPoly.fill(this.sectionBlockFill(sec));
|
|
5054
|
-
sec.subLabel.text(
|
|
5360
|
+
sec.subLabel.text(
|
|
5361
|
+
this.sectionAvailabilityState(sec) === "sold-out" ? t("map.soldOut") : t("map.seatsLeft", { count: sec.free })
|
|
5362
|
+
);
|
|
5055
5363
|
sec.subLabel.offsetX(sec.subLabel.width() / 2);
|
|
5056
5364
|
}
|
|
5057
5365
|
/** True when a section/zone is currently in the `closed` event-state. */
|
|
5058
5366
|
isSectionClosed(sec) {
|
|
5059
5367
|
return this.closedSections.has(sec.id) || this.closedSections.has(sec.logicalId) || sec.zone != null && this.closedSections.has(sec.zone);
|
|
5060
5368
|
}
|
|
5061
|
-
/**
|
|
5369
|
+
/** Resolve the four-bucket overview availability state for a section (OV-69).
|
|
5370
|
+
* `closed` (operator) outranks live availability; the availability buckets
|
|
5371
|
+
* only apply to seated sections (GA-only shells have no seat capacity here). */
|
|
5372
|
+
sectionAvailabilityState(sec) {
|
|
5373
|
+
if (this.isSectionClosed(sec)) return "closed";
|
|
5374
|
+
if (sec.total <= 0) return "normal";
|
|
5375
|
+
if (sec.free <= 0) return "sold-out";
|
|
5376
|
+
if (sec.free <= sec.total * SECTION_NEARLY_GONE_RATIO) return "nearly-gone";
|
|
5377
|
+
return "normal";
|
|
5378
|
+
}
|
|
5379
|
+
/** Overview shells stay neutral except for the bounded availability shading
|
|
5380
|
+
* (nearly-gone / sold-out) and the operator `closed` slab — never category
|
|
5381
|
+
* or price paint, which is deferred to section focus/seat detail. */
|
|
5062
5382
|
sectionBlockFill(sec) {
|
|
5063
|
-
|
|
5064
|
-
return this.isSectionClosed(sec) ? darken(fill, 0.12) : fill;
|
|
5383
|
+
return overviewStateFill(overviewPalette(this.canvasBackground), this.sectionAvailabilityState(sec));
|
|
5065
5384
|
}
|
|
5066
5385
|
/**
|
|
5067
5386
|
* Zone rung: one giant screen-constant label per zone (+ optional "FROM $n"),
|
|
@@ -6067,10 +6386,9 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6067
6386
|
};
|
|
6068
6387
|
});
|
|
6069
6388
|
const palette = overviewPalette(this.canvasBackground);
|
|
6070
|
-
const neutralSectionFills =
|
|
6071
|
-
palette.
|
|
6072
|
-
|
|
6073
|
-
]);
|
|
6389
|
+
const neutralSectionFills = new Set(
|
|
6390
|
+
["normal", "nearly-gone", "sold-out", "closed"].map((state) => overviewStateFill(palette, state).toLowerCase())
|
|
6391
|
+
);
|
|
6074
6392
|
const visibleSectionShells = this.sections.filter((section) => section.blockPoly.opacity() > 0.05);
|
|
6075
6393
|
return {
|
|
6076
6394
|
viewport,
|
|
@@ -6240,7 +6558,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6240
6558
|
if (shouldCache && !this.cached) {
|
|
6241
6559
|
this.cacheSeatLayer();
|
|
6242
6560
|
} else if (!shouldCache && (this.cached || !this.seatLayer.listening())) {
|
|
6243
|
-
if (this.cached) this.
|
|
6561
|
+
if (this.cached) this.releaseSeatLayerBitmap();
|
|
6244
6562
|
this.seatLayer.listening(true);
|
|
6245
6563
|
this.cached = false;
|
|
6246
6564
|
this.seatLayer.batchDraw();
|
|
@@ -6260,6 +6578,28 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6260
6578
|
this.rebuildSeatCache();
|
|
6261
6579
|
this.seatLayer.batchDraw();
|
|
6262
6580
|
}
|
|
6581
|
+
/**
|
|
6582
|
+
* Drop the seat-layer overview bitmap while PRESERVING every descendant's
|
|
6583
|
+
* cached local transform + clientRect.
|
|
6584
|
+
*
|
|
6585
|
+
* Konva's public `Layer.clearCache()` releases the bitmap and then runs a deep
|
|
6586
|
+
* `_clearSelfAndDescendantCache()` that clears those caches on all 14k seat
|
|
6587
|
+
* nodes. Recomputing them on the single frame the melt first reveals a section's
|
|
6588
|
+
* live seats is the ~480ms first-drill stall (OV-80). A camera glide only marks
|
|
6589
|
+
* each seat's ABSOLUTE_TRANSFORM dirty (recomputed lazily at ordinary pan cost)
|
|
6590
|
+
* and never moves a seat's LOCAL transform, so the local caches stay valid —
|
|
6591
|
+
* keeping them lets the first melt paint at pan cost, matching the ~17ms of
|
|
6592
|
+
* every subsequent glide on the same section. Any edit that actually moves a
|
|
6593
|
+
* seat invalidates its own transform cache through the attr setter, so only
|
|
6594
|
+
* still-valid caches survive here.
|
|
6595
|
+
*/
|
|
6596
|
+
releaseSeatLayerBitmap() {
|
|
6597
|
+
const layer = this.seatLayer;
|
|
6598
|
+
const entry = layer._cache.get("canvas");
|
|
6599
|
+
if (!entry) return;
|
|
6600
|
+
Konva.Util.releaseCanvas(entry.scene._canvas, entry.filter._canvas, entry.hit._canvas);
|
|
6601
|
+
layer._cache.delete("canvas");
|
|
6602
|
+
}
|
|
6263
6603
|
/**
|
|
6264
6604
|
* SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the
|
|
6265
6605
|
* ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore
|
|
@@ -6278,7 +6618,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6278
6618
|
if (this.effScale() < CACHE_THRESHOLD) {
|
|
6279
6619
|
this.rebuildSeatCache();
|
|
6280
6620
|
} else if (this.cached) {
|
|
6281
|
-
this.
|
|
6621
|
+
this.releaseSeatLayerBitmap();
|
|
6282
6622
|
this.seatLayer.listening(true);
|
|
6283
6623
|
this.cached = false;
|
|
6284
6624
|
}
|
|
@@ -6294,6 +6634,63 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6294
6634
|
const gaOverviewHidden = objectId != null && (kind === "ga-label" || kind === "ga-capacity") && this.gaById.get(objectId)?.sectionId != null && effectiveScale < CACHE_THRESHOLD;
|
|
6295
6635
|
node.visible(!gaDimmed && !gaOverviewHidden && isBookableLabelLegibleAtScale(node.fontSize(), effectiveScale));
|
|
6296
6636
|
}
|
|
6637
|
+
for (const { node, fontSize } of this.iconNodeById.values()) {
|
|
6638
|
+
node.visible(isBookableLabelLegibleAtScale(fontSize, effectiveScale));
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
/** OV-45(a): resolve authored row-letter labels for the buyer/preview map, in
|
|
6642
|
+
* world space, matching the Designer's placement contract (start/end/both/none
|
|
6643
|
+
* preset, a free-drag `position` that wins over the preset, rotation, and
|
|
6644
|
+
* labelStyle colour/size fed through the same auto-contrast guard). Segmented
|
|
6645
|
+
* rows keep their own logical-label handling and are resolved by their owner. */
|
|
6646
|
+
buildRowLabelPlan(view) {
|
|
6647
|
+
this.rowLabelPlan = [];
|
|
6648
|
+
const background = this.theme.background ?? "#0e1117";
|
|
6649
|
+
const seatsByRow = /* @__PURE__ */ new Map();
|
|
6650
|
+
for (const seat of this.seats) {
|
|
6651
|
+
if (seat.kind === "booth") continue;
|
|
6652
|
+
const key = seat.logicalRowId ?? seat.rowId;
|
|
6653
|
+
(seatsByRow.get(key) ?? seatsByRow.set(key, []).get(key)).push(seat);
|
|
6654
|
+
}
|
|
6655
|
+
const seatOrder = (seat) => seat.logicalSeatIndex ?? Number(seat.id.split(":").pop() ?? 0);
|
|
6656
|
+
for (const obj of view.objects) {
|
|
6657
|
+
if (obj.type !== "row") continue;
|
|
6658
|
+
if (obj.segmentedRow && obj.segmentedRow.componentIndex !== 0) continue;
|
|
6659
|
+
const presentation = obj.segmentedRow?.labelPresentation ?? obj.labelPresentation;
|
|
6660
|
+
if (presentation?.visible === false || presentation?.positionPreset === "none") continue;
|
|
6661
|
+
const key = obj.segmentedRow ? obj.segmentedRow.groupId : obj.id;
|
|
6662
|
+
const seats = (seatsByRow.get(key) ?? []).slice().sort((a, b) => seatOrder(a) - seatOrder(b));
|
|
6663
|
+
if (!seats.length) continue;
|
|
6664
|
+
const first = seats[0];
|
|
6665
|
+
const last = seats[seats.length - 1];
|
|
6666
|
+
const labelStyle = presentation?.labelStyle;
|
|
6667
|
+
const ink = stateAwareBookableLabelInk(
|
|
6668
|
+
background,
|
|
6669
|
+
labelStyle?.color ?? this.theme.rowLabelColor ?? this.theme.textColor ?? "#e6e9f0"
|
|
6670
|
+
);
|
|
6671
|
+
const fontSize = labelStyle?.size ?? 12;
|
|
6672
|
+
const rotation = presentation?.rotation ?? 0;
|
|
6673
|
+
const text = obj.segmentedRow?.displayLabel ?? obj.displayLabel ?? obj.label;
|
|
6674
|
+
const opacity = this.objectFilteredOut(obj) ? 0.15 : 1;
|
|
6675
|
+
const push = (x, y) => this.rowLabelPlan.push({ text, x, y, rotation, fontSize, ink, opacity });
|
|
6676
|
+
if (presentation?.position) {
|
|
6677
|
+
push(presentation.position.x, presentation.position.y);
|
|
6678
|
+
continue;
|
|
6679
|
+
}
|
|
6680
|
+
const radians = obj.rotation * Math.PI / 180;
|
|
6681
|
+
const along = { x: Math.cos(radians), y: Math.sin(radians) };
|
|
6682
|
+
const gap = this.seatR + 12;
|
|
6683
|
+
const preset = presentation?.positionPreset ?? "start";
|
|
6684
|
+
if (preset === "start" || preset === "both") push(first.x - along.x * gap, first.y - along.y * gap);
|
|
6685
|
+
if (preset === "end" || preset === "both") push(last.x + along.x * gap, last.y + along.y * gap);
|
|
6686
|
+
}
|
|
6687
|
+
}
|
|
6688
|
+
/** Row labels never carry status; the buyer just dims them under the same
|
|
6689
|
+
* category/price filters that dim their seats. */
|
|
6690
|
+
objectFilteredOut(obj) {
|
|
6691
|
+
const key = obj.categoryKey;
|
|
6692
|
+
if (!key) return false;
|
|
6693
|
+
return Boolean(this.categoryHighlight && key !== this.categoryHighlight || this.categoryFilter && !this.categoryFilter.has(key));
|
|
6297
6694
|
}
|
|
6298
6695
|
updateLabels() {
|
|
6299
6696
|
const effectiveScale = this.effScale();
|
|
@@ -6387,6 +6784,30 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
6387
6784
|
this.seatLabelById.set(seat.id, t2);
|
|
6388
6785
|
if (++count >= MAX_LABELS) break;
|
|
6389
6786
|
}
|
|
6787
|
+
for (const rl of this.rowLabelPlan) {
|
|
6788
|
+
const screen = this.worldToScreen({ x: rl.x, y: rl.y });
|
|
6789
|
+
if (screen.x < -40 || screen.x > this.stage.width() + 40 || screen.y < -40 || screen.y > this.stage.height() + 40) continue;
|
|
6790
|
+
const t2 = new Text({
|
|
6791
|
+
x: rl.x,
|
|
6792
|
+
y: rl.y,
|
|
6793
|
+
text: rl.text,
|
|
6794
|
+
fontSize: rl.fontSize,
|
|
6795
|
+
fontStyle: "700",
|
|
6796
|
+
fontFamily: this.labelFont(),
|
|
6797
|
+
fill: rl.ink,
|
|
6798
|
+
rotation: rl.rotation,
|
|
6799
|
+
opacity: rl.opacity,
|
|
6800
|
+
shadowColor: "#05070c",
|
|
6801
|
+
shadowBlur: rl.ink.toLowerCase() === "#ffffff" ? 5 : 0,
|
|
6802
|
+
shadowOpacity: rl.ink.toLowerCase() === "#ffffff" ? 0.8 : 0,
|
|
6803
|
+
shadowForStrokeEnabled: false,
|
|
6804
|
+
listening: false,
|
|
6805
|
+
perfectDrawEnabled: false
|
|
6806
|
+
});
|
|
6807
|
+
t2.offsetX(t2.width() / 2);
|
|
6808
|
+
t2.offsetY(t2.height() / 2);
|
|
6809
|
+
this.labelGroup.add(t2);
|
|
6810
|
+
}
|
|
6390
6811
|
if (this.isoT > 0 && this.viewMode !== "perspective") this.applyUprightLabels();
|
|
6391
6812
|
this.overlayLayer.batchDraw();
|
|
6392
6813
|
}
|
|
@@ -6718,6 +7139,36 @@ var PickerController = class {
|
|
|
6718
7139
|
const group = this.groupedTableBySeatId.get(seatIdOrLabel) ?? this.groupedTablesByLabel.get(seatIdOrLabel);
|
|
6719
7140
|
return group ? this.toTableSeat(group) : null;
|
|
6720
7141
|
}
|
|
7142
|
+
/**
|
|
7143
|
+
* Buyer-facing name + type word for a checkout line item, resolved from the
|
|
7144
|
+
* SAME author overrides the tray/tooltip already render. `label` stays the
|
|
7145
|
+
* booking identity; a host builds its own order summary from `displayLabel`/
|
|
7146
|
+
* `displayType` so the buyer sees the designer's copy, not the internal label.
|
|
7147
|
+
* Absent fields = no override (host falls back to `label`).
|
|
7148
|
+
*/
|
|
7149
|
+
lineItemDisplay(item) {
|
|
7150
|
+
if (item.objectType === "ga") {
|
|
7151
|
+
const doc = this.visibleDoc();
|
|
7152
|
+
const area = gaAreasOf(doc).find((candidate) => candidate.id === item.objectId);
|
|
7153
|
+
return {
|
|
7154
|
+
...area?.displayLabel ? { displayLabel: area.displayLabel } : {},
|
|
7155
|
+
...area?.displayType ? { displayType: area.displayType } : {}
|
|
7156
|
+
};
|
|
7157
|
+
}
|
|
7158
|
+
if (item.objectType === "table") {
|
|
7159
|
+
const group = this.groupedTablesByLabel.get(item.label);
|
|
7160
|
+
return {
|
|
7161
|
+
...group?.displayLabel && group.displayLabel !== group.label ? { displayLabel: group.displayLabel } : {},
|
|
7162
|
+
...group?.displayType ? { displayType: group.displayType } : {}
|
|
7163
|
+
};
|
|
7164
|
+
}
|
|
7165
|
+
const seat = this.labelToSeat.get(item.label);
|
|
7166
|
+
const context = seat ? this.seatContext.get(seat.id) : void 0;
|
|
7167
|
+
return {
|
|
7168
|
+
...seat?.displayLabel ? { displayLabel: seat.displayLabel } : {},
|
|
7169
|
+
...context?.displayType ? { displayType: context.displayType } : {}
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
6721
7172
|
/** Fetch chart, build label maps, mount the renderer, seed statuses, go live. */
|
|
6722
7173
|
async render(host) {
|
|
6723
7174
|
if (this.renderer) return null;
|
|
@@ -7633,7 +8084,7 @@ var PickerController = class {
|
|
|
7633
8084
|
const color = sec.color ?? zone?.color ?? categories[0]?.color ?? "#6e7bff";
|
|
7634
8085
|
return {
|
|
7635
8086
|
id,
|
|
7636
|
-
label: sec.label,
|
|
8087
|
+
label: sec.displayLabel ?? sec.label,
|
|
7637
8088
|
zoneLabel: zone?.label ?? "",
|
|
7638
8089
|
...sec.entrance && sec.entrance.trim() ? { entrance: sec.entrance.trim() } : {},
|
|
7639
8090
|
color,
|
|
@@ -8235,9 +8686,9 @@ function generateSeatThumb(seat, focalPoint, _neighborSeats) {
|
|
|
8235
8686
|
|
|
8236
8687
|
// src/i18n/bundles.ts
|
|
8237
8688
|
var LOADERS = {
|
|
8238
|
-
es: () => import("./es-
|
|
8239
|
-
de: () => import("./de-
|
|
8240
|
-
fr: () => import("./fr-
|
|
8689
|
+
es: () => import("./es-6TJS2L7S.js").then((m) => ({ default: m.es })),
|
|
8690
|
+
de: () => import("./de-UHAOVDS3.js").then((m) => ({ default: m.de })),
|
|
8691
|
+
fr: () => import("./fr-MMSY7FPE.js").then((m) => ({ default: m.fr }))
|
|
8241
8692
|
};
|
|
8242
8693
|
var loaded = /* @__PURE__ */ new Set(["en"]);
|
|
8243
8694
|
async function loadLocale(code) {
|