@expofp/floorplan 3.44.8 → 3.45.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.
Files changed (131) hide show
  1. package/dist/browser/{Button-C1iQgU3z.js → Button-6lV64H09.js} +5 -5
  2. package/dist/browser/{CookieConsent-Dv1LCPG3.js → CookieConsent-k11VHxoM.js} +7 -7
  3. package/dist/browser/{Debug-DPy0A0cw.js → Debug-DbfbGWb0.js} +7 -7
  4. package/dist/browser/{DebugTools-Dp8d4gPZ.js → DebugTools-BjHOBi_k.js} +6 -6
  5. package/dist/browser/{Demo-CHH4a7sZ.js → Demo-CrFjKybB.js} +9 -9
  6. package/dist/browser/{Free-BidfuRjG.js → Free-4IN6GHrY.js} +10 -10
  7. package/dist/browser/{GalleryContainer-7IYWWKkK.js → GalleryContainer-BWd-8Nhp.js} +11 -11
  8. package/dist/browser/{GpsLoader-CrO61Fpj.js → GpsLoader-C43ADyfU.js} +13 -13
  9. package/dist/browser/{KioskStore-BE_V60tp.js → KioskStore-0xBjJ9AG.js} +14 -20
  10. package/dist/browser/{LayerStore-BM7GOQ3J.js → LayerStore-BifpIwHB.js} +3726 -3220
  11. package/dist/browser/{MaplibreAdapter-DmrCTw3Q.js → MaplibreAdapter-CxETR3-R.js} +2517 -2517
  12. package/dist/browser/{ModalContainer-DqsSRv60.js → ModalContainer-IvkrtwT_.js} +10 -10
  13. package/dist/browser/{PermissionNotice--Vn_MkaQ.js → PermissionNotice-C4Nu1dPO.js} +6 -6
  14. package/dist/browser/{RouteStore-D7G9YROM.js → RouteStore-ltbgXRLP.js} +28 -28
  15. package/dist/browser/{SetKioskMode-CMndo5d3.js → SetKioskMode-BWzFzO_Q.js} +12 -12
  16. package/dist/browser/{ShowKiosk-CUiprdS9.js → ShowKiosk-BYOTTOrX.js} +10 -10
  17. package/dist/browser/{UIState-D0GHKRf4.js → UIState-BG-A7rPb.js} +230 -230
  18. package/dist/browser/{ViewerMenuPanel-B7corw44.js → ViewerMenuPanel-DscD3jCY.js} +11 -11
  19. package/dist/browser/{add-debug-secret-listener-uMLIuPW5.js → add-debug-secret-listener-qgQOxLV_.js} +1 -1
  20. package/dist/browser/{adopt-global-settings-BVVdz-YX.js → adopt-global-settings-CB1YrOJs.js} +9 -9
  21. package/dist/browser/{boolean-editor-Dg3cfoLy.js → boolean-editor-DcFqYLg6.js} +9 -9
  22. package/dist/browser/{bootIntercom-7FTJ0piX.js → bootIntercom-DJEOZaFU.js} +2 -2
  23. package/dist/browser/bundle.json +87 -87
  24. package/dist/browser/{camera-events-DbYubA01.js → camera-events-BwP3bfY4.js} +1 -1
  25. package/dist/browser/{classnames-BryLpfgQ.js → classnames-C6CE8V3C.js} +2 -2
  26. package/dist/browser/{client-DnnJr0Ks.js → client-B42ooBdH.js} +5 -5
  27. package/dist/browser/{components-DHNMQbqJ.js → components-DelXq6ex.js} +461 -461
  28. package/dist/browser/{create-live-plan-BgCjK-Kh.js → create-live-plan-jO-YW94S.js} +263 -245
  29. package/dist/browser/{debug-context-BEABO7OL.js → debug-context-BFAUm0Rv.js} +5 -5
  30. package/dist/browser/{debug-overlay-Bv-C1rmT.js → debug-overlay-0pLu5_hz.js} +10 -10
  31. package/dist/browser/{debug-ui-FirQ0EQb.js → debug-ui-CPF3Fr0y.js} +6 -6
  32. package/dist/browser/{dist-sup8YcEL.js → dist-5MtJlmvC.js} +5 -5
  33. package/dist/browser/{dist-p14a9te8.js → dist-BImkgFoY.js} +6 -6
  34. package/dist/browser/{dist-DN5ATV5p.js → dist-D7lv86ly.js} +3 -3
  35. package/dist/browser/{efp-debug-init-DUPmVtYg.js → efp-debug-init-DBnQHIuj.js} +3 -3
  36. package/dist/browser/{enum-editor-g46R4Zq7.js → enum-editor-wagTer9Z.js} +4 -4
  37. package/dist/browser/{es5-D_WEVRPo.js → es5-ClZJZH3H.js} +2 -2
  38. package/dist/browser/{event-head-DBemDpob.js → event-head-Dvg64Dl9.js} +1 -1
  39. package/dist/browser/{event-not-found-m_QUX3nl.js → event-not-found-CmHnmais.js} +3 -3
  40. package/dist/browser/{event-scoped-cache-BpjbCC59.js → event-scoped-cache-blYstzYW.js} +2 -2
  41. package/dist/browser/{expofpUrl-CAOzqFzt.js → expofpUrl-D99TqyHD.js} +1 -1
  42. package/dist/browser/{exports-svWN4mLB.js → exports-BBJtyyI0.js} +1 -1
  43. package/dist/browser/{favicon-hR5BaEm4.js → favicon-Bac0ZnSB.js} +1 -1
  44. package/dist/browser/{fetch-retry.umd-DS-5XmpN.js → fetch-retry.umd-Dkr69k7z.js} +2 -2
  45. package/dist/browser/{flex-BAz1Zlx4.js → flex-2znF0sHW.js} +5 -5
  46. package/dist/browser/{floorplan.loader-DPHmWNvd.js → floorplan.loader-B2NptbPQ.js} +12 -12
  47. package/dist/browser/{floorplan.ready-clG372Lo.js → floorplan.ready-DTyG-lkM.js} +344 -335
  48. package/dist/browser/{freeBanner-D0nU1aT0.js → freeBanner-yyOqSdAy.js} +2 -2
  49. package/dist/browser/{fuse-DFf-hk6f.js → fuse-x_QTzSiL.js} +2 -2
  50. package/dist/browser/{i18n-CPJmxFQX.js → i18n-CLEztXjo.js} +6 -6
  51. package/dist/browser/index.js +17 -17
  52. package/dist/browser/{index.module-COSPv-bu.js → index.module-C9C4kJk7.js} +4 -4
  53. package/dist/browser/{init-ui-Cj38w8tb.js → init-ui-rxZzKF4X.js} +16 -16
  54. package/dist/browser/{integrateKiosk-Du5HThkw.js → integrateKiosk-DsU-d7uk.js} +5 -5
  55. package/dist/browser/{is-debug-CmeNjnvW.js → is-debug-Bnj4naYd.js} +4 -4
  56. package/dist/browser/{is-own-domain-z0V4JpKp.js → is-own-domain-DNjOZllq.js} +1 -1
  57. package/dist/browser/{is-webview-JHA9dtnx.js → is-webview-Drer0GOu.js} +1 -1
  58. package/dist/browser/{jsx-runtime-D-d_UIhH.js → jsx-runtime-DB8EwfzE.js} +2 -2
  59. package/dist/browser/{kiosk-mode-ZBMSIWbK.js → kiosk-mode-B89VL0oY.js} +3 -3
  60. package/dist/browser/{kiosk-record-Djd0ZbEF.js → kiosk-record-rnTon4Lp.js} +1 -1
  61. package/dist/browser/{kioskApi-CXqDoN71.js → kioskApi-opoHdUqq.js} +7 -7
  62. package/dist/browser/{lib-GyGKAKXf.js → lib-eiqwFHwk.js} +3 -3
  63. package/dist/browser/{loadImage-cnbZD9uN.js → loadImage-BS80HTUK.js} +1 -1
  64. package/dist/browser/{logDeviceInfo-BSf9sLzS.js → logDeviceInfo-BqSbYo5l.js} +9 -9
  65. package/dist/browser/{mobx-D3NQFhEq.js → mobx-9NGoPiek.js} +4 -4
  66. package/dist/browser/{mobx.module-CAKsDOYI.js → mobx.module-BP1vMHLz.js} +1 -1
  67. package/dist/browser/{optional-boolean-editor-IR9THgLK.js → optional-boolean-editor-D6hR19BE.js} +3 -3
  68. package/dist/browser/{optional-enum-editor-PRQn6yzK.js → optional-enum-editor-BQPM-fRt.js} +4 -4
  69. package/dist/browser/{optional-string-editor-bZCuZ1tn.js → optional-string-editor-DUXoDnXB.js} +4 -4
  70. package/dist/browser/{particles.min-CwWuVwyg.js → particles.min-CBeInmmW.js} +2 -2
  71. package/dist/browser/{react-DQVTc7xG.js → react-Dg88gKA7.js} +2 -2
  72. package/dist/browser/{react-dom-BsqqKfoG.js → react-dom-C3PpoQeD.js} +3 -3
  73. package/dist/browser/{rolldown-runtime-Cyn7iuGp.js → rolldown-runtime-C7pJ6q0h.js} +1 -1
  74. package/dist/browser/{scene-CqJCEbSr.js → scene-CV1XFwO9.js} +12 -12
  75. package/dist/browser/{scheduler-CVY86sNW.js → scheduler-D-EvNbvQ.js} +2 -2
  76. package/dist/browser/{select-Du3T8Mpj.js → select-CQPuihmE.js} +10 -10
  77. package/dist/browser/{settings-NB72PTux.js → settings-BBn9P5W0.js} +2 -2
  78. package/dist/browser/{settings-item-BIPeCHmD.js → settings-item-BOVedxqA.js} +6 -6
  79. package/dist/browser/{store-BvnDl4Sc.js → store-D73yMRu5.js} +2 -2
  80. package/dist/browser/{string-editor-o-TMbaK8.js → string-editor-Drmcb4Uw.js} +4 -4
  81. package/dist/browser/{text-field-BZ5346fV.js → text-field-CnzYOUfF.js} +5 -5
  82. package/dist/browser/{theme-CPcxdYz7.js → theme-B4d7ReQC.js} +8 -8
  83. package/dist/browser/{ui-CesJTtUW.js → ui-DQ22eDdk.js} +8 -8
  84. package/dist/browser/useManageTraffic-C-4Maw9l.js +1439 -0
  85. package/dist/browser/{useRenderTarget-DpLNpx1f.js → useRenderTarget-BaCkqntS.js} +4 -4
  86. package/dist/browser/{viewport-QrHclV_L.js → viewport-CcbGLmJI.js} +3 -3
  87. package/dist/browser/{wayfinding-v9-TVwHq.js → wayfinding-4TI6Xwmj.js} +416 -383
  88. package/dist/esm/components/Kiosk/KioskStore.d.ts +5 -0
  89. package/dist/esm/components/Kiosk/KioskStore.js +1 -1
  90. package/dist/esm/components/Map/drawing/config/TextFitter.d.ts +2 -2
  91. package/dist/esm/components/Map/drawing/config/TextFitter.js +1 -1
  92. package/dist/esm/components/Map/drawing/config/canvases.d.ts +90 -2
  93. package/dist/esm/components/Map/drawing/config/canvases.js +1 -1
  94. package/dist/esm/components/Map/drawing/config/config-all.js +1 -1
  95. package/dist/esm/components/Map/drawing/config/config-booth-badge.d.ts +3 -3
  96. package/dist/esm/components/Map/drawing/config/config-booth-bookmark.d.ts +1 -1
  97. package/dist/esm/components/Map/drawing/config/config-booth-bookmark.js +1 -1
  98. package/dist/esm/components/Map/drawing/config/config-booth-labels-special.d.ts +3 -4
  99. package/dist/esm/components/Map/drawing/config/config-booth-labels-special.js +2 -2
  100. package/dist/esm/components/Map/drawing/config/config-booth-labels.d.ts +2 -2
  101. package/dist/esm/components/Map/drawing/config/config-booth-labels.js +1 -1
  102. package/dist/esm/components/Map/drawing/config/config-markers.d.ts +17 -1
  103. package/dist/esm/components/Map/drawing/config/config-markers.js +1 -1
  104. package/dist/esm/components/Map/drawing/config/config-pins.d.ts +40 -0
  105. package/dist/esm/components/Map/drawing/config/config-pins.js +1 -0
  106. package/dist/esm/components/Map/drawing/config/pin-geometry.d.ts +65 -0
  107. package/dist/esm/components/Map/drawing/config/pin-geometry.js +1 -0
  108. package/dist/esm/components/Map/traffic/useBuildRoute.d.ts +1 -1
  109. package/dist/esm/components/Map/traffic/useBuildRoute.js +4 -4
  110. package/dist/esm/components/Map/traffic/useManageTraffic.js +1 -1
  111. package/dist/esm/engine/defs.d.ts +5 -0
  112. package/dist/esm/engine/defs.js +3 -3
  113. package/dist/esm/engine/update-def.d.ts +13 -1
  114. package/dist/esm/engine/update-def.js +1 -1
  115. package/dist/esm/services/url-dispatch.js +1 -1
  116. package/dist/esm/store/init/init-heatmap.d.ts +1 -1
  117. package/dist/esm/store/init/init-heatmap.js +1 -1
  118. package/dist/esm/store/search-buttons/SearchButtonsActions.d.ts +9 -0
  119. package/dist/esm/store/search-buttons/SearchButtonsActions.js +1 -1
  120. package/dist/esm/store/search-buttons/SearchButtonsStore.d.ts +15 -0
  121. package/dist/esm/store/search-buttons/SearchButtonsStore.js +1 -1
  122. package/dist/esm/test/store-harness.d.ts +13 -0
  123. package/dist/esm/test/store-harness.js +1 -1
  124. package/dist/esm/utils/dimming.js +1 -1
  125. package/dist/esm/wayfinding/adapters/canvasIconProvider.js +1 -1
  126. package/dist/esm/wayfinding/handlers/kioskHandler.js +1 -1
  127. package/dist/esm/wayfinding/handlers/yahHandler.js +1 -1
  128. package/package.json +10 -10
  129. package/dist/browser/dimming-B7lpw_UN.js +0 -1214
  130. package/dist/esm/engine/canvases.d.ts +0 -5
  131. package/dist/esm/engine/canvases.js +0 -1
@@ -43,6 +43,11 @@ declare class KioskStore {
43
43
  delayChange(cb: () => void): void;
44
44
  handleChange(event: SetKioskChangeEvent): void;
45
45
  initialPtScale?: number;
46
+ /**
47
+ * Records the pixel size the plan booted at in this session. Not written into the saved record
48
+ * here: `getCameraState` saves it together with `mapPtScale`, so the two always share a unit.
49
+ * @param ptscale - The plan's pixel size.
50
+ */
46
51
  setInitialPtScale(ptscale: number): void;
47
52
  handleClick(point: {
48
53
  x: number;
@@ -1 +1 @@
1
- import{__decorate as i}from"tslib";import{getConfig as C}from"@expofp/config";import{action as n,computed as k,observable as d,toJS as m,when as y}from"mobx";import{KIOSK_ENABLE_KEY as p}from"../../constants";import a from"../../store";import{areLayersEnabled as K}from"../../utils/areLayersEnabled";import{t as h}from"../../utils/i18n";import{isLocalStorageAvailable as S}from"../../utils/localStorage";import{mapCamera as f}from"../Map/camera";import{mapViewport as M}from"../Map/viewport";import{storedKioskMode as v}from"./kiosk-mode";import{getPtScaleZoomRatio as P,toFiniteNumber as u}from"./kiosk-record";import{updateKiosk as b}from"./kioskApi";import{getSavedKiosk as w,removeKiosk as F,saveKiosk as R}from"./SetKiosk";import{KIOSK_STORAGE_KEY as D}from"./SetKiosk/constants";const I=2e4;class s{constructor(){this.savedKiosk=null,this.statusMessages=[],this.statusMessageTimer=0,this.isResettingCamera=!1,this.isRestoringFraming=!1}get kiosk(){return a.uiState.kioskData}setKiosk(e){a.uiState.setKioskData(e)}getCameraState(){if(a.maplibreStore.showMaplibre){const t=a.maplibreStore.cameraPort?.getCameraState();return t?{mapCenterLng:t.lng,mapCenterLat:t.lat,mapZoom:t.zoom,mapBearingDegrees:t.bearing,mapPitchDegrees:t.pitch}:{}}const e=f()?.state();return e?{mapInitialPtScale:this.initialPtScale,mapPtScale:e.pixelSize,mapCenterX:e.center.x,mapCenterY:e.center.y,mapRollDegrees:e.roll,mapPitch:e.pitch}:{}}get hasUnsavedChanges(){const e=this.savedKiosk,t=m(this.kiosk);if(!t||!e)return!!t!=!!e;const o=Object.keys(e),r=Object.keys(t);if(o.length!==r.length)return!0;for(const l of o)if(!(l in t)||e[l]!==t[l])return!0;return!1}addStatusMessage(e){this.statusMessages=[{...e,id:Date.now()}],this.startCleanupMessages()}clearStatusMessages(){this.statusMessages=[]}startCleanupMessages(){clearTimeout(this.statusMessageTimer),this.statusMessageTimer=window.setTimeout(()=>this.clearStatusMessages(),1e3)}async resetCamera(){if(!this.isResettingCamera){this.isResettingCamera=!0;try{if(a.maplibreStore.showMaplibre&&await this.resetMaplibreCamera()){this.isRestoringFraming=!0;return}this.isRestoringFraming=await this.resetPlanCamera()}finally{this.isResettingCamera=!1}}}async resetMaplibreCamera(){const e=await this.waitForMaplibreCameraPort();if(!e)return!1;const t=this.kiosk;t?.z!=null&&a.fp.activateFloor({name:String(t.z)});const o=u(t?.mapCenterLng),r=u(t?.mapCenterLat),l=u(t?.mapZoom);return o===void 0||r===void 0||l===void 0?(e.resetPitch(),a.uiState.fitBounds(),!0):(e.applyCameraState({lng:o,lat:r,zoom:l,bearing:u(t?.mapBearingDegrees),pitch:u(t?.mapPitchDegrees)}),!0)}async waitForMaplibreCameraPort(){const{maplibreStore:e}=a;if(e.cameraPort)return e.cameraPort;try{await y(()=>!!e.cameraPort||!e.showMaplibre,{timeout:I})}catch{return null}return e.cameraPort}async resetPlanCamera(){const e=f();if(!e)return!1;const t=this.kiosk;await e.api.reset({pan:!0,zoom:!0,roll:!0,pitch:!0},{immediate:!0}),t?.z!=null&&a.fp.activateFloor({name:String(t.z)});const o=P(t);o!==void 0&&await e.api.zoomBy(o,{immediate:!0});const r=u(t?.mapCenterX),l=u(t?.mapCenterY);r!==void 0&&l!==void 0&&await e.api.panTo({x:r,y:l},{immediate:!0});const c=u(t?.mapRollDegrees);c!==void 0&&await e.api.rollTo(c,{immediate:!0});const g=u(t?.mapPitch);return g!==void 0&&await e.api.pitchTo(g,{immediate:!0}),!0}restoreData(){const e=w();this.savedKiosk=e??null,e&&(this.setKiosk(e),a.uiState.kiosk=!0)}handleSetupReady(){this.restoreData(),a.uiState.kiosk=!0,a.uiState.hideFreeOrDemo=!0,a.uiState.setForceDim(!0),a.searchStore.setSearchText(""),a.searchStore.setFocused(!1),this.resetCamera()}handleClose(){v(C())||(a.uiState.kiosk=!1),a.uiState.restoreUIScale(),this.setKiosk(null),a.uiState.setForceDim(!1),a.uiState.enableSetKioskMode(!1),a.searchStore.closeSearch()}handleDelete(){S&&localStorage.getItem(D)!==null&&localStorage.getItem(p)==="1"&&localStorage.removeItem(p),F(),this.savedKiosk=null,this.setKiosk(null),a.uiState.resetMapSettings(),a.uiState.resetUIScale(),this.addStatusMessage({variant:"success",title:h("Deleted")})}handleSave(){const e=M();if(!e)return;const t=m(this.kiosk);if(!t)return;const o=this.getCameraState(),r={...t,...o};if(!e.isVisible({x:r.x,y:r.y})){this.addStatusMessage({variant:"error",title:h("Kiosk not visible")});return}this.setKiosk(r),R(r),S&&localStorage.setItem(p,"1"),b(r,"https://app.expofp.com/"),a.uiState.setKioskUIScale(r.uiScale,!0),this.addStatusMessage({variant:"success",title:h("Saved")}),this.savedKiosk=r}delayChange(e){requestAnimationFrame(()=>e?.())}handleChange(e){const t=m(this.kiosk);t&&(Number.isFinite(e.angle)&&this.setKiosk({...t,heading:e.angle}),Number.isFinite(e.scale)&&(this.setKiosk({...t,uiScale:e.scale}),this.delayChange(()=>a.uiState.setKioskUIScale(e.scale,!1))),Number.isFinite(e.percent)&&this.setKiosk({...t,iconSizePercent:e.percent}))}setInitialPtScale(e){if(this.initialPtScale)return;this.initialPtScale=e;const t=m(this.kiosk);t&&this.setKiosk({...t,mapInitialPtScale:e})}handleClick(e){const t=m(this.kiosk),o=a.fp.getFloors(),r=K()?o.find(c=>c.active)?.name??null:null,l=a.uiState.uiScale;this.setKiosk({...t,x:e.x,y:e.y,z:r,uiScale:t?.uiScale||l,heading:t?.heading||0,iconSizePercent:t?.iconSizePercent||100,...this.getCameraState()})}handleNavigationChange(){const e=this.isRestoringFraming;this.isRestoringFraming=!1;const t=m(this.kiosk);if(!t)return;const o=this.getCameraState();this.setKiosk({...t,...o}),e&&this.savedKiosk&&(this.savedKiosk={...this.savedKiosk,...o})}}i([k({keepAlive:!0})],s.prototype,"kiosk",null),i([n],s.prototype,"setKiosk",null),i([d],s.prototype,"savedKiosk",void 0),i([k({keepAlive:!0})],s.prototype,"hasUnsavedChanges",null),i([d],s.prototype,"statusMessages",void 0),i([n],s.prototype,"addStatusMessage",null),i([n],s.prototype,"clearStatusMessages",null),i([n],s.prototype,"startCleanupMessages",null),i([n],s.prototype,"resetCamera",null),i([n],s.prototype,"restoreData",null),i([n],s.prototype,"handleSetupReady",null),i([n],s.prototype,"handleClose",null),i([n],s.prototype,"handleDelete",null),i([n],s.prototype,"handleSave",null),i([n],s.prototype,"handleChange",null),i([n],s.prototype,"setInitialPtScale",null),i([n],s.prototype,"handleClick",null),i([n],s.prototype,"handleNavigationChange",null);export default new s;
1
+ import{__decorate as i}from"tslib";import{getConfig as C}from"@expofp/config";import{action as n,computed as d,observable as S,toJS as m,when as y}from"mobx";import{KIOSK_ENABLE_KEY as p}from"../../constants";import a from"../../store";import{areLayersEnabled as K}from"../../utils/areLayersEnabled";import{t as h}from"../../utils/i18n";import{isLocalStorageAvailable as k}from"../../utils/localStorage";import{mapCamera as f}from"../Map/camera";import{mapViewport as M}from"../Map/viewport";import{storedKioskMode as v}from"./kiosk-mode";import{getPtScaleZoomRatio as P,toFiniteNumber as u}from"./kiosk-record";import{updateKiosk as b}from"./kioskApi";import{getSavedKiosk as w,removeKiosk as F,saveKiosk as R}from"./SetKiosk";import{KIOSK_STORAGE_KEY as D}from"./SetKiosk/constants";const z=2e4;class s{constructor(){this.savedKiosk=null,this.statusMessages=[],this.statusMessageTimer=0,this.isResettingCamera=!1,this.isRestoringFraming=!1}get kiosk(){return a.uiState.kioskData}setKiosk(e){a.uiState.setKioskData(e)}getCameraState(){if(a.maplibreStore.showMaplibre){const t=a.maplibreStore.cameraPort?.getCameraState();return t?{mapCenterLng:t.lng,mapCenterLat:t.lat,mapZoom:t.zoom,mapBearingDegrees:t.bearing,mapPitchDegrees:t.pitch}:{}}const e=f()?.state();return e?{mapInitialPtScale:this.initialPtScale,mapPtScale:e.pixelSize,mapCenterX:e.center.x,mapCenterY:e.center.y,mapRollDegrees:e.roll,mapPitch:e.pitch}:{}}get hasUnsavedChanges(){const e=this.savedKiosk,t=m(this.kiosk);if(!t||!e)return!!t!=!!e;const o=Object.keys(e),r=Object.keys(t);if(o.length!==r.length)return!0;for(const l of o)if(!(l in t)||e[l]!==t[l])return!0;return!1}addStatusMessage(e){this.statusMessages=[{...e,id:Date.now()}],this.startCleanupMessages()}clearStatusMessages(){this.statusMessages=[]}startCleanupMessages(){clearTimeout(this.statusMessageTimer),this.statusMessageTimer=window.setTimeout(()=>this.clearStatusMessages(),1e3)}async resetCamera(){if(!this.isResettingCamera){this.isResettingCamera=!0;try{if(a.maplibreStore.showMaplibre&&await this.resetMaplibreCamera()){this.isRestoringFraming=!0;return}this.isRestoringFraming=await this.resetPlanCamera()}finally{this.isResettingCamera=!1}}}async resetMaplibreCamera(){const e=await this.waitForMaplibreCameraPort();if(!e)return!1;const t=this.kiosk;t?.z!=null&&a.fp.activateFloor({name:String(t.z)});const o=u(t?.mapCenterLng),r=u(t?.mapCenterLat),l=u(t?.mapZoom);return o===void 0||r===void 0||l===void 0?(e.resetPitch(),a.uiState.fitBounds(),!0):(e.applyCameraState({lng:o,lat:r,zoom:l,bearing:u(t?.mapBearingDegrees),pitch:u(t?.mapPitchDegrees)}),!0)}async waitForMaplibreCameraPort(){const{maplibreStore:e}=a;if(e.cameraPort)return e.cameraPort;try{await y(()=>!!e.cameraPort||!e.showMaplibre,{timeout:z})}catch{return null}return e.cameraPort}async resetPlanCamera(){const e=f();if(!e)return!1;const t=this.kiosk;await e.api.reset({pan:!0,zoom:!0,roll:!0,pitch:!0},{immediate:!0}),t?.z!=null&&a.fp.activateFloor({name:String(t.z)});const o=P(t);o!==void 0&&await e.api.zoomBy(o,{immediate:!0});const r=u(t?.mapCenterX),l=u(t?.mapCenterY);r!==void 0&&l!==void 0&&await e.api.panTo({x:r,y:l},{immediate:!0});const c=u(t?.mapRollDegrees);c!==void 0&&await e.api.rollTo(c,{immediate:!0});const g=u(t?.mapPitch);return g!==void 0&&await e.api.pitchTo(g,{immediate:!0}),!0}restoreData(){const e=w();this.savedKiosk=e??null,e&&(this.setKiosk(e),a.uiState.kiosk=!0)}handleSetupReady(){this.restoreData(),a.uiState.kiosk=!0,a.uiState.hideFreeOrDemo=!0,a.uiState.setForceDim(!0),a.searchStore.setSearchText(""),a.searchStore.setFocused(!1),this.resetCamera()}handleClose(){v(C())||(a.uiState.kiosk=!1),a.uiState.restoreUIScale(),this.setKiosk(null),a.uiState.setForceDim(!1),a.uiState.enableSetKioskMode(!1),a.searchStore.closeSearch()}handleDelete(){k&&localStorage.getItem(D)!==null&&localStorage.getItem(p)==="1"&&localStorage.removeItem(p),F(),this.savedKiosk=null,this.setKiosk(null),a.uiState.resetMapSettings(),a.uiState.resetUIScale(),this.addStatusMessage({variant:"success",title:h("Deleted")})}handleSave(){const e=M();if(!e)return;const t=m(this.kiosk);if(!t)return;const o=this.getCameraState(),r={...t,...o};if(!e.isVisible({x:r.x,y:r.y})){this.addStatusMessage({variant:"error",title:h("Kiosk not visible")});return}this.setKiosk(r),R(r),k&&localStorage.setItem(p,"1"),b(r,"https://app.expofp.com/"),a.uiState.setKioskUIScale(r.uiScale,!0),this.addStatusMessage({variant:"success",title:h("Saved")}),this.savedKiosk=r}delayChange(e){requestAnimationFrame(()=>e?.())}handleChange(e){const t=m(this.kiosk);t&&(Number.isFinite(e.angle)&&this.setKiosk({...t,heading:e.angle}),Number.isFinite(e.scale)&&(this.setKiosk({...t,uiScale:e.scale}),this.delayChange(()=>a.uiState.setKioskUIScale(e.scale,!1))),Number.isFinite(e.percent)&&this.setKiosk({...t,iconSizePercent:e.percent}))}setInitialPtScale(e){this.initialPtScale||(this.initialPtScale=e)}handleClick(e){const t=m(this.kiosk),o=a.fp.getFloors(),r=K()?o.find(c=>c.active)?.name??null:null,l=a.uiState.uiScale;this.setKiosk({...t,x:e.x,y:e.y,z:r,uiScale:t?.uiScale||l,heading:t?.heading||0,iconSizePercent:t?.iconSizePercent||100,...this.getCameraState()})}handleNavigationChange(){const e=this.isRestoringFraming;this.isRestoringFraming=!1;const t=m(this.kiosk);if(!t)return;const o=this.getCameraState();this.setKiosk({...t,...o}),e&&this.savedKiosk&&(this.savedKiosk={...this.savedKiosk,...o})}}i([d({keepAlive:!0})],s.prototype,"kiosk",null),i([n],s.prototype,"setKiosk",null),i([S],s.prototype,"savedKiosk",void 0),i([d({keepAlive:!0})],s.prototype,"hasUnsavedChanges",null),i([S],s.prototype,"statusMessages",void 0),i([n],s.prototype,"addStatusMessage",null),i([n],s.prototype,"clearStatusMessages",null),i([n],s.prototype,"startCleanupMessages",null),i([n],s.prototype,"resetCamera",null),i([n],s.prototype,"restoreData",null),i([n],s.prototype,"handleSetupReady",null),i([n],s.prototype,"handleClose",null),i([n],s.prototype,"handleDelete",null),i([n],s.prototype,"handleSave",null),i([n],s.prototype,"handleChange",null),i([n],s.prototype,"setInitialPtScale",null),i([n],s.prototype,"handleClick",null),i([n],s.prototype,"handleNavigationChange",null);export default new s;
@@ -1,11 +1,11 @@
1
- import { FontSizeFactor } from '../../../../engine/defs';
1
+ import { type FontSizeFactor } from '../../../../engine/defs';
2
2
  export default class TextFitter {
3
3
  private readonly maxMultilineFontSize;
4
4
  private readonly baseFontSize;
5
5
  private readonly fontSizes;
6
6
  private readonly ctx;
7
7
  private readonly spaceWidth;
8
- constructor(fontFunc: (number: any) => string, fontSizes: number[], maxMultilineFontSize: number);
8
+ constructor(fontFunc: (fontSize: number) => string, fontSizes: number[], maxMultilineFontSize: number);
9
9
  getStepsForRect(text: string, width: number, height: number): FontSizeFactor[];
10
10
  }
11
11
  //# sourceMappingURL=TextFitter.d.ts.map
@@ -1 +1 @@
1
- const M=document.createElement("canvas").getContext("2d");export default class I{constructor(r,i,e){this.baseFontSize=this.maxMultilineFontSize=e,this.fontSizes=i,this.ctx=M,this.ctx.textAlign="center",this.ctx.textBaseline="alphabetic",this.ctx.font=r(this.baseFontSize),this.spaceWidth=this.ctx.measureText(" ").width}getStepsForRect(r,i,e){const t=r.split(/\s+/),c=t.map(o=>this.ctx.measureText(o).width),n=[];let s=1/0,h=0;for(const o of this.fontSizes){const d=o,l=o/this.baseFontSize,u=c.map(p=>p*l),f=this.spaceWidth*l,x=B(u,f,o>this.maxMultilineFontSize?1:1/0).filter(p=>p);for(let p=0;p<x.length;p++){const g=x[p],F=g,m=p+1,L=d*m,W=F/i,v=L/e,w=Math.max(v,W);if(w>s||m<h)continue;s=w,h=m;const z=y(g,m,u,f),S=H(z,u,f);if(!S)continue;const b=k(S,t);n.push({scaleFactor:w,value:o,lines:b,width:g})}}return n}}function B(a,r,i){const e=[];let t,c=1,n=1/0,s;for(;(s=T(n,a,r))&&s.length<=i;)c!==s.length&&(e[c-1]=t),c=s.length,t=Math.max(...s),n=t-1;return e[c-1]=t,e}function T(a,r,i){const e=[];let t,c=-1;function n(){c++,t=0}n();for(const s of r){const h=t+(t>0?i:0)+s;if(h>a){if(s>a)return null;n(),t=s}else t=h;e[c]=t}return e}function y(a,r,i,e){return t(r,0);function t(n,s){const h=c(s),o=[];for(const d of h){const l=s+d.length;if(l>=i.length){o.push([d]);break}if(n>0){const u=t(n-1,l);for(const f of u)f.length===n-1&&o.push([d,...f])}}return o}function c(n){if(n>=i.length)throw new Error("From exceed blocks length");const s=[0,-1];let h=0,o=0;for(;i.length>n+o&&(h+=(o>0?e:0)+i[n+o])&&h/a<1.001;)o++;return s.map(l=>o+l).filter(l=>l>0).map(l=>d(n,l));function d(l,u){const f=Array(u);for(;u--;)f[u]=u+l;return f}}}function H(a,r,i){const e=a.map(t=>{const c=t.map(s=>s.map(h=>r[h]).reduce((h,o,d)=>h+(d>0?i:0)+o),0),n=R(c);return{ll:t,dd:n}});return e.sort((t,c)=>t.dd-c.dd),e.map(t=>t.ll)[0]}function R(a){const r=a.length,i=a.reduce((e,t)=>e+t)/r;return Math.sqrt(a.map(e=>Math.pow(e-i,2)).reduce((e,t)=>e+t)/r)}function k(a,r){return a.map(i=>i.map(e=>r[e]).reduce((e,t,c)=>e+(c>0?" ":"")+t),"")}
1
+ const M=document.createElement("canvas").getContext("2d");export default class I{constructor(r,i,e){this.baseFontSize=this.maxMultilineFontSize=e,this.fontSizes=i,this.ctx=M,this.ctx.textAlign="center",this.ctx.textBaseline="alphabetic",this.ctx.font=r(this.baseFontSize),this.spaceWidth=this.ctx.measureText(" ").width}getStepsForRect(r,i,e){const t=r.split(/\s+/),c=t.map(o=>this.ctx.measureText(o).width),n=[];let s=1/0,h=0;for(const o of this.fontSizes){const d=o,l=o/this.baseFontSize,u=c.map(p=>p*l),f=this.spaceWidth*l,x=B(u,f,o>this.maxMultilineFontSize?1:1/0).filter(p=>p);for(let p=0;p<x.length;p++){const w=x[p],F=w,m=p+1,L=d*m,W=F/i,v=L/e,g=Math.max(v,W);if(g>s||m<h)continue;s=g,h=m;const z=y(w,m,u,f),S=H(z,u,f);if(!S)continue;const b=k(S,t);n.push({scaleFactor:g,value:o,lines:b})}}return n}}function B(a,r,i){const e=[];let t=0,c=1,n=1/0,s;for(;(s=T(n,a,r))&&s.length<=i;)c!==s.length&&(e[c-1]=t),c=s.length,t=Math.max(...s),n=t-1;return e[c-1]=t,e}function T(a,r,i){const e=[];let t=0,c=-1;function n(){c++,t=0}n();for(const s of r){const h=t+(t>0?i:0)+s;if(h>a){if(s>a)return null;n(),t=s}else t=h;e[c]=t}return e}function y(a,r,i,e){return t(r,0);function t(n,s){const h=c(s),o=[];for(const d of h){const l=s+d.length;if(l>=i.length){o.push([d]);break}if(n>0){const u=t(n-1,l);for(const f of u)f.length===n-1&&o.push([d,...f])}}return o}function c(n){if(n>=i.length)throw new Error("From exceed blocks length");const s=[0,-1];let h=0,o=0;for(;i.length>n+o&&(h+=(o>0?e:0)+i[n+o])&&h/a<1.001;)o++;return s.map(l=>o+l).filter(l=>l>0).map(l=>d(n,l));function d(l,u){const f=Array(u);for(;u--;)f[u]=u+l;return f}}}function H(a,r,i){const e=a.map(t=>{const c=t.map(s=>s.map(h=>r[h]).reduce((h,o,d)=>h+(d>0?i:0)+o),0),n=R(c);return{ll:t,dd:n}});return e.sort((t,c)=>t.dd-c.dd),e.map(t=>t.ll)[0]}function R(a){const r=a.length,i=a.reduce((e,t)=>e+t)/r;return Math.sqrt(a.map(e=>Math.pow(e-i,2)).reduce((e,t)=>e+t)/r)}function k(a,r){return a.map(i=>i.map(e=>r[e]).reduce((e,t,c)=>e+(c>0?" ":"")+t),"")}
@@ -1,8 +1,96 @@
1
+ import { Rect } from '@expofp/geometry';
2
+ /**
3
+ * Creates a canvas that remembers the device pixel ratio it was rasterized at.
4
+ *
5
+ * The backing size is taken as given, and `style.width`/`style.height` hold the CSS size, the
6
+ * backing size over the ratio. The renderer sizes defs from that CSS size, so the ratio only sets
7
+ * how crisp the canvas is. A caller with a CSS size passes it times the ratio.
8
+ * @param width - The backing width in device pixels.
9
+ * @param height - The backing height in device pixels.
10
+ * @param pixelRatio - Device pixels per CSS pixel.
11
+ * @returns The canvas.
12
+ */
13
+ export declare function createCanvas(width: number, height: number, pixelRatio?: number): HTMLCanvasElement;
14
+ /**
15
+ * The CSS size a canvas from this module was drawn at, as it recorded when it was made.
16
+ *
17
+ * For a caller that holds a canvas and no longer holds the numbers it was made from. Prefer the
18
+ * size function that names the creator ({@link circleCanvasCssSize}, {@link imageCanvasCssSize})
19
+ * where the caller made the canvas itself.
20
+ * @param canvas - A canvas made by one of the creators here.
21
+ * @returns The canvas's CSS width and height.
22
+ */
23
+ export declare function cssSizeOf(canvas: HTMLCanvasElement): {
24
+ width: number;
25
+ height: number;
26
+ };
27
+ export declare function getBounds(x: number, y: number, width: number, height: number, scale?: number, rotate?: number, elevation?: number): Rect;
28
+ export declare function getFont(px: number, weight?: number, style?: string): string;
29
+ export declare function createLabelCanvas(text: string, fontSize: number, pixelRatio: number, color: string | undefined, fontWeight: number, strokeStyle?: string, strokeWidth?: number): HTMLCanvasElement;
30
+ /**
31
+ * The CSS size a circle canvas of this radius is drawn at — the one answer to "how big is this dot",
32
+ * and the number a def's bounds are sized from.
33
+ *
34
+ * A canvas's `width` is its backing store in the device pixels it was baked at, which is a different
35
+ * quantity: truncated to a whole pixel, and baked at a ratio that need not be the one the renderer
36
+ * draws into. Geometry reads this; the backing store is for crispness.
37
+ * @param radius - The dot's radius in CSS pixels.
38
+ * @returns The canvas's CSS width and height, which are equal.
39
+ */
40
+ export declare function circleCanvasCssSize(radius: number): number;
41
+ export declare function createCircleCanvas(radius: number, color: string): HTMLCanvasElement;
42
+ /**
43
+ * The CSS size a bookmark canvas is drawn at: the width asked for, and the height its ribbon adds.
44
+ * @param maxSizePx - The ribbon's width in CSS pixels.
45
+ * @returns The canvas's CSS width and height.
46
+ */
47
+ export declare function bookmarkCanvasCssSize(maxSizePx: number): {
48
+ width: number;
49
+ height: number;
50
+ };
51
+ export declare function createBookmarkCanvas(maxSizePx: number, pixelRatio: number): HTMLCanvasElement;
52
+ /**
53
+ * The CSS size {@link createImageCanvas} draws an image at: the box it was asked for, shrunk on one
54
+ * axis to the image's own aspect.
55
+ * @param image - The image the canvas is drawn from.
56
+ * @param width - The box's width in CSS pixels.
57
+ * @param height - The box's height in CSS pixels.
58
+ * @param ptsScale - The scale the canvas was drawn at, as {@link createImageCanvas} takes it.
59
+ * @returns The canvas's CSS width and height.
60
+ */
61
+ export declare function imageCanvasCssSize(image: HTMLImageElement, width: number, height: number, ptsScale?: number): {
62
+ width: number;
63
+ height: number;
64
+ };
1
65
  export declare function createImageCanvas(image: HTMLImageElement, width: number, height: number, pixelRatio: number, ptsScale?: number, flip?: 'horizontal' | 'vertical'): HTMLCanvasElement;
2
66
  export declare function createCurrentCanvas(pixelRatio: number, color?: string, scale?: number, width?: number, height?: number, text?: string, textColor?: string): HTMLCanvasElement;
3
67
  export declare function createTargetCanvas(pixelRatio: number, color?: string, scale?: number): HTMLCanvasElement;
4
68
  export declare function createArrowCurrentCanvas(pixelRatio: number, color?: string, scale?: number): HTMLCanvasElement;
5
69
  export declare function createYahCanvas(pixelRatio: number, color?: string, scale?: number): HTMLCanvasElement;
6
- export declare function createLabelCanvas(text: string, fontSize: number, pixelRatio: number, color: string | undefined, fontWeight: number, strokeStyle?: string, strokeWidth?: number): HTMLCanvasElement;
7
- export declare function getFont(px: number, weight?: number, style?: string): string;
70
+ /**
71
+ * The pin marking a booth an active PoI-type filter selected: a teardrop pointing down, filled red,
72
+ * edged in black, with a white center in its head.
73
+ *
74
+ * The black edge is what carries the shape over a highlighted booth — the body and a highlighted
75
+ * booth are both red, so without it the drop dissolves into the booth and only the center reads.
76
+ *
77
+ * Hands back a canvas rather than the `ImageData` the two pins above return, because the renderer
78
+ * packs a canvas into its atlas directly and every pin on the plan shares this one image.
79
+ */
80
+ export declare function createPoiPinCanvas(widthPx: number, pixelRatio: number): HTMLCanvasElement;
81
+ /**
82
+ * The marker standing for a group of booths an active PoI-type filter selected: the same teardrop
83
+ * the lone pin draws, with an empty white counter circle filling its head.
84
+ *
85
+ * The count is **not** baked in. A number on the canvas would make one `ImageSource` per count, and
86
+ * the renderer's image container repacks its atlas when the *set* of images changes, so a zoom step
87
+ * that moved a cluster from 7 members to 12 would repack. Drawn empty, exactly two images ever
88
+ * reach the atlas — this one and the lone pin — and the set is fixed for the plan's life. The count
89
+ * is a separate screen-space text def in a sibling layer, standing on the marker's anchor; neither
90
+ * carries a placement, since both draw a cluster the renderer already decided.
91
+ * @param widthPx - The marker's width in CSS pixels.
92
+ * @param pixelRatio - Device pixels per CSS pixel.
93
+ * @returns The canvas every cluster marker draws.
94
+ */
95
+ export declare function createClusterPinCanvas(widthPx: number, pixelRatio: number): HTMLCanvasElement;
8
96
  //# sourceMappingURL=canvases.d.ts.map
@@ -1 +1 @@
1
- import{FONT_FACE as z,FONT_WEIGHT_PRIMARY_BOOTH as f}from"../../../../constants";export function createImageCanvas(n,l,o,i,c=1,r){const e=n?n.width/n.height:1;let a=l*i*c,t=o*i*c;l/o>e?a=t*e:t=a/e;const v=document.createElement("canvas"),u=v.getContext("2d");return v.width=a,v.height=t,v.id=n.id,r==="horizontal"?(u.scale(-1,1),u.translate(-a,0)):r==="vertical"&&(u.scale(1,-1),u.translate(0,-t)),u.drawImage(n,0,0,a,t),v}export function createCurrentCanvas(n,l="#c8248b",o=n*.4,i,c,r,e="#000"){i=i||95,c=c||95;const a=document.createElement("canvas"),t=a.getContext("2d");a.width=i*o,a.height=c*o,t.scale(o,o);const v=i/2,u=c/2;if(t.translate(v-35,r?0:u-35),t.beginPath(),t.fillStyle="#FFFFFF",t.moveTo(0,35),t.bezierCurveTo(0,54.329966,15.670034,70,35,70),t.bezierCurveTo(54.329966,70,70,54.329966,70,35),t.bezierCurveTo(70,15.670034,54.329966,0,35,0),t.bezierCurveTo(15.670034,0,0,15.670034,0,35),t.fill(),t.beginPath(),t.fillStyle=l,t.moveTo(10,35),t.bezierCurveTo(10,48.807119,21.192881,60,35,60),t.bezierCurveTo(48.807119,60,60,48.807119,60,35),t.bezierCurveTo(60,21.192881,48.807119,10,35,10),t.bezierCurveTo(21.192881,10,10,21.192881,10,35),t.fill(),r){t.textAlign="center",t.textBaseline="alphabetic",t.lineJoin="round",t.strokeStyle="#fff",t.fillStyle=e;const T=38;t.font=getFont(T),t.lineWidth=6;const b=70+T;t.strokeText(r,35,b,i),t.fillText(r,35,b,i)}return a}export function createTargetCanvas(n,l="#c8248b",o=n*.5){const i=70*o,c=100*o,r=document.createElement("canvas"),e=r.getContext("2d");return r.width=i,r.height=c,e.scale(o,o),e.beginPath(),e.fillStyle="rgb(255, 255, 255)",e.moveTo(32.6,97.8),e.bezierCurveTo(24.4,81.5,0,57,0,32.6),e.bezierCurveTo(0,14.6,14.6,0,32.6,0),e.bezierCurveTo(50.5,0,65.2,14.6,65.2,32.6),e.bezierCurveTo(65.2,57,40.7,81.5,32.6,97.8),e.fill(),e.beginPath(),e.fillStyle=l,e.moveTo(32.6,91.1),e.bezierCurveTo(25.2,76.3,3.1,54.2,3.1,32.1),e.bezierCurveTo(3.1,15.9,16.3,2.6,32.6,2.6),e.bezierCurveTo(48.8,2.6,62,15.9,62,32.1),e.bezierCurveTo(62,54.2,39.9,76.3,32.6,91.1),e.fill(),e.beginPath(),e.fillStyle="rgb(255, 255, 255)",e.moveTo(16.2,32.6),e.bezierCurveTo(16.2,41.6,23.5,48.9,32.5,48.9),e.bezierCurveTo(41.5,48.9,48.8,41.6,48.8,32.6),e.bezierCurveTo(48.8,23.6,41.5,16.3,32.5,16.3),e.bezierCurveTo(23.5,16.3,16.2,23.6,16.2,32.6),e.fill(),r}export function createArrowCurrentCanvas(n,l="#c8248b",o=n*.4){const i=95*o,c=95*o,r=document.createElement("canvas"),e=r.getContext("2d");return r.width=i,r.height=c,e.scale(o,o),e.beginPath(),e.arc(47,47,25,0,2*Math.PI),e.fillStyle=l,e.fill(),e.beginPath(),e.fillStyle=l,e.moveTo(75,27),e.lineTo(95,47),e.lineTo(75,67),e.lineTo(80,47),e.closePath(),e.fill(),r}export function createYahCanvas(n,l="#ff4343",o=n*.5){const i=77*o,c=116*o,r=document.createElement("canvas"),e=r.getContext("2d");return r.width=i,r.height=c,e.scale(o,o),e.scale(o,o),e.beginPath(),e.fillStyle="#FFFFFF",e.moveTo(68.303,57.335),e.bezierCurveTo(77.894,39.304,70.649,15.785,50.95,8.04),e.bezierCurveTo(30.727,0,8.375,11.837,3.207,32.831),e.bezierCurveTo(0,46.185,6.644,57.323,13.131,68.211),e.fill(),e.beginPath(),e.fillStyle=l,e.moveTo(51.565,35.459),e.bezierCurveTo(51.565,43.256,45.201,49.575,37.354,49.575),e.bezierCurveTo(29.516,49.575,23.159,43.256,23.159,35.459),e.bezierCurveTo(23.159,27.668,29.516,21.345,37.354,21.345),e.bezierCurveTo(45.201,21.345,51.565,27.668,51.565,35.459),e.closePath(),e.fill(),e.beginPath(),e.moveTo(68.303,57.335),e.bezierCurveTo(77.894,39.304,70.649,15.785,50.95,8.04),e.bezierCurveTo(30.727,0,8.375,11.837,3.207,32.831),e.bezierCurveTo(0,46.185,6.644,57.323,13.131,68.211),e.lineTo(13.131,68.211),e.lineTo(13.131,68.211),e.bezierCurveTo(13.921,69.533,14.698,70.829,15.454,72.137),e.bezierCurveTo(19.465,79.158,23.533,86.12,27.571,93.086),e.lineTo(27.571,93.086),e.bezierCurveTo(30.098,97.421,32.611,101.756,35.116,106.077),e.bezierCurveTo(36.128,107.868,38.934,107.868,39.945,106.077),e.bezierCurveTo(49.387,90.003,58.708,74.029,68.031,57.951),e.bezierCurveTo(68.15,57.743,68.24,57.543,68.303,57.335),e.closePath(),e.moveTo(60.103,60.395),e.lineTo(63.201,55.041),e.lineTo(63.201,55.041),e.bezierCurveTo(73.31,36.735,61.285,11.614,39.04,11.17),e.bezierCurveTo(19.388,10.714,2.759,29.479,9.386,49.013),e.bezierCurveTo(10.726,52.998,12.657,56.9,14.84,60.721),e.bezierCurveTo(15.041,58.454,15.938,56.258,17.589,54.586),e.bezierCurveTo(19.708,52.425,22.216,50.638,24.996,49.283),e.bezierCurveTo(28.252,52.249,32.595,54.051,37.354,54.051),e.bezierCurveTo(42.123,54.051,46.47,52.249,49.73,49.283),e.bezierCurveTo(52.505,50.638,55.017,52.425,57.135,54.586),e.bezierCurveTo(58.701,56.188,59.701,58.245,60.103,60.395),e.closePath(),e.fill("evenodd"),e.beginPath(),e.moveTo(29.024,104.982),e.bezierCurveTo(29.024,103.626,27.923,102.527,26.57,102.527),e.bezierCurveTo(25.214,102.527,24.114,103.626,24.114,104.982),e.bezierCurveTo(24.114,111.395,30.347,116.838,37.444,116.838),e.bezierCurveTo(44.54,116.838,50.771,111.395,50.771,104.982),e.bezierCurveTo(50.771,103.626,49.666,102.527,48.317,102.527),e.bezierCurveTo(46.961,102.527,45.855,103.626,45.855,104.982),e.bezierCurveTo(45.855,108.193,42.352,111.956,37.444,111.956),e.bezierCurveTo(32.528,111.956,29.024,108.193,29.024,104.982),e.closePath(),e.fill(),r}const h=document.createElement("canvas"),C=h.getContext("2d");function d(n,l){return C.font=n,C.measureText(l).width}export function createLabelCanvas(n,l,o,i="#fff",c,r,e){n=n.replace(/^_/,""),l*=o;const a=document.createElement("canvas"),t=a.getContext("2d"),v=Number(getComputedStyle(document.body).getPropertyValue(f)),u=getFont(l,v||c),T=d(u,n.replace(/[0-9]/g,"3").replace(/[A-Z]/g,"A"))+3+3,b=4,s=l+b;return a.width=T*o,a.height=s*o,t.font=u,t.textAlign="center",t.textBaseline="alphabetic",t.fillStyle=i,e&&r&&(t.lineWidth=e,t.strokeStyle=r,t.strokeText(n,T/2,s-b/2*o),t.lineJoin="round"),t.fillText(n,T/2,s-b/2*o),a}export function getFont(n,l=500,o="normal"){const i=getComputedStyle(document.body).getPropertyValue(z),c='Oswald, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',r=i?`${i}, ${c}`:c;return`${o} ${l} ${n}px ${r}`}
1
+ import{Rect as _}from"@expofp/geometry";import{FONT_FACE as x,FONT_WEIGHT_PRIMARY_BOOTH as I}from"../../../../constants";import{clusterCounterCircle as p,PIN_ASPECT as g,PIN_EDGE_PX as P,PIN_HEAD_FACTOR as d}from"./pin-geometry";export function createCanvas(o,c,n=1){const t=document.createElement("canvas");return t.width=o,t.height=c,t.style.width=`${o/n}px`,t.style.height=`${c/n}px`,t}export function cssSizeOf(o){return{width:parseFloat(o.style.width),height:parseFloat(o.style.height)}}export function getBounds(o,c,n,t,s=1,r,e){const l=n*s,i=t*s;return new _({x:o,y:c},{x:l,y:i},r,e)}export function getFont(o,c=500,n="normal"){const t=getComputedStyle(document.body).getPropertyValue(x),s='Oswald, -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',r=t?`${t}, ${s}`:s;return`${n} ${c} ${o}px ${r}`}let f;function O(o,c){return f??=document.createElement("canvas").getContext("2d"),f.font=o,f.measureText(c).width}export function createLabelCanvas(o,c,n,t="#fff",s,r,e){o=o.replace(/^_/,""),c*=n;const l=Number(getComputedStyle(document.body).getPropertyValue(I)),i=getFont(c,l||s),u=O(i,o.replace(/[0-9]/g,"3").replace(/[A-Z]/g,"A"))+3+3,a=4,C=c+a,T=createCanvas(u*n,C*n,n),v=T.getContext("2d");return v.font=i,v.textAlign="center",v.textBaseline="alphabetic",v.fillStyle=t,e&&r&&(v.lineWidth=e,v.strokeStyle=r,v.strokeText(o,u/2,C-a/2*n),v.lineJoin="round"),v.fillText(o,u/2,C-a/2*n),T}export function circleCanvasCssSize(o){return o*2+k*2}export function createCircleCanvas(o,c){const n=c.toUpperCase();if(!b.has(n)){const t=circleCanvasCssSize(o),s=createCanvas(t*devicePixelRatio,t*devicePixelRatio,devicePixelRatio),r=s.getContext("2d");r.fillStyle=c,r.beginPath(),r.arc(s.width/2,s.height/2,o*devicePixelRatio,0,2*Math.PI),r.fill(),b.set(n,s)}return b.get(n)}export function bookmarkCanvasCssSize(o){return{width:o,height:o*1.4}}export function createBookmarkCanvas(o,c){const n=o;if(h.has(n))return h.get(n);const{width:t,height:s}=bookmarkCanvasCssSize(o),r=Math.ceil(t*c),e=Math.ceil(s*c),l=createCanvas(r,e,c),i=l.getContext("2d");return i.scale(c,c),i.fillStyle="#fdbf2b",i.strokeStyle="#fff",i.lineWidth=4/c,i.beginPath(),i.moveTo(0,0),i.lineTo(0,s),i.lineTo(t/2,s-t/2),i.lineTo(t,s),i.lineTo(t,0),i.lineTo(0,0),i.fill(),i.stroke(),h.set(n,l),l}const k=1,b=new Map,h=new Map;export function imageCanvasCssSize(o,c,n,t=1){const[s,r]=y(o,c,n,c*t,n*t);return{width:s,height:r}}export function createImageCanvas(o,c,n,t,s=1,r){const[e,l]=y(o,c,n,c*t*s,n*t*s),i=createCanvas(e,l,t),u=i.getContext("2d");return i.id=o.id,r==="horizontal"?(u.scale(-1,1),u.translate(-e,0)):r==="vertical"&&(u.scale(1,-1),u.translate(0,-l)),u.drawImage(o,0,0,e,l),i}function y(o,c,n,t,s){const r=o?o.width/o.height:1;return c/n>r?[s*r,s]:[t,t/r]}export function createCurrentCanvas(o,c="#c8248b",n=o*.4,t,s,r,e="#000"){t=t||95,s=s||95;const l=createCanvas(t*n,s*n,o),i=l.getContext("2d");i.scale(n,n);const u=t/2,a=s/2;if(i.translate(u-35,r?0:a-35),i.beginPath(),i.fillStyle="#FFFFFF",i.moveTo(0,35),i.bezierCurveTo(0,54.329966,15.670034,70,35,70),i.bezierCurveTo(54.329966,70,70,54.329966,70,35),i.bezierCurveTo(70,15.670034,54.329966,0,35,0),i.bezierCurveTo(15.670034,0,0,15.670034,0,35),i.fill(),i.beginPath(),i.fillStyle=c,i.moveTo(10,35),i.bezierCurveTo(10,48.807119,21.192881,60,35,60),i.bezierCurveTo(48.807119,60,60,48.807119,60,35),i.bezierCurveTo(60,21.192881,48.807119,10,35,10),i.bezierCurveTo(21.192881,10,10,21.192881,10,35),i.fill(),r){i.textAlign="center",i.textBaseline="alphabetic",i.lineJoin="round",i.strokeStyle="#fff",i.fillStyle=e;const C=38;i.font=getFont(C),i.lineWidth=6;const T=70+C;i.strokeText(r,35,T,t),i.fillText(r,35,T,t)}return l}export function createTargetCanvas(o,c="#c8248b",n=o*.5){const t=70*n,s=100*n,r=createCanvas(t,s,o),e=r.getContext("2d");return e.scale(n,n),e.beginPath(),e.fillStyle="rgb(255, 255, 255)",e.moveTo(32.6,97.8),e.bezierCurveTo(24.4,81.5,0,57,0,32.6),e.bezierCurveTo(0,14.6,14.6,0,32.6,0),e.bezierCurveTo(50.5,0,65.2,14.6,65.2,32.6),e.bezierCurveTo(65.2,57,40.7,81.5,32.6,97.8),e.fill(),e.beginPath(),e.fillStyle=c,e.moveTo(32.6,91.1),e.bezierCurveTo(25.2,76.3,3.1,54.2,3.1,32.1),e.bezierCurveTo(3.1,15.9,16.3,2.6,32.6,2.6),e.bezierCurveTo(48.8,2.6,62,15.9,62,32.1),e.bezierCurveTo(62,54.2,39.9,76.3,32.6,91.1),e.fill(),e.beginPath(),e.fillStyle="rgb(255, 255, 255)",e.moveTo(16.2,32.6),e.bezierCurveTo(16.2,41.6,23.5,48.9,32.5,48.9),e.bezierCurveTo(41.5,48.9,48.8,41.6,48.8,32.6),e.bezierCurveTo(48.8,23.6,41.5,16.3,32.5,16.3),e.bezierCurveTo(23.5,16.3,16.2,23.6,16.2,32.6),e.fill(),r}export function createArrowCurrentCanvas(o,c="#c8248b",n=o*.4){const t=95*n,s=95*n,r=createCanvas(t,s,o),e=r.getContext("2d");return e.scale(n,n),e.beginPath(),e.arc(47,47,25,0,2*Math.PI),e.fillStyle=c,e.fill(),e.beginPath(),e.fillStyle=c,e.moveTo(75,27),e.lineTo(95,47),e.lineTo(75,67),e.lineTo(80,47),e.closePath(),e.fill(),r}export function createYahCanvas(o,c="#ff4343",n=o*.5){const t=77*n,s=116*n,r=createCanvas(t,s,o),e=r.getContext("2d");return e.scale(n,n),e.scale(n,n),e.beginPath(),e.fillStyle="#FFFFFF",e.moveTo(68.303,57.335),e.bezierCurveTo(77.894,39.304,70.649,15.785,50.95,8.04),e.bezierCurveTo(30.727,0,8.375,11.837,3.207,32.831),e.bezierCurveTo(0,46.185,6.644,57.323,13.131,68.211),e.fill(),e.beginPath(),e.fillStyle=c,e.moveTo(51.565,35.459),e.bezierCurveTo(51.565,43.256,45.201,49.575,37.354,49.575),e.bezierCurveTo(29.516,49.575,23.159,43.256,23.159,35.459),e.bezierCurveTo(23.159,27.668,29.516,21.345,37.354,21.345),e.bezierCurveTo(45.201,21.345,51.565,27.668,51.565,35.459),e.closePath(),e.fill(),e.beginPath(),e.moveTo(68.303,57.335),e.bezierCurveTo(77.894,39.304,70.649,15.785,50.95,8.04),e.bezierCurveTo(30.727,0,8.375,11.837,3.207,32.831),e.bezierCurveTo(0,46.185,6.644,57.323,13.131,68.211),e.lineTo(13.131,68.211),e.lineTo(13.131,68.211),e.bezierCurveTo(13.921,69.533,14.698,70.829,15.454,72.137),e.bezierCurveTo(19.465,79.158,23.533,86.12,27.571,93.086),e.lineTo(27.571,93.086),e.bezierCurveTo(30.098,97.421,32.611,101.756,35.116,106.077),e.bezierCurveTo(36.128,107.868,38.934,107.868,39.945,106.077),e.bezierCurveTo(49.387,90.003,58.708,74.029,68.031,57.951),e.bezierCurveTo(68.15,57.743,68.24,57.543,68.303,57.335),e.closePath(),e.moveTo(60.103,60.395),e.lineTo(63.201,55.041),e.lineTo(63.201,55.041),e.bezierCurveTo(73.31,36.735,61.285,11.614,39.04,11.17),e.bezierCurveTo(19.388,10.714,2.759,29.479,9.386,49.013),e.bezierCurveTo(10.726,52.998,12.657,56.9,14.84,60.721),e.bezierCurveTo(15.041,58.454,15.938,56.258,17.589,54.586),e.bezierCurveTo(19.708,52.425,22.216,50.638,24.996,49.283),e.bezierCurveTo(28.252,52.249,32.595,54.051,37.354,54.051),e.bezierCurveTo(42.123,54.051,46.47,52.249,49.73,49.283),e.bezierCurveTo(52.505,50.638,55.017,52.425,57.135,54.586),e.bezierCurveTo(58.701,56.188,59.701,58.245,60.103,60.395),e.closePath(),e.fill("evenodd"),e.beginPath(),e.moveTo(29.024,104.982),e.bezierCurveTo(29.024,103.626,27.923,102.527,26.57,102.527),e.bezierCurveTo(25.214,102.527,24.114,103.626,24.114,104.982),e.bezierCurveTo(24.114,111.395,30.347,116.838,37.444,116.838),e.bezierCurveTo(44.54,116.838,50.771,111.395,50.771,104.982),e.bezierCurveTo(50.771,103.626,49.666,102.527,48.317,102.527),e.bezierCurveTo(46.961,102.527,45.855,103.626,45.855,104.982),e.bezierCurveTo(45.855,108.193,42.352,111.956,37.444,111.956),e.bezierCurveTo(32.528,111.956,29.024,108.193,29.024,104.982),e.closePath(),e.fill(),r}const z="#ffffff",w=.45,m="#e8112d",S="#000000";function A(o,c,n,t,s){const r=c/2,e=t+s,l=n-s;o.beginPath(),o.moveTo(r,l),o.bezierCurveTo(r-t*.55,e+t*.8,r-t,e+t*.35,r-t,e),o.bezierCurveTo(r-t,e-t*.72,r-t*.45,e-t,r,e-t),o.bezierCurveTo(r+t*.45,e-t,r+t,e-t*.72,r+t,e),o.bezierCurveTo(r+t,e+t*.35,r+t*.55,e+t*.8,r,l),o.closePath()}function F(o,c,n,t,s,r,e=z){const l=o,i=o*c,u=createCanvas(l*n,i*n,n),a=u.getContext("2d");a.scale(n,n);const C=l*t;return A(a,l,i,C,s),a.fillStyle=r,a.strokeStyle=e,a.lineWidth=s,a.lineJoin="round",a.fill(),a.stroke(),{canvas:u,ctx:a,cx:l/2,cy:C+s,r:C}}export function createPoiPinCanvas(o,c){const{canvas:n,ctx:t,cx:s,cy:r,r:e}=F(o,g,c,d,P,m,S);return t.beginPath(),t.arc(s,r,e*w,0,2*Math.PI),t.fillStyle=z,t.fill(),n}export function createClusterPinCanvas(o,c){const{canvas:n,ctx:t}=F(o,g,c,d,P,m,S),{cx:s,cy:r,r:e}=p(o);return t.beginPath(),t.arc(s,r,e,0,2*Math.PI),t.fillStyle=z,t.fill(),n}
@@ -1 +1 @@
1
- import{initWayfindingLayers as p}from"@expofp/wayfinding";import{createLayerDef as L}from"../../../../engine/defs";import f,{boothStore as d,uiState as l}from"../../../../store";import{isPathwayLayer as u}from"../../../../utils/is-pathway-layer";import{createTrafficLayers as h}from"../../traffic/trafficLayers";import{configBoothsBadges as g}from"./config-booth-badge";import w from"./config-load-layer";import{MARKER_LAYER_NAME as b}from"./config-markers";export default function A(){const{defaultLayer:a}=f.layerStore;let{layers:e}=f.layerStore;if(a){const r=[...e],o=e.indexOf(a);r.splice(o,1),e=[a,...r]}const m=e.filter(r=>!r.rootParent).map(r=>w(r));return Promise.all(m).then(r=>{const o=L(b,[]);o.overlay=l.is3DView;const y=p({overlay:l.is3DView}),i=[],s=[];for(const t of r.flat())u(t.name)?(t.dim=0,s.push(t)):i.push(t);const{layer:n,cleanup:c}=g("root",d.booths);return{layers:[...i,...n?[n]:[],...s,...h(),o,y],cleanup:c}})}
1
+ import{initWayfindingLayers as L}from"@expofp/wayfinding";import{createLayerDef as f}from"../../../../engine/defs";import m,{boothStore as d,uiState as s}from"../../../../store";import{isPathwayLayer as A}from"../../../../utils/is-pathway-layer";import{createTrafficLayers as E}from"../../traffic/trafficLayers";import{configBoothsBadges as _}from"./config-booth-badge";import g from"./config-load-layer";import{MARKER_LAYER_NAME as h}from"./config-markers";import{configPins as N,PIN_CLUSTER_LAYER_NAME as P,PIN_COUNT_LAYER_NAME as R,PIN_LAYER_NAME as w}from"./config-pins";export default function M(){const{defaultLayer:r}=m.layerStore;let{layers:o}=m.layerStore;if(r){const e=[...o],t=o.indexOf(r);e.splice(t,1),o=[r,...e]}const i=o.filter(e=>!e.rootParent).map(e=>g(e));return Promise.all(i).then(e=>{const t=f(h,[]);t.overlay=s.is3DView;const a=s.is3DView?S():void 0,p=L({overlay:s.is3DView}),l=[],c=[];for(const n of e.flat())A(n.name)?(n.dim=0,c.push(n)):l.push(n);const{layer:y,cleanup:u}=_("root",d.booths);return{layers:[...l,...y?[y]:[],...c,...E(),t,...a?.layers??[],p],cleanup:()=>{u(),a?.cleanup()}}})}function S(){const r=[w,P,R].map(t=>{const a=f(t,[]);return a.overlay=!0,a.dim=0,a}),[o,i,e]=r;return{layers:r,cleanup:N(o,i,e)}}
@@ -22,7 +22,7 @@ export declare class BoothBadgeDrawer {
22
22
  constructor(placement: BadgePlacement);
23
23
  /**
24
24
  * Lays the background rect out for a new pixel size.
25
- * @param pixelSize - Plan units per device pixel.
25
+ * @param pixelSize - Plan units per CSS pixel.
26
26
  * @returns The background unless its floor is switched off — the rect is kept current either
27
27
  * way, so showing it draws the right size straight away.
28
28
  */
@@ -30,7 +30,7 @@ export declare class BoothBadgeDrawer {
30
30
  /**
31
31
  * Lays the booth number out for a new pixel size. The font stops growing at the scale the badge
32
32
  * itself stops growing, so the text never outgrows the rect around it.
33
- * @param pixelSize - Plan units per device pixel.
33
+ * @param pixelSize - Plan units per CSS pixel.
34
34
  * @returns The text unless its floor is switched off, as for the background.
35
35
  */
36
36
  layOutText(pixelSize: number): TextDef[];
@@ -40,7 +40,7 @@ export declare class BoothBadgeDrawer {
40
40
  * The anchor is in world space and names the badge's top-left corner, so the center is
41
41
  * `anchor + R(rotation) · (w/2, h/2)`; the renderer then rotates the badge about that center, which
42
42
  * lands it where the anchor says.
43
- * @param pixelSize - Plan units per device pixel.
43
+ * @param pixelSize - Plan units per CSS pixel.
44
44
  * @returns The rect.
45
45
  */
46
46
  private rectScaled;
@@ -15,7 +15,7 @@ export declare class BoothBookmarkDrawer extends BoothDrawerBaseWithoutPainter {
15
15
  /**
16
16
  * Lays this bookmark out for a new pixel size: the ribbon holds its on-screen size, clamped to what
17
17
  * fits in the top-right corner of the booth.
18
- * @param pixelSize - Plan units per device pixel.
18
+ * @param pixelSize - Plan units per CSS pixel.
19
19
  * @returns The bookmark unless hidden — nothing draws a hidden one, and `update()` syncs it on
20
20
  * the way back into view.
21
21
  */
@@ -1 +1 @@
1
- import{Rect as m}from"@expofp/geometry";import{update as d}from"@expofp/renderer";import{createBookmarkCanvas as p}from"../../../../engine/canvases";import{createImageDef as u}from"../../../../engine/defs";import{getClampedBoundsCanvas as k,getQuarterTurns as c,getRollValue as l,rotateRectByQuarters as f}from"../../../../engine/update-def";import{layersStore as i,uiState as a}from"../../../../store";import{planReaction as s}from"../../../../utils/plan-reactions.js";import{BoothDrawerBaseWithoutPainter as b}from"./BoothDrawerBase";export default function B(r){if(!a.kiosk)return new BoothBookmarkDrawer(r)}export class BoothBookmarkDrawer extends b{constructor(t){super(t),this.getShape=()=>this.shape,this.padding=this.booth.borderWidth/2,this.rect=new m(this.booth.rect.center,this.booth.rect.size,this.booth.rotate,this.booth.elevation),this.canvas=p(11,devicePixelRatio),this.bookmarkId=`bookmark-${this.booth.id}`,this.shape=u(this.canvas,this.rect,{hidden:!t.bookmarked}),this.shape.onScale=({pixelSize:e})=>this.layOutBookmark(e),s(()=>[t.bookmarked,i.layersLoaded,this.booth.skipDim],()=>this.update(t.bookmarked),{fireImmediately:t.bookmarked}),s(()=>a.mapSettings,({roll:e})=>{l(e??0)&&(this.shape.onRoll=({roll:h,pixelSize:n})=>{const o=c(h,this.rect.rotation);if(o!==0)return this.rect=f(this.rect,o),this.layOutBookmark(n),[this.shape]})},{fireImmediately:!0})}update(t){i.layersLoaded&&(this.shape.hidden=!t,this.shape.dim=this.booth.skipDim?0:void 0,d(this.shape))}layOutBookmark(t){return this.shape.bounds=k(this.rect,this.canvas,this.padding,t),this.shape.hidden?[]:[this.shape]}}
1
+ import{Rect as d}from"@expofp/geometry";import{update as p}from"@expofp/renderer";import{createImageDef as k}from"../../../../engine/defs";import{getClampedBoundsCanvas as u,getQuarterTurns as c,getRollValue as l,rotateRectByQuarters as f}from"../../../../engine/update-def";import{layersStore as i,uiState as a}from"../../../../store";import{planReaction as s}from"../../../../utils/plan-reactions.js";import{BoothDrawerBaseWithoutPainter as b}from"./BoothDrawerBase";import{bookmarkCanvasCssSize as B,createBookmarkCanvas as g}from"./canvases";export default function y(o){if(!a.kiosk)return new BoothBookmarkDrawer(o)}export class BoothBookmarkDrawer extends b{constructor(t){super(t),this.getShape=()=>this.shape,this.padding=this.booth.borderWidth/2,this.rect=new d(this.booth.rect.center,this.booth.rect.size,this.booth.rotate,this.booth.elevation),this.canvas=g(h,devicePixelRatio),this.bookmarkId=`bookmark-${this.booth.id}`,this.shape=k(this.canvas,this.rect,{hidden:!t.bookmarked}),this.shape.onScale=({pixelSize:e})=>this.layOutBookmark(e),s(()=>[t.bookmarked,i.layersLoaded,this.booth.skipDim],()=>this.update(t.bookmarked),{fireImmediately:t.bookmarked}),s(()=>a.mapSettings,({roll:e})=>{l(e??0)&&(this.shape.onRoll=({roll:n,pixelSize:m})=>{const r=c(n,this.rect.rotation);if(r!==0)return this.rect=f(this.rect,r),this.layOutBookmark(m),[this.shape]})},{fireImmediately:!0})}update(t){i.layersLoaded&&(this.shape.hidden=!t,this.shape.dim=this.booth.skipDim?0:void 0,p(this.shape))}layOutBookmark(t){return this.shape.bounds=u(this.rect,B(h),this.padding,t),this.shape.hidden?[]:[this.shape]}}const h=11;
@@ -3,7 +3,7 @@ import { type FontSizeFactor } from '../../../../engine/defs';
3
3
  import { type Booth, SpecialBooth } from '../../../../store/BoothStore';
4
4
  import { BoothLabelDrawer } from './config-booth-labels';
5
5
  export default function configBoothLabelsSpecial(booth: Booth): BoothLabelSpecialDrawer | undefined;
6
- declare class BoothLabelSpecialDrawer extends BoothLabelDrawer {
6
+ export declare class BoothLabelSpecialDrawer extends BoothLabelDrawer {
7
7
  protected steps: FontSizeFactor[];
8
8
  protected labelIsVertical: boolean;
9
9
  protected text: string;
@@ -12,18 +12,17 @@ declare class BoothLabelSpecialDrawer extends BoothLabelDrawer {
12
12
  /**
13
13
  * Lays a special booth's label out: the text fitter's steps are indexed by the inverse pixel size,
14
14
  * and a plan too far out for the smallest step drops the label to nothing.
15
- * @param pixelSize - Plan units per device pixel.
15
+ * @param pixelSize - Plan units per CSS pixel.
16
16
  * @returns Always the label; every step writes the line, and the fitter's text may change with it.
17
17
  */
18
18
  layOutLabel(pixelSize: number): TextDef[];
19
19
  /**
20
20
  * Lays a special booth's dot out: it stands in for the label exactly when no step fits.
21
- * @param pixelSize - Plan units per device pixel.
21
+ * @param pixelSize - Plan units per CSS pixel.
22
22
  * @returns Always the dot; the bounds are rewritten on every step.
23
23
  */
24
24
  layOutDot(pixelSize: number): ImageDef[];
25
25
  setFactors(text: string): void;
26
26
  setText(): void;
27
27
  }
28
- export {};
29
28
  //# sourceMappingURL=config-booth-labels-special.d.ts.map
@@ -1,2 +1,2 @@
1
- import{Rect as u}from"@expofp/geometry";import{update as L}from"@expofp/renderer";import{reaction as m}from"mobx";import{FONT_WEIGHT_PRIMARY_BOOTH as g,FONT_WEIGHT_PRIMARY_SPECIAL as y}from"../../../../constants";import{createTextDef as F}from"../../../../engine/defs";import{loadCustomFontsUrls as D}from"../../../../engine/fonts";import{getQuarterTurns as x,getRollValue as S,rotateRectByQuarters as R,rotateTextDefByQuarters as T,shouldFlip as v}from"../../../../engine/update-def";import{heatmapStore as B,layersStore as I,uiState as f}from"../../../../store";import{SpecialBooth as z}from"../../../../store/BoothStore";import{eventScopedCache as C}from"../../../../tools/event-scoped-cache.js";import O from"../../../../tools/settings";import{getFont as w}from"./canvases";import{BoothLabelDrawer as M,getFontUrlByWeight as P,getMinZoomFactorForDot as _}from"./config-booth-labels";import{LABEL_MARGIN_FRACTION as b}from"./label-inset.js";import A from"./TextFitter";const l=C();function N(i){let t=l().get(i);if(!t){const s=[18,16,14,12,10,7].map(o=>o*i),e=14*i;t=new A(w,s,e),l().set(i,t),setTimeout(()=>l().delete(i),5e3)}return t}export default function V(i){if(!(!(i instanceof z)||i.noLabels))return new k(i)}class k extends M{constructor(t){super(t),this.steps=[],this.text="";const s=this.booth.rect,e=Number(getComputedStyle(document.body).getPropertyValue(y))||Number(getComputedStyle(document.body).getPropertyValue(g))||500,o=P(e,D()),r=s.expand({x:-(s.size.width*b+this.padding),y:-(s.size.height*b+this.padding)});this.setText(),this.canvasRect=new u(r.center,r.size,t.rotate,t.elevation),this.setFactors(this.text),this.labelIsVertical=Math.abs(Math.abs(t.rotate)-Math.PI/2)<.01,this.fontSizes=[this.steps,[]],this.minZoomDotVisible=_(this.steps.map(a=>a.scaleFactor)),this.shapeLabel=F([{text:this.text,color:t.labelColor||O.boothLabelColor,fontUrl:o,fontSize:0}],new u(r.center,r.size,t.rotate,t.elevation),[this.padding,this.padding],{horizontal:"center",text:"center",vertical:"center"}),this.shapeLabel.onScale=({pixelSize:a})=>this.layOutLabel(a),this.getShapeDot(),m(()=>I.layersLoaded&&this.booth.skipDim===!0,a=>{this.shapeLabel.dim=a?0:void 0,this.shapeDot.dim=a?0:void 0,L(this.shapeLabel,this.shapeDot)}),m(()=>f.mapSettings,({roll:a})=>{S(a??0)&&(this.shapeLabel.onRoll=({roll:c,pixelSize:p})=>{const h=this.shapeLabel.bounds.rotation;if(this.labelIsVertical)return v(c,h)?(this.shapeLabel.bounds.rotate(-2*h,this.shapeLabel.bounds),[this.shapeLabel,this.shapeDot]):void 0;const n=x(c,h);if(n===0)return;const{size:d}=this.canvasRect;return this.shapeLabel=T(this.shapeLabel,n),d.x!==d.y&&!this.shapeLabel.hidden&&(this.canvasRect=R(this.canvasRect,n),this.setFactors(this.text),this.layOutLabel(p),this.layOutDot(p)),[this.shapeLabel,this.shapeDot]})},{fireImmediately:!0})}getShape(){return[this.shapeLabel,this.shapeDot]}layOutLabel(t){const s=this.steps.find(e=>e.scaleFactor<1/t);return s?(this.shapeLabel.lines[0].fontSize=s.value*t,this.shapeLabel.lines[0].text=s.lines.join(`
2
- `),this.shapeLabel.padding=[this.paddingScaled[0]*t+this.padding,this.paddingScaled[1]*t+this.padding],[this.shapeLabel]):(this.shapeLabel.lines[0].fontSize=0,[this.shapeLabel])}layOutDot(t){const s=this.steps.find(r=>r.scaleFactor<1/t),e=this.shapeDot.bounds,o=this.shapeDot.source;return e.scale({x:o.width*t/e.size.x,y:o.height*t/e.size.y},e.center,e),this.shapeDot.hidden=!!s,[this.shapeDot]}setFactors(t){this.steps=N(devicePixelRatio).getStepsForRect(t,this.canvasRect.size.x,this.canvasRect.size.y)}setText(){const t=this.booth.title||this.booth.name,e=`Clicks: ${B.getTotalClicksByBooth(this.booth)}`;this.text=f.heatmap?`${t} - ${e}`:t}}
1
+ import{Rect as d}from"@expofp/geometry";import{update as L}from"@expofp/renderer";import{reaction as u}from"mobx";import{FONT_WEIGHT_PRIMARY_BOOTH as g,FONT_WEIGHT_PRIMARY_SPECIAL as y}from"../../../../constants";import{createTextDef as S,SHAPE_DOT_CSS_PX as m}from"../../../../engine/defs";import{loadCustomFontsUrls as F}from"../../../../engine/fonts";import{getQuarterTurns as R,getRollValue as x,rotateRectByQuarters as D,rotateTextDefByQuarters as T,shouldFlip as _}from"../../../../engine/update-def";import{heatmapStore as I,layersStore as O,uiState as b}from"../../../../store";import{SpecialBooth as B}from"../../../../store/BoothStore";import P from"../../../../tools/settings";import{getFont as v}from"./canvases";import{BoothLabelDrawer as C,getFontUrlByWeight as M,getMinZoomFactorForDot as N}from"./config-booth-labels";import{LABEL_MARGIN_FRACTION as f}from"./label-inset.js";import z from"./TextFitter";const A=[18,16,14,12,10,7],E=14;export default function w(i){if(!(!(i instanceof B)||i.noLabels))return new BoothLabelSpecialDrawer(i)}export class BoothLabelSpecialDrawer extends C{constructor(t){super(t),this.steps=[],this.text="";const s=this.booth.rect,e=Number(getComputedStyle(document.body).getPropertyValue(y))||Number(getComputedStyle(document.body).getPropertyValue(g))||500,r=M(e,F()),o=s.expand({x:-(s.size.width*f+this.padding),y:-(s.size.height*f+this.padding)});this.setText(),this.canvasRect=new d(o.center,o.size,t.rotate,t.elevation),this.setFactors(this.text),this.labelIsVertical=Math.abs(Math.abs(t.rotate)-Math.PI/2)<.01,this.fontSizes=[this.steps,[]],this.minZoomDotVisible=N(this.steps.map(a=>a.scaleFactor)),this.shapeLabel=S([{text:this.text,color:t.labelColor||P.boothLabelColor,fontUrl:r,fontSize:0}],new d(o.center,o.size,t.rotate,t.elevation),[this.padding,this.padding],{horizontal:"center",text:"center",vertical:"center"}),this.shapeLabel.onScale=({pixelSize:a})=>this.layOutLabel(a),this.getShapeDot(),u(()=>O.layersLoaded&&this.booth.skipDim===!0,a=>{this.shapeLabel.dim=a?0:void 0,this.shapeDot.dim=a?0:void 0,L(this.shapeLabel,this.shapeDot)}),u(()=>b.mapSettings,({roll:a})=>{x(a??0)&&(this.shapeLabel.onRoll=({roll:l,pixelSize:c})=>{const h=this.shapeLabel.bounds.rotation;if(this.labelIsVertical)return _(l,h)?(this.shapeLabel.bounds.rotate(-2*h,this.shapeLabel.bounds),[this.shapeLabel,this.shapeDot]):void 0;const n=R(l,h);if(n===0)return;const{size:p}=this.canvasRect;return this.shapeLabel=T(this.shapeLabel,n),p.x!==p.y&&!this.shapeLabel.hidden&&(this.canvasRect=D(this.canvasRect,n),this.setFactors(this.text),this.layOutLabel(c),this.layOutDot(c)),[this.shapeLabel,this.shapeDot]})},{fireImmediately:!0})}getShape(){return[this.shapeLabel,this.shapeDot]}layOutLabel(t){const s=this.steps.find(e=>e.scaleFactor<1/t);return s?(this.shapeLabel.lines[0].fontSize=s.value*t,this.shapeLabel.lines[0].text=s.lines.join(`
2
+ `),this.shapeLabel.padding=[this.paddingScaled[0]*t+this.padding,this.paddingScaled[1]*t+this.padding],[this.shapeLabel]):(this.shapeLabel.lines[0].fontSize=0,[this.shapeLabel])}layOutDot(t){const s=this.steps.find(r=>r.scaleFactor<1/t),e=this.shapeDot.bounds;return e.scale({x:m*t/e.size.x,y:m*t/e.size.y},e.center,e),this.shapeDot.hidden=!!s,[this.shapeDot]}setFactors(t){this.steps=new z(v,A,E).getStepsForRect(t,this.canvasRect.size.x,this.canvasRect.size.y)}setText(){const t=this.booth.title||this.booth.name,e=`Clicks: ${I.getTotalClicksByBooth(this.booth)}`;this.text=b.heatmap?`${t} - ${e}`:t}}
@@ -41,14 +41,14 @@ export declare class BoothLabelDrawer extends BoothDrawerBaseWithoutPainter {
41
41
  /**
42
42
  * Lays this booth's label out for a new pixel size: the font-size step, the alignment that follows
43
43
  * it, and the padding that scales with it.
44
- * @param pixelSize - Plan units per device pixel.
44
+ * @param pixelSize - Plan units per CSS pixel.
45
45
  * @returns The label when it moved, empty when nothing changed so the renderer skips the write.
46
46
  */
47
47
  layOutLabel(pixelSize: number): TextDef[];
48
48
  /**
49
49
  * Lays this booth's dot out for a new pixel size: it is drawn only in the band between the zoom
50
50
  * where the label stops fitting and the zoom where the dot itself would overflow the booth.
51
- * @param pixelSize - Plan units per device pixel.
51
+ * @param pixelSize - Plan units per CSS pixel.
52
52
  * @returns The dot when it moved, empty when nothing changed so the renderer skips the write.
53
53
  */
54
54
  layOutDot(pixelSize: number): ImageDef[];
@@ -1 +1 @@
1
- import{Rect as E}from"@expofp/geometry";import{update as H}from"@expofp/renderer";import{FONT_WEIGHT_PRIMARY_BOOTH as U,FONT_WEIGHT_PRIMARY_EXHIBITOR as V,FONT_WEIGHT_SECONDARY_BOOTH as Z,FONT_WEIGHT_SECONDARY_EXHIBITOR as X}from"../../../../constants";import c from"../../../../data";import{createShapeDot as G,createTextDef as Y,createTextDefLines as Q}from"../../../../engine/defs";import{DEFAULT_FONT_LIGHT_URL as $,DEFAULT_FONT_URL as B,loadCustomFontsUrls as q}from"../../../../engine/fonts";import{getQuarterTurns as j,getRollValue as k,rotateRectByQuarters as J,rotateTextDefByQuarters as K,updateLinesScale as tt}from"../../../../engine/update-def";import{boothStore as et,layersStore as it,uiState as f}from"../../../../store";import{RegularBooth as st,SpecialBooth as ot}from"../../../../store/BoothStore";import D from"../../../../tools/settings";import{t as S}from"../../../../utils/i18n";import nt from"../../../../utils/is-mobile";import at from"../../../../utils/is-webview";import{planReaction as M}from"../../../../utils/plan-reactions.js";import{isArabicText as rt}from"../../../../utils/rtl";import{BoothDrawerBaseWithoutPainter as ht}from"./BoothDrawerBase";import{getFont as W}from"./canvases";import{getLabelBorderInset as lt}from"./label-inset.js";function _(){return D.EXPO==="tqs2021"?"#000":D.boothLabelColor}const x=nt||at,z=n=>n.replace(" ","").substring(0,4).replace(/[0-9]/g,"3").replace(/[A-Z]/gi,"A"),I=document.createElement("canvas").getContext("2d");export default function ct(n){if(!(!(n instanceof st)||n.noLabels))return new BoothLabelDrawer(n)}export function getMinZoomFactorForDot(n){return Array.isArray(n)&&n.length>0?Math.max(...n.map(t=>t)):typeof n=="number"?n:-0}export const isDirectionsMode=()=>!!(f.selectedRoute?.from&&f.selectedRoute?.to);export function getFontUrlByWeight(n,t=[],e="normal"){return[...t,{weight:500,url:B,style:"normal"},{weight:300,url:$,style:"normal"}].find(s=>+s.weight===n&&s.style===e)?.url||B}function b(n,t){return Number(getComputedStyle(document.body).getPropertyValue(n))||t}export function getBoothLabelWeights(){return{main:b(U,500),details:b(Z,300)}}export function getExhibitorLabelWeights(){return{main:b(V,500),details:b(X,300)}}export function getBadgeFontWeight(){return getExhibitorLabelWeights().details}const F="Details";export class BoothLabelDrawer extends ht{constructor(t){super(t),this.minZoomDotVisible=0,this.maxZoomDotVisible=0,this.exh=[],this.shapeLabel=void 0,this.shapeDot=void 0,this.fontSizes=[[],[]],this.lines=[[],[]],this.fontUrls=["",""],this.canvasRect=new E(t.rect.center,t.rect.size,t.rotate,t.elevation),this.paddingScaled=[4,4],this.padding=lt(t.borderWidth||et.borderWidth,t.rect.size),this.topLeftAlignment={horizontal:f.rtl?"right":"left",vertical:"top"},this.centerAlignment={horizontal:"center",vertical:"center"},this.prefixes=x?[{fontSize:7,name:"XS",short:!0},{fontSize:10,name:"S",short:!0},{fontSize:16,name:F,short:!1}]:[{fontSize:7,name:"XS",short:!0},{fontSize:10,name:"S",short:!0},{fontSize:12,name:"M",short:!0},{fontSize:14,name:"L",short:!0},{fontSize:18,name:F,short:!1}],!(t instanceof ot)&&(this.exh=c.hideExhibitors?[]:c.onlyFeaturedExhibitors?t.exhibitors.filter(e=>e.featured):t.exhibitors,x&&this.optimizationLevel()>=3&&(this.prefixes=this.prefixes.filter(e=>e.name!=="S")),this.createLines(),this.calculateFontSizeFactors(),this.shapeLabel=Y(Q(this.lines,this.booth.labelColor||_(),0,this.fontUrls),new E(this.booth.rect.center,this.booth.rect.size,this.booth.rotate,this.booth.elevation),[...this.paddingScaled],{horizontal:"left",vertical:"top"}),this.shapeLabel.onScale=({pixelSize:e})=>this.layOutLabel(e),this.getShapeDot(),M(()=>it.layersLoaded&&this.booth.skipDim===!0,e=>{this.shapeLabel.dim=e?0:void 0,this.shapeDot.dim=e?0:void 0,H(this.shapeLabel,this.shapeDot)}),M(()=>f.mapSettings,({roll:e})=>{k(e??0)&&(this.shapeLabel.onRoll=({roll:i,pixelSize:a})=>{const s=j(i,this.shapeLabel.bounds.rotation);if(s===0)return;const{size:r}=this.canvasRect;return this.shapeLabel=K(this.shapeLabel,s),!this.shapeLabel.hidden&&!this.exh.length&&r.x!==r.y&&(this.canvasRect=J(this.canvasRect,s),this.calculateFontSizeFactors(),this.layOutLabel(a),this.layOutDot(a)),[this.shapeLabel,this.shapeDot]})},{fireImmediately:!0}))}getShape(){return[this.shapeLabel,this.shapeDot]}layOutLabel(t){const e=this.lines[1]??[],i=this.fontSizes[1]??[];if(D.EXPO!=="wineparis2026"){const s=this.exh.length?this.topLeftAlignment:e.length?t<i[i.length-1].scaleFactor?this.topLeftAlignment:this.centerAlignment:this.topLeftAlignment;this.shapeLabel.alignment=s}return tt(this.shapeLabel.lines,t,this.fontSizes)?(this.shapeLabel.padding[0]=this.paddingScaled[0]*t+this.padding,this.shapeLabel.padding[1]=this.paddingScaled[1]*t+this.padding,[this.shapeLabel]):[]}layOutDot(t){const e=t>=this.minZoomDotVisible&&t<=this.maxZoomDotVisible;if(!e&&this.shapeDot.hidden)return[];const i=this.shapeDot.bounds,a=this.shapeDot.source;return i.scale({x:a.width*t/i.size.x,y:a.height*t/i.size.y},i.center,i),this.shapeDot.hidden=!e,[this.shapeDot]}getShapeDot(){this.shapeDot=G(this.canvasRect,this.booth.labelColor||_()),this.shapeDot.hidden=!0,this.shapeDot.onScale=({pixelSize:e})=>this.layOutDot(e);const t=this.shapeDot.source;this.maxZoomDotVisible=Math.min(this.canvasRect.size.x/t.width,this.canvasRect.size.y/t.height)}createLines(){const t=this.booth,e=[],i=[],a=x&&this.optimizationLevel()>=3?1:3;if(this.exh.length){const s=t.exhibitors.filter(o=>o.order===0),r=t.exhibitors.filter(o=>o.order);if(s.length>0)e.push(...s.map(o=>o.name));else if(c.onlyFeaturedExhibitors)e.push(...t.exhibitors.filter(o=>o.featured).map(o=>o.name));else if(r.length>0){e.push(...r.map(m=>m.name));const o=t.exhibitors.filter(m=>m.order===void 0);o.length>0&&e.push(S("and {{moreCount}} more",{moreCount:o.length}))}else t.exhibitors.length>a?e.push(`${t.exhibitors.length} ${c.exhibitorTermPlural}`):e.push(...t.exhibitors.map(o=>o.name));i.push(t.title||t.name)}else{const s=!!t.exhibitors.length;e.push(t.title||t.name),t.onHold?i.push(S("On Hold")):t.reserved?i.push(S("Reserved")):s||i.push(...t.exhibitors.map(r=>r.name).sort((r,o)=>r>o?1:-1)),t.size&&i.push(t.size.indexOf("/")>-1?t.size.substring(0,t.size.indexOf("/")).trim():t.size),t.price&&t.price!=="0"&&!f.previewMode&&i.push(t.price)}f.rtl&&e.forEach((s,r)=>{(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))&&(e[r]=e[r]+"\u200F"),rt(s)&&(e[r]=e[r]+" ")}),this.lines=[e,i]}calculateFontSizeFactors(){const t=this.lines[0];let e;const i=this.canvasRect,a=[],s=[],r=this.prefixes.slice(0,this.exh.length?this.prefixes.length:this.prefixes.length-1),{main:o,details:m}=this.exh.length?getExhibitorLabelWeights():getBoothLabelWeights();for(const{fontSize:l,short:u}of r){const p=l*devicePixelRatio,L=.9*l*devicePixelRatio,d=W(p,o),R=W(L,m),T=c.hideExhibitorBoothNumber||u;let O,w,v,g;if(this.exh.length)e=u?[]:this.lines[1],v=Math.max(...t.map(h=>this.measureText(h,d).width),...e.map(h=>this.measureText(h,R).width)),O=Math.max(...t.map(h=>this.exh.length?this.measureText(z(h),d).width:this.measureText(z(h),d).width+3+3),...e.map(h=>this.measureText(z(h),R).width)),g=p*t.length+L*e.length+devicePixelRatio*(t.length+e.length)+3,w=T?g/t.length:null;else{const h=t[0].replace(/[0-9]/g,"3").replace(/[A-Z]/g,"A"),N=4;v=this.measureText(h,d).width+3+3,g=p+N}const P=i.size.x/(O||v),C=i.size.y/(w||g),A=Math.min(P,C);a.push({scaleFactor:A,value:p,lines:[]}),T||s.push({scaleFactor:A,value:L,lines:[]})}if(!this.exh.length){const l=a[a.length-1],u=this.prefixes.find(p=>p.name===F);u&&(a.push({scaleFactor:l.scaleFactor/1.8,value:u.fontSize*devicePixelRatio,lines:[]}),s.push({scaleFactor:l.scaleFactor/1.8,value:u.fontSize*(x?1:.9)*devicePixelRatio,lines:[]}))}const y=q();this.fontUrls=[getFontUrlByWeight(o,y),getFontUrlByWeight(m,y)],this.minZoomDotVisible=getMinZoomFactorForDot(a.map(l=>l.scaleFactor)),this.fontSizes=[a,s]}calcArea(t,e){return Math.floor(Math.max(0,t)*Math.max(0,e)/1e3)}optimizationLevel(){return Math.min(c.viewOptimizationLevel?c.viewOptimizationLevel:Math.floor(this.calcArea(this.canvasRect.size.x,this.canvasRect.size.y)/5e3),3)}measureText(t,e){return I.font=e,I.measureText(t)}}
1
+ import{Rect as _}from"@expofp/geometry";import{update as U}from"@expofp/renderer";import{FONT_WEIGHT_PRIMARY_BOOTH as V,FONT_WEIGHT_PRIMARY_EXHIBITOR as Z,FONT_WEIGHT_SECONDARY_BOOTH as X,FONT_WEIGHT_SECONDARY_EXHIBITOR as G}from"../../../../constants";import c from"../../../../data";import{createShapeDot as Y,createTextDef as Q,createTextDefLines as $,SHAPE_DOT_CSS_PX as b}from"../../../../engine/defs";import{DEFAULT_FONT_LIGHT_URL as q,DEFAULT_FONT_URL as B,loadCustomFontsUrls as j}from"../../../../engine/fonts";import{getQuarterTurns as k,getRollValue as J,rotateRectByQuarters as K,rotateTextDefByQuarters as tt,updateLinesScale as et}from"../../../../engine/update-def";import{boothStore as it,layersStore as st,uiState as p}from"../../../../store";import{RegularBooth as nt,SpecialBooth as ot}from"../../../../store/BoothStore";import D from"../../../../tools/settings";import{t as F}from"../../../../utils/i18n";import rt from"../../../../utils/is-mobile";import at from"../../../../utils/is-webview";import{planReaction as M}from"../../../../utils/plan-reactions.js";import{isArabicText as ht}from"../../../../utils/rtl";import{BoothDrawerBaseWithoutPainter as lt}from"./BoothDrawerBase";import{getFont as W}from"./canvases";import{getLabelBorderInset as ct}from"./label-inset.js";function I(){return D.EXPO==="tqs2021"?"#000":D.boothLabelColor}const x=rt||at,v=o=>o.replace(" ","").substring(0,4).replace(/[0-9]/g,"3").replace(/[A-Z]/gi,"A"),C=document.createElement("canvas").getContext("2d");export default function mt(o){if(!(!(o instanceof nt)||o.noLabels))return new BoothLabelDrawer(o)}export function getMinZoomFactorForDot(o){return Array.isArray(o)&&o.length>0?Math.max(...o.map(t=>t)):typeof o=="number"?o:-0}export const isDirectionsMode=()=>!!(p.selectedRoute?.from&&p.selectedRoute?.to);export function getFontUrlByWeight(o,t=[],e="normal"){return[...t,{weight:500,url:B,style:"normal"},{weight:300,url:q,style:"normal"}].find(s=>+s.weight===o&&s.style===e)?.url||B}function L(o,t){return Number(getComputedStyle(document.body).getPropertyValue(o))||t}export function getBoothLabelWeights(){return{main:L(V,500),details:L(X,300)}}export function getExhibitorLabelWeights(){return{main:L(Z,500),details:L(G,300)}}export function getBadgeFontWeight(){return getExhibitorLabelWeights().details}const y="Details";export class BoothLabelDrawer extends lt{constructor(t){super(t),this.minZoomDotVisible=0,this.maxZoomDotVisible=0,this.exh=[],this.shapeLabel=void 0,this.shapeDot=void 0,this.fontSizes=[[],[]],this.lines=[[],[]],this.fontUrls=["",""],this.canvasRect=new _(t.rect.center,t.rect.size,t.rotate,t.elevation),this.paddingScaled=[4,4],this.padding=ct(t.borderWidth||it.borderWidth,t.rect.size),this.topLeftAlignment={horizontal:p.rtl?"right":"left",vertical:"top"},this.centerAlignment={horizontal:"center",vertical:"center"},this.prefixes=x?[{fontSize:7,name:"XS",short:!0},{fontSize:10,name:"S",short:!0},{fontSize:16,name:y,short:!1}]:[{fontSize:7,name:"XS",short:!0},{fontSize:10,name:"S",short:!0},{fontSize:12,name:"M",short:!0},{fontSize:14,name:"L",short:!0},{fontSize:18,name:y,short:!1}],!(t instanceof ot)&&(this.exh=c.hideExhibitors?[]:c.onlyFeaturedExhibitors?t.exhibitors.filter(e=>e.featured):t.exhibitors,x&&this.optimizationLevel()>=3&&(this.prefixes=this.prefixes.filter(e=>e.name!=="S")),this.createLines(),this.calculateFontSizeFactors(),this.shapeLabel=Q($(this.lines,this.booth.labelColor||I(),0,this.fontUrls),new _(this.booth.rect.center,this.booth.rect.size,this.booth.rotate,this.booth.elevation),[...this.paddingScaled],{horizontal:"left",vertical:"top"}),this.shapeLabel.onScale=({pixelSize:e})=>this.layOutLabel(e),this.getShapeDot(),M(()=>st.layersLoaded&&this.booth.skipDim===!0,e=>{this.shapeLabel.dim=e?0:void 0,this.shapeDot.dim=e?0:void 0,U(this.shapeLabel,this.shapeDot)}),M(()=>p.mapSettings,({roll:e})=>{J(e??0)&&(this.shapeLabel.onRoll=({roll:i,pixelSize:a})=>{const s=k(i,this.shapeLabel.bounds.rotation);if(s===0)return;const{size:r}=this.canvasRect;return this.shapeLabel=tt(this.shapeLabel,s),!this.shapeLabel.hidden&&!this.exh.length&&r.x!==r.y&&(this.canvasRect=K(this.canvasRect,s),this.calculateFontSizeFactors(),this.layOutLabel(a),this.layOutDot(a)),[this.shapeLabel,this.shapeDot]})},{fireImmediately:!0}))}getShape(){return[this.shapeLabel,this.shapeDot]}layOutLabel(t){const e=this.lines[1]??[],i=this.fontSizes[1]??[];if(D.EXPO!=="wineparis2026"){const s=this.exh.length?this.topLeftAlignment:e.length?t<i[i.length-1].scaleFactor?this.topLeftAlignment:this.centerAlignment:this.topLeftAlignment;this.shapeLabel.alignment=s}return et(this.shapeLabel.lines,t,this.fontSizes)?(this.shapeLabel.padding[0]=this.paddingScaled[0]*t+this.padding,this.shapeLabel.padding[1]=this.paddingScaled[1]*t+this.padding,[this.shapeLabel]):[]}layOutDot(t){const e=t>=this.minZoomDotVisible&&t<=this.maxZoomDotVisible;if(!e&&this.shapeDot.hidden)return[];const i=this.shapeDot.bounds;return i.scale({x:b*t/i.size.x,y:b*t/i.size.y},i.center,i),this.shapeDot.hidden=!e,[this.shapeDot]}getShapeDot(){this.shapeDot=Y(this.canvasRect,this.booth.labelColor||I()),this.shapeDot.hidden=!0,this.shapeDot.onScale=({pixelSize:t})=>this.layOutDot(t),this.maxZoomDotVisible=Math.min(this.canvasRect.size.x/b,this.canvasRect.size.y/b)}createLines(){const t=this.booth,e=[],i=[],a=x&&this.optimizationLevel()>=3?1:3;if(this.exh.length){const s=t.exhibitors.filter(n=>n.order===0),r=t.exhibitors.filter(n=>n.order);if(s.length>0)e.push(...s.map(n=>n.name));else if(c.onlyFeaturedExhibitors)e.push(...t.exhibitors.filter(n=>n.featured).map(n=>n.name));else if(r.length>0){e.push(...r.map(m=>m.name));const n=t.exhibitors.filter(m=>m.order===void 0);n.length>0&&e.push(F("and {{moreCount}} more",{moreCount:n.length}))}else t.exhibitors.length>a?e.push(`${t.exhibitors.length} ${c.exhibitorTermPlural}`):e.push(...t.exhibitors.map(n=>n.name));i.push(t.title||t.name)}else{const s=!!t.exhibitors.length;e.push(t.title||t.name),t.onHold?i.push(F("On Hold")):t.reserved?i.push(F("Reserved")):s||i.push(...t.exhibitors.map(r=>r.name).sort((r,n)=>r>n?1:-1)),t.size&&i.push(t.size.indexOf("/")>-1?t.size.substring(0,t.size.indexOf("/")).trim():t.size),t.price&&t.price!=="0"&&!p.previewMode&&i.push(t.price)}p.rtl&&e.forEach((s,r)=>{(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))&&(e[r]=e[r]+"\u200F"),ht(s)&&(e[r]=e[r]+" ")}),this.lines=[e,i]}calculateFontSizeFactors(){const t=this.lines[0];let e;const i=this.canvasRect,a=[],s=[],r=this.prefixes.slice(0,this.exh.length?this.prefixes.length:this.prefixes.length-1),{main:n,details:m}=this.exh.length?getExhibitorLabelWeights():getBoothLabelWeights();for(const{fontSize:l,short:u}of r){const f=l,S=.9*l,d=W(f,n),O=W(S,m),R=c.hideExhibitorBoothNumber||u;let w,A,z,g;if(this.exh.length)e=u?[]:this.lines[1],z=Math.max(...t.map(h=>this.measureText(h,d).width),...e.map(h=>this.measureText(h,O).width)),w=Math.max(...t.map(h=>this.exh.length?this.measureText(v(h),d).width:this.measureText(v(h),d).width+3+3),...e.map(h=>this.measureText(v(h),O).width)),g=f*t.length+S*e.length+(t.length+e.length)+3,A=R?g/t.length:null;else{const h=t[0].replace(/[0-9]/g,"3").replace(/[A-Z]/g,"A"),P=4;z=this.measureText(h,d).width+3+3,g=f+P}const H=i.size.x/(w||z),N=i.size.y/(A||g),E=Math.min(H,N);a.push({scaleFactor:E,value:f,lines:[]}),R||s.push({scaleFactor:E,value:S,lines:[]})}if(!this.exh.length){const l=a[a.length-1],u=this.prefixes.find(f=>f.name===y);u&&(a.push({scaleFactor:l.scaleFactor/1.8,value:u.fontSize,lines:[]}),s.push({scaleFactor:l.scaleFactor/1.8,value:u.fontSize*(x?1:.9),lines:[]}))}const T=j();this.fontUrls=[getFontUrlByWeight(n,T),getFontUrlByWeight(m,T)],this.minZoomDotVisible=getMinZoomFactorForDot(a.map(l=>l.scaleFactor)),this.fontSizes=[a,s]}calcArea(t,e){return Math.floor(Math.max(0,t)*Math.max(0,e)/1e3)}optimizationLevel(){return Math.min(c.viewOptimizationLevel?c.viewOptimizationLevel:Math.floor(this.calcArea(this.canvasRect.size.x,this.canvasRect.size.y)/5e3),3)}measureText(t,e){return C.font=e,C.measureText(t)}}
@@ -1,4 +1,4 @@
1
- import { type SceneDef } from '@expofp/renderer';
1
+ import { type ImageDef, type RenderableDef, type SceneDef } from '@expofp/renderer';
2
2
  import { type FloorPlanMarkerEvent } from '../../../../types';
3
3
  export declare const MARKER_LAYER_NAME = "markers";
4
4
  /** What {@link configMarkers} needs: the scene whose root layers hold the marker layer. */
@@ -6,6 +6,22 @@ export interface MarkerOptions {
6
6
  /** The scene markers are drawn into; `config-all` pre-creates their layer in it. */
7
7
  readonly scene: SceneDef;
8
8
  }
9
+ /**
10
+ * Sizes one marker for a new pixel size — the `onScale` every marker def declares.
11
+ *
12
+ * One function for every marker on the plan, reached through each marker's own `onScale` closure
13
+ * and driven directly by the imperative bridge. Idempotent, because the center and rotation it
14
+ * reads back are the ones it wrote.
15
+ * @param marker - The marker to size.
16
+ * @param size - The icon's size in CSS pixels. Not the canvas's: that is rasterized at the device
17
+ * ratio.
18
+ * @param pixelSize - Plan units per CSS pixel.
19
+ * @returns The def, which always moves — a marker holds its on-screen size at every zoom.
20
+ */
21
+ export declare function rescaleMarker(marker: ImageDef, size: {
22
+ readonly width: number;
23
+ readonly height: number;
24
+ }, pixelSize: number): readonly RenderableDef[];
9
25
  /**
10
26
  * Draws the plan's markers into a renderer scene and keeps them current with the store.
11
27
  * @param options - The scene to draw into.
@@ -1 +1 @@
1
- import{Box as K}from"@expofp/geometry";import{update as v}from"@expofp/renderer";import{reaction as E}from"mobx";import{getBounds as y}from"../../../../engine/canvases";import{createImageDef as R}from"../../../../engine/defs";import l,{layersStore as P,uiState as N}from"../../../../store";import{setMarkerResolver as C}from"../../pointer";import{createImageCanvas as O}from"./canvases";const L="_selected";export const MARKER_LAYER_NAME="markers";function T(r,f){const{center:c,rotation:o,elevation:d}=r.bounds,{width:i,height:s}=r.source;return r.bounds=y(c.x,c.y,i,s,f,o,d),[r]}function V(r){w=r}export function configMarkers(r){const{scene:f}=r,c=[],o=new Map,d=new Map;let i=[];const s=f.rootLayer.children.find(e=>e.name===MARKER_LAYER_NAME);s.onScale=({pixelSize:e})=>V(e),C(markerAt),v(s);async function p(e){const n=[];e.forEach(u=>{const{name:a,content:t,width:h,height:D,scale:g}=u;if(o.has(a))return;const m=new Image,S=new Promise((M,b)=>{m.onload=()=>{o.set(a,{img:m,width:h,height:D,scale:g}),M()},m.onerror=x=>{b(x)}});n.push(S),m.src=t,m.crossOrigin="anonymous"}),await Promise.all(n)}const B=e=>{e.onScale=({pixelSize:n})=>T(e,n)},z=e=>{e.screenSpace||(e.onRoll=({roll:n})=>{if(n!==e.bounds.rotation)return e.bounds.rotate(n-e.bounds.rotation,e.bounds),[e]})};function I(e,n,u){const a=d.get(e);if(a)return a;const t=O(n.img,n.width,n.height,u);return d.set(e,t),t}function A(){const e=l.routeStore.markersData.markers;if(!e.length)return;i=[];const n=1,u=0,a=N.is3DView;e.forEach(t=>{const h=o.get(t.icon);if(!h)return;const D=o.get(t.selectedIcon);if(!D)return;const g=h.scale||window.devicePixelRatio,m=I(t.icon,h,g),S=I(t.selectedIcon,D,g),M=P.findLayer(t.z)?.visible??!0,b=y(t.x,t.y,m.width,m.height,n,u),x=y(t.x,t.y,S.width,S.height,n,u);let k;switch(t.position){case"lefttop":k=[0,0];break;case"centertop":k=[.5,0];break;case"centerbottom":k=[.5,1];break;default:k=[.5,.5]}const F={...R(m,b,{hidden:!M,origin:k}),id:t.id,scale:g,screenSpace:a},H={...R(S,x,{hidden:!(M&&t.active),origin:k}),id:`${t.id}${L}`,scale:g,screenSpace:a};i.push(F,H)}),s.children=i,i.forEach(t=>{B(t),z(t)})}function _(){s.children=[],i=[]}function $(){const e=l.routeStore.markersData.markers;e.length&&e.forEach(n=>{const u=i.find(h=>h.id===n.id),a=i.find(h=>h.id===`${n.id}${L}`);if(!u||!a)return;const t=P.findLayer(n.z)?.visible??!0;n.active?(u.hidden=!0,a.hidden=!(t&&n.active)):(u.hidden=!t,a.hidden=!0)})}return c.push(E(()=>[l.routeStore.selectedMarkers,l.layerStore.visible],()=>{if(!l.routeStore.markersData.markers.length){_(),v(s);return}$(),v(...i)})),c.push(E(()=>l.routeStore.markersData.markers,()=>{p(l.routeStore.markersData.icons).then(()=>{A(),v(s)})},{fireImmediately:!0})),function(){c.forEach(n=>n()),c.length=0,s.onScale=void 0,C(),w=1,v(s)}}export function markerAt(r,f){return getMarkerFromClick(r,f,w)}export function getMarkerFromClick(r,f,c){for(const o of l.routeStore.markersData.markers){const d=l.routeStore.markersData.icons.find(p=>p.name===o.icon);if(!d)continue;const i=d.width*c*devicePixelRatio,s=d.height*c*devicePixelRatio;if(W(r,f,o.x,o.y,i,s)){const p=l.layerStore.findLayer(o.z);if(!p||p&&p.visible)return o}}return null}function W(r,f,c,o,d,i){return K.fromCenter({x:c,y:o},{x:2*d,y:2*i}).containsPoint({x:r,y:f})}let w=1;
1
+ import{Box as T}from"@expofp/geometry";import{update as M}from"@expofp/renderer";import{reaction as R}from"mobx";import{createImageDef as L}from"../../../../engine/defs";import f,{layersStore as P,uiState as V}from"../../../../store";import{setMarkerResolver as B}from"../../pointer";import{createImageCanvas as W,getBounds as x,imageCanvasCssSize as A}from"./canvases";const _="_selected";export const MARKER_LAYER_NAME="markers";export function rescaleMarker(s,h,u){const{center:r,rotation:a,elevation:o}=s.bounds,{width:i,height:m}=h;return s.bounds=x(r.x,r.y,i,m,u,a,o),[s]}function Y(s){y=s}export function configMarkers(s){const{scene:h}=s,u=[],r=new Map,a=new Map;let o=[];const i=h.rootLayer.children.find(e=>e.name===MARKER_LAYER_NAME);i.onScale=({pixelSize:e})=>Y(e),B(markerAt),M(i);async function m(e){const t=[];e.forEach(c=>{const{name:d,content:n,width:l,height:g,scale:k}=c;if(r.has(d))return;const p=new Image,w=new Promise((b,D)=>{p.onload=()=>{r.set(d,{img:p,width:l,height:g,scale:k}),b()},p.onerror=v=>{D(v)}});t.push(w),p.src=n,p.crossOrigin="anonymous"}),await Promise.all(t)}const I=(e,t)=>{e.onScale=({pixelSize:c})=>rescaleMarker(e,t,c)},$=e=>{e.screenSpace||(e.onRoll=({roll:t})=>{if(t!==e.bounds.rotation)return e.bounds.rotate(t-e.bounds.rotation,e.bounds),[e]})};function C(e,t){const c=a.get(e);if(c)return c;const d=W(t.img,t.width,t.height,window.devicePixelRatio,t.scale||1);return a.set(e,d),d}function F(){const e=f.routeStore.markersData.markers;if(!e.length)return;o=[];const t=1,c=0,d=V.is3DView;e.forEach(n=>{const l=r.get(n.icon);if(!l)return;const g=r.get(n.selectedIcon);if(!g)return;const k=l.scale||1,p=C(n.icon,l),w=C(n.selectedIcon,g),b=P.findLayer(n.z)?.visible??!0,D=A(l.img,l.width,l.height,k),v=A(g.img,g.width,g.height,k),N=x(n.x,n.y,D.width,D.height,t,c),O=x(n.x,n.y,v.width,v.height,t,c);let S;switch(n.position){case"lefttop":S=[0,0];break;case"centertop":S=[.5,0];break;case"centerbottom":S=[.5,1];break;default:S=[.5,.5]}const E={...L(p,N,{hidden:!b,origin:S}),id:n.id,scale:k,screenSpace:d},z={...L(w,O,{hidden:!(b&&n.active),origin:S}),id:`${n.id}${_}`,scale:k,screenSpace:d};I(E,D),I(z,v),o.push(E,z)}),i.children=o,o.forEach($)}function H(){i.children=[],o=[]}function K(){const e=f.routeStore.markersData.markers;e.length&&e.forEach(t=>{const c=o.find(l=>l.id===t.id),d=o.find(l=>l.id===`${t.id}${_}`);if(!c||!d)return;const n=P.findLayer(t.z)?.visible??!0;t.active?(c.hidden=!0,d.hidden=!(n&&t.active)):(c.hidden=!n,d.hidden=!0)})}return u.push(R(()=>[f.routeStore.selectedMarkers,f.layerStore.visible],()=>{if(!f.routeStore.markersData.markers.length){H(),M(i);return}K(),M(...o)})),u.push(R(()=>f.routeStore.markersData.markers,()=>{m(f.routeStore.markersData.icons).then(()=>{F(),M(i)})},{fireImmediately:!0})),function(){u.forEach(t=>t()),u.length=0,i.onScale=void 0,B(),y=1,M(i)}}export function markerAt(s,h){return getMarkerFromClick(s,h,y)}export function getMarkerFromClick(s,h,u){for(const r of f.routeStore.markersData.markers){const a=f.routeStore.markersData.icons.find(m=>m.name===r.icon);if(!a)continue;const o=a.width*(a.scale||1)*u,i=a.height*(a.scale||1)*u;if(j(s,h,r.x,r.y,o,i)){const m=f.layerStore.findLayer(r.z);if(!m||m&&m.visible)return r}}return null}function j(s,h,u,r,a,o){return T.fromCenter({x:u,y:r},{x:2*a,y:2*o}).containsPoint({x:s,y:h})}let y=1;
@@ -0,0 +1,40 @@
1
+ import { type LayerDef } from '@expofp/renderer';
2
+ /**
3
+ * Draws a pin over every booth an active POI-type search button selects, and draws the renderer's
4
+ * clusters of those pins from a pool of hidden markers.
5
+ *
6
+ * The pins key off `uiState.selectedPoiTypeFilters`, which is what both a single `poi_type` button
7
+ * and a `poi_types` group button write — so one filter or a whole group reaches this the same way.
8
+ *
9
+ * This module only *substitutes*. The renderer decides which pins collide, hides every pin in a
10
+ * cluster through its own `onPlace`, and reports the clusters to the pin layer's `clustering`. What
11
+ * this draws for a report is a pooled marker per cluster, in two sibling layers that declare neither
12
+ * `placement` nor `clustering`, so a marker can never be clustered as its own input.
13
+ *
14
+ * Nothing is created or destroyed on a camera move. The pins are built when the booth set changes,
15
+ * one per booth, and so is the pool: a cluster needs two pins, so `floor(n / 2)` markers is every
16
+ * marker a report can ask for. A report writes positions and counts onto defs already mounted, and
17
+ * no layer's `children` is reassigned by anything but a booth-set change.
18
+ *
19
+ * Takes the layers rather than the scene, so it runs in `config-all` beside the layers' creation:
20
+ * nothing here needs the renderer, and `update` before the scene mounts is a documented no-op that
21
+ * the mount's own full sync covers.
22
+ * @param pinLayer - The layer for pins, which `config-all` creates.
23
+ * @param clusterLayer - The layer for cluster teardrops, created directly above `pinLayer`.
24
+ * @param countLayer - The layer for cluster counts, created directly above `clusterLayer`.
25
+ * @returns A disposer.
26
+ */
27
+ export declare function configPins(pinLayer: LayerDef, clusterLayer: LayerDef, countLayer: LayerDef): () => void;
28
+ /** The layer `config-all` pre-creates for pins, and the one whose clustering this module declares. */
29
+ export declare const PIN_LAYER_NAME = "poiFilterPins";
30
+ /** The layer `config-all` pre-creates for cluster teardrops, drawn directly above the pins. */
31
+ export declare const PIN_CLUSTER_LAYER_NAME = "poiFilterPinClusters";
32
+ /** The layer `config-all` pre-creates for cluster counts, drawn directly above the teardrops. */
33
+ export declare const PIN_COUNT_LAYER_NAME = "poiFilterPinCounts";
34
+ /**
35
+ * How long a pin takes to fade in or out, in milliseconds. MapLibre's `fadeDuration` default, which
36
+ * the placement spec's research cites: long enough that a crowd thinning out reads as motion, short
37
+ * enough that a zoom does not leave half-faded pins behind the camera.
38
+ */
39
+ export declare const PIN_FADE_MS = 300;
40
+ //# sourceMappingURL=config-pins.d.ts.map
@@ -0,0 +1 @@
1
+ import{Rect as S}from"@expofp/geometry";import{update as E}from"@expofp/renderer";import{comparer as H,reaction as X}from"mobx";import{createImageDef as M}from"../../../../engine/defs";import{DEFAULT_FONT_URL as k}from"../../../../engine/fonts";import{boothStore as Y,uiState as B}from"../../../../store";import{createDimmingAnimator as G}from"../../../../utils/dimming";import{createClusterPinCanvas as W,createPoiPinCanvas as $}from"./canvases";import{clusterCounterCircle as K,clusterCountFontPx as L,clusterCountText as R,COUNT_BLOCK_HALF_EM as V,PIN_ASPECT as _}from"./pin-geometry";export function configPins(t,i,s){const o=[];let r=[],n=[],u=[];function f(){const c=B.selectedPoiTypeFilters;if(!c.length)return[];const P=new Set(c.map(m=>m.id));return Y.booths.filter(m=>m.visible&&P.has(m.poiTypeId)&&m.rect)}const d=c=>{r.push(c)};function e(){r.forEach(c=>c.stop()),r=[]}function a(){t.children=n.map(c=>Q(c,d))}function l(){u=Array.from({length:Math.floor(n.length/2)},()=>Z(d)),i.children=u.map(c=>c.image),s.children=u.map(c=>c.count)}function p(c,P){const m=new Set,y=C=>C?.forEach(b=>m.add(b)),N=tt(u,c,nt*P.pixelSize);N.forEach((C,b)=>{et(C,c[b])&&y([C.image,C.count]),y(C.fader.place(!0))});const D=new Set(N);for(const C of u)D.has(C)||y(C.fader.place(!1));return m.size?[...m]:void 0}const h={onCluster:(c,P)=>p(c,P),marker:{width:x,height:T,origin:w}};return t.clustering=h,o.push(X(()=>f(),c=>{n=c,e(),a(),l(),E(t,i,s)},{equals:H.shallow,fireImmediately:!0})),function(){o.forEach(P=>P()),o.length=0,e(),u=[],t.clustering=void 0,t.children=[],i.children=[],s.children=[],E(t,i,s)}}function A(t,i,s,o,r){let n,u=r,f=!1,d=!1;const e=l=>{const p=1-Math.min(Math.max(l,0),1);let h=!1;if(s()!==p&&(i(p),h=!0),!u&&l>=1&&t.some(c=>!c.hidden)){for(const c of t)c.hidden=!0;h=!0}h&&(f?d=!0:E(...t))},a=()=>{if(!n&&(n=G(e,PIN_FADE_MS),o(n),!r)){const l=f;f=!0,n.setTarget(!0,{immediate:!0}),f=l}return n};return{place(l){if(l===u)return;u=l;let p=!1;if(l&&t.some(h=>h.hidden)){for(const h of t)h.hidden=!1;p=!0}return f=!0,d=!1,a().setTarget(!l),f=!1,p||d?t:void 0}}}function U(t,i,s,o){const{bounds:r}=t,n=i*o,u=i*s*o;if(!(r.size.x===n&&r.size.y===u))return r.set(r.center.x,r.center.y,n,u,r.rotation,r.elevation),[t]}function j(){return v||(v=$(g,window.devicePixelRatio)),v}function J(){return I||(I=W(x,window.devicePixelRatio)),I}function Q(t,i){const s=new S(t.rect.center,{x:g,y:g*_},0,t.elevation*2),o={...M(j(),s,{hidden:!1,origin:w}),screenSpace:!0,opacity:1};o.onScale=({pixelSize:n})=>U(o,g,_,n);const r=A([o],n=>{o.opacity=n},()=>o.opacity??1,i,!0);return o.placement={onPlace:n=>r.place(n)},o}function z(t){const i=Math.round(Math.min(Math.max(t,0),1)*255).toString(16);return`${ot}${i.padStart(2,"0")}`}function Z(t){const i=new S({x:0,y:0},{x,y:T},0,0),s={...M(J(),i,{hidden:!0,origin:w}),screenSpace:!0,opacity:0};s.onScale=({pixelSize:n})=>U(s,x,_,n);const o=q(s),r=A([s,o],n=>{s.opacity=n,o.lines[0].color=z(n)},()=>s.opacity??1,t,!1);return{image:s,count:o,fader:r}}function q(t){const i={lines:[{text:R(2),color:z(0),fontUrl:k,fontSize:0}],bounds:new S({x:t.bounds.center.x,y:t.bounds.center.y},{x:0,y:0},0,t.bounds.elevation),padding:[0,0],alignment:{horizontal:"center",vertical:"top",text:"center"},screenSpace:!0,hidden:!0};return i.onScale=({pixelSize:s})=>{const o=L(O.r)*s,r=x*s,u=2*((T-O.cy)*s+V*o),{bounds:f}=i,[d]=i.lines;if(!(d.fontSize===o&&f.size.x===r&&f.size.y===u))return d.fontSize=o,f.set(t.bounds.center.x,t.bounds.center.y,r,u,f.rotation,t.bounds.elevation),[i]},i}function tt(t,i,s){const o=Math.min(i.length,t.length),r=[],n=new Set,u=[];t.forEach(({image:e},a)=>{if(!e.hidden)for(let l=0;l<o;l++){const{x:p,y:h}=i[l],c=Math.hypot(p-e.bounds.center.x,h-e.bounds.center.y);c<=s&&u.push({distance:c,cluster:l,unit:a})}}),u.sort((e,a)=>e.distance-a.distance||e.cluster-a.cluster||e.unit-a.unit);for(const{cluster:e,unit:a}of u)r[e]||n.has(t[a])||(r[e]=t[a],n.add(t[a]));const f=t.map((e,a)=>({unit:e,index:a})).filter(({unit:e})=>!n.has(e)).sort((e,a)=>F(e.unit)-F(a.unit)||e.index-a.index);let d=0;for(let e=0;e<o;e++)r[e]||(r[e]=f[d++].unit);return r}function F({image:t}){return t.hidden?0:t.opacity??1}function et({image:t,count:i},s){const{x:o,y:r,elevation:n,unitCount:u}=s,f=R(u),[d]=i.lines,e=t.bounds;if(e.center.x===o&&e.center.y===r&&e.elevation===n&&d.text===f)return!1;e.set(o,r,e.size.x,e.size.y,e.rotation,n);const{bounds:a}=i;return a.set(o,r,a.size.x,a.size.y,a.rotation,n),d.text=f,!0}export const PIN_LAYER_NAME="poiFilterPins",PIN_CLUSTER_LAYER_NAME="poiFilterPinClusters",PIN_COUNT_LAYER_NAME="poiFilterPinCounts",PIN_FADE_MS=300;const g=32,w=[.5,1],x=44,nt=x,ot="#000000",O=K(x),T=x*_;let v,I;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * How a count is written on a cluster marker: the count itself up to 99, and `99+` above that.
3
+ *
4
+ * Three characters is the most the counter circle holds, and the font size is chosen for three, so
5
+ * a longer label would have to be drawn smaller or clipped.
6
+ * @param count - How many points the cluster holds.
7
+ * @returns The label.
8
+ */
9
+ export declare function clusterCountText(count: number): string;
10
+ /**
11
+ * The counter circle inside a cluster pin, in CSS pixels from the pin's top-left corner. The pin
12
+ * fills its canvas, so this is also the canvas's CSS coordinate space.
13
+ * @param widthPx - The pin's width in CSS pixels.
14
+ * @returns The circle's center and radius.
15
+ */
16
+ export declare function clusterCounterCircle(widthPx: number): {
17
+ cx: number;
18
+ cy: number;
19
+ r: number;
20
+ };
21
+ /**
22
+ * The count's em height, chosen once so that `99+` — the widest label — fits inside the circle, and
23
+ * used for every count so a marker does not change size as its membership changes.
24
+ *
25
+ * The label's half-diagonal is what has to fit, not its half-width: a box inscribed in a circle
26
+ * touches at its corners.
27
+ * @param radiusPx - The counter circle's radius in CSS pixels.
28
+ * @returns The font size in CSS pixels.
29
+ */
30
+ export declare function clusterCountFontPx(radiusPx: number): number;
31
+ /**
32
+ * The teardrop's height as a fraction of its width, for every pin drawn from `createPinCanvas`.
33
+ * Here rather than in `canvases.ts`, so a pin's height is computable without loading a module that
34
+ * builds a canvas.
35
+ */
36
+ export declare const PIN_ASPECT: number;
37
+ /** The pin head's radius as a fraction of the pin's width, for the PoI pin and the cluster pin. */
38
+ export declare const PIN_HEAD_FACTOR = 0.37;
39
+ /** The edge stroke's width in CSS pixels, which `createPinCanvas` also takes as its inset. */
40
+ export declare const PIN_EDGE_PX = 1.4;
41
+ /** The counter circle's radius as a fraction of the pin head's radius. */
42
+ export declare const CLUSTER_CIRCLE_FACTOR = 0.78;
43
+ /**
44
+ * One character's advance width as a fraction of the font size, for the SDK's condensed face.
45
+ *
46
+ * An estimate, like {@link CLUSTER_COUNT_CAP_EM} and {@link CLUSTER_COUNT_FIT}, rather than a
47
+ * computation: the count is laid out by the renderer's text engine and not by a 2D context, so
48
+ * there is nothing here to call `measureText` on. Nothing automated checks the three against the
49
+ * shipped font. The renderer's `ClusterCounts` baselines draw a fixture font, so they check the
50
+ * layout, not these numbers. The real check is visual: run the app and look at a `99+` marker.
51
+ */
52
+ export declare const CLUSTER_COUNT_ADVANCE_EM = 0.58;
53
+ /**
54
+ * How far below a `top`-aligned line's top edge the digits' ink center sits, in em. Troika anchors
55
+ * the line at the block's top, ascender space included, so this lifts the glyphs from that edge onto
56
+ * the circle's center. Measured in the running app with the shipped font (device ratios 1 and 2, one
57
+ * to three characters), not half the block, which was the 0.5 it replaced. The name keeps the old
58
+ * "half block" wording. The renderer story `ClusterCounts` keeps its own value for its fixture font.
59
+ */
60
+ export declare const COUNT_BLOCK_HALF_EM = 0.61;
61
+ /** A digit's cap height as a fraction of the font size, measured the same way. */
62
+ export declare const CLUSTER_COUNT_CAP_EM = 0.72;
63
+ /** How much of the circle the label claims, leaving a visible ring of white around it. */
64
+ export declare const CLUSTER_COUNT_FIT = 0.88;
65
+ //# sourceMappingURL=pin-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ export function clusterCountText(t){return t>99?"99+":String(t)}export function clusterCounterCircle(t){const o=t*PIN_HEAD_FACTOR;return{cx:t/2,cy:o+PIN_EDGE_PX,r:o*CLUSTER_CIRCLE_FACTOR}}export function clusterCountFontPx(t){const o=3*CLUSTER_COUNT_ADVANCE_EM/2,n=CLUSTER_COUNT_CAP_EM/2;return CLUSTER_COUNT_FIT*t/Math.hypot(o,n)}export const PIN_ASPECT=93/81,PIN_HEAD_FACTOR=.37,PIN_EDGE_PX=1.4,CLUSTER_CIRCLE_FACTOR=.78,CLUSTER_COUNT_ADVANCE_EM=.58,COUNT_BLOCK_HALF_EM=.61,CLUSTER_COUNT_CAP_EM=.72,CLUSTER_COUNT_FIT=.88;