@expofp/floorplan 3.44.7 → 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.
- package/dist/browser/{Button-CleQDd3q.js → Button-6lV64H09.js} +5 -5
- package/dist/browser/{CookieConsent-DBf69NUJ.js → CookieConsent-k11VHxoM.js} +7 -7
- package/dist/browser/{Debug-B5dACqLH.js → Debug-DbfbGWb0.js} +7 -7
- package/dist/browser/{DebugTools-CJqVrNUk.js → DebugTools-BjHOBi_k.js} +6 -6
- package/dist/browser/{Demo-Bn0xGm2R.js → Demo-CrFjKybB.js} +9 -9
- package/dist/browser/{Free-DdJFphUM.js → Free-4IN6GHrY.js} +10 -10
- package/dist/browser/{GalleryContainer-Dr3XdE_K.js → GalleryContainer-BWd-8Nhp.js} +11 -11
- package/dist/browser/{GpsLoader-x1X6cIIo.js → GpsLoader-C43ADyfU.js} +13 -13
- package/dist/browser/{KioskStore-DAX0R23S.js → KioskStore-0xBjJ9AG.js} +14 -20
- package/dist/browser/{LayerStore-CchaypH9.js → LayerStore-BifpIwHB.js} +3732 -3226
- package/dist/browser/{MaplibreAdapter-DTEZ-jxf.js → MaplibreAdapter-CxETR3-R.js} +2517 -2517
- package/dist/browser/{ModalContainer-Cj8s9wg0.js → ModalContainer-IvkrtwT_.js} +10 -10
- package/dist/browser/{PermissionNotice-CAMpf8J5.js → PermissionNotice-C4Nu1dPO.js} +6 -6
- package/dist/browser/{RouteStore-BG2GPSXR.js → RouteStore-ltbgXRLP.js} +28 -28
- package/dist/browser/{SetKioskMode-B7Dki7mM.js → SetKioskMode-BWzFzO_Q.js} +12 -12
- package/dist/browser/{ShowKiosk-CrMZ-Nzh.js → ShowKiosk-BYOTTOrX.js} +10 -10
- package/dist/browser/{UIState-C-Y4d_-F.js → UIState-BG-A7rPb.js} +230 -230
- package/dist/browser/{ViewerMenuPanel-ByEmJoRl.js → ViewerMenuPanel-DscD3jCY.js} +11 -11
- package/dist/browser/{add-debug-secret-listener-BGDZfpcC.js → add-debug-secret-listener-qgQOxLV_.js} +1 -1
- package/dist/browser/{adopt-global-settings-Dk05fnXw.js → adopt-global-settings-CB1YrOJs.js} +9 -9
- package/dist/browser/{boolean-editor-o6yCthBy.js → boolean-editor-DcFqYLg6.js} +9 -9
- package/dist/browser/{bootIntercom-BwnVPXBt.js → bootIntercom-DJEOZaFU.js} +2 -2
- package/dist/browser/bundle.json +87 -87
- package/dist/browser/{camera-events-DWOBiqIB.js → camera-events-BwP3bfY4.js} +1 -1
- package/dist/browser/{classnames-CZclRloQ.js → classnames-C6CE8V3C.js} +2 -2
- package/dist/browser/{client-BvQ9Gczi.js → client-B42ooBdH.js} +5 -5
- package/dist/browser/{components-nLLOu6UV.js → components-DelXq6ex.js} +461 -461
- package/dist/browser/{create-live-plan-CWx504lG.js → create-live-plan-jO-YW94S.js} +263 -245
- package/dist/browser/{debug-context-D39JjNZt.js → debug-context-BFAUm0Rv.js} +5 -5
- package/dist/browser/{debug-overlay-m0mSmVHJ.js → debug-overlay-0pLu5_hz.js} +10 -10
- package/dist/browser/{debug-ui-BnyOgnPt.js → debug-ui-CPF3Fr0y.js} +6 -6
- package/dist/browser/{dist-B0uHOfHb.js → dist-5MtJlmvC.js} +5 -5
- package/dist/browser/{dist-DLh73aaY.js → dist-BImkgFoY.js} +6 -6
- package/dist/browser/{dist-yVxNF_HZ.js → dist-D7lv86ly.js} +3 -3
- package/dist/browser/{efp-debug-init-CCymXgr-.js → efp-debug-init-DBnQHIuj.js} +3 -3
- package/dist/browser/{enum-editor-Du2N0dRj.js → enum-editor-wagTer9Z.js} +4 -4
- package/dist/browser/{es5-l7cNM1JQ.js → es5-ClZJZH3H.js} +2 -2
- package/dist/browser/{event-head-DaeIW6ZC.js → event-head-Dvg64Dl9.js} +1 -1
- package/dist/browser/{event-not-found-CFWIRPAy.js → event-not-found-CmHnmais.js} +3 -3
- package/dist/browser/{event-scoped-cache-793HawJt.js → event-scoped-cache-blYstzYW.js} +2 -2
- package/dist/browser/{expofpUrl-BLqQlx4U.js → expofpUrl-D99TqyHD.js} +1 -1
- package/dist/browser/{exports-BmgyMAW1.js → exports-BBJtyyI0.js} +1 -1
- package/dist/browser/{favicon-BCSYqkNZ.js → favicon-Bac0ZnSB.js} +1 -1
- package/dist/browser/{fetch-retry.umd-BFKfjB2M.js → fetch-retry.umd-Dkr69k7z.js} +2 -2
- package/dist/browser/{flex-CK3VOHMW.js → flex-2znF0sHW.js} +5 -5
- package/dist/browser/{floorplan.loader-C9TjDBmt.js → floorplan.loader-B2NptbPQ.js} +12 -12
- package/dist/browser/{floorplan.ready-c_FJgMPD.js → floorplan.ready-DTyG-lkM.js} +344 -335
- package/dist/browser/{freeBanner-DgUUkI2a.js → freeBanner-yyOqSdAy.js} +2 -2
- package/dist/browser/{fuse-BYRtXyUs.js → fuse-x_QTzSiL.js} +2 -2
- package/dist/browser/{i18n-D6mkjwGK.js → i18n-CLEztXjo.js} +6 -6
- package/dist/browser/index.js +17 -17
- package/dist/browser/{index.module-WJQpxtrH.js → index.module-C9C4kJk7.js} +4 -4
- package/dist/browser/{init-ui-DRwSj40I.js → init-ui-rxZzKF4X.js} +16 -16
- package/dist/browser/{integrateKiosk-eGXJsNiO.js → integrateKiosk-DsU-d7uk.js} +5 -5
- package/dist/browser/{is-debug-m1W_6MrE.js → is-debug-Bnj4naYd.js} +4 -4
- package/dist/browser/{is-own-domain-Bdfz0zQ0.js → is-own-domain-DNjOZllq.js} +1 -1
- package/dist/browser/{is-webview-B8VsNIoN.js → is-webview-Drer0GOu.js} +1 -1
- package/dist/browser/{jsx-runtime-C1oR0Zi0.js → jsx-runtime-DB8EwfzE.js} +2 -2
- package/dist/browser/{kiosk-mode-B1Xr_IyL.js → kiosk-mode-B89VL0oY.js} +3 -3
- package/dist/browser/{kiosk-record-BOx9wVlW.js → kiosk-record-rnTon4Lp.js} +1 -1
- package/dist/browser/{kioskApi-BenqwSpt.js → kioskApi-opoHdUqq.js} +7 -7
- package/dist/browser/{lib-BMUuspHa.js → lib-eiqwFHwk.js} +3 -3
- package/dist/browser/{loadImage-BVv4a2P0.js → loadImage-BS80HTUK.js} +1 -1
- package/dist/browser/{logDeviceInfo-Ca0FCWzJ.js → logDeviceInfo-BqSbYo5l.js} +9 -9
- package/dist/browser/{mobx-Dd5eFIow.js → mobx-9NGoPiek.js} +4 -4
- package/dist/browser/{mobx.module-C48iLaGi.js → mobx.module-BP1vMHLz.js} +1 -1
- package/dist/browser/{optional-boolean-editor-B-42x5e-.js → optional-boolean-editor-D6hR19BE.js} +3 -3
- package/dist/browser/{optional-enum-editor-Bxiw2Z8x.js → optional-enum-editor-BQPM-fRt.js} +4 -4
- package/dist/browser/{optional-string-editor-CqHfXBvX.js → optional-string-editor-DUXoDnXB.js} +4 -4
- package/dist/browser/{particles.min-U6rx5JeG.js → particles.min-CBeInmmW.js} +2 -2
- package/dist/browser/{react-C3MD_6wk.js → react-Dg88gKA7.js} +2 -2
- package/dist/browser/{react-dom-_B4zRwEv.js → react-dom-C3PpoQeD.js} +3 -3
- package/dist/browser/{rolldown-runtime-D2hCdFW8.js → rolldown-runtime-C7pJ6q0h.js} +1 -1
- package/dist/browser/{scene-DyfGtdIg.js → scene-CV1XFwO9.js} +12 -12
- package/dist/browser/{scheduler-Bg382KcU.js → scheduler-D-EvNbvQ.js} +2 -2
- package/dist/browser/{select-D8SjUiUb.js → select-CQPuihmE.js} +10 -10
- package/dist/browser/{settings-Bh45PRJm.js → settings-BBn9P5W0.js} +2 -2
- package/dist/browser/{settings-item-DoHYH97F.js → settings-item-BOVedxqA.js} +6 -6
- package/dist/browser/{store-zbZemYUA.js → store-D73yMRu5.js} +2 -2
- package/dist/browser/{string-editor-23PXPywz.js → string-editor-Drmcb4Uw.js} +4 -4
- package/dist/browser/{text-field-C1dH_sz6.js → text-field-CnzYOUfF.js} +5 -5
- package/dist/browser/{theme-CHTbq4Fs.js → theme-B4d7ReQC.js} +8 -8
- package/dist/browser/{ui-D2xk_zF-.js → ui-DQ22eDdk.js} +8 -8
- package/dist/browser/useManageTraffic-C-4Maw9l.js +1439 -0
- package/dist/browser/{useRenderTarget-CHnba2yS.js → useRenderTarget-BaCkqntS.js} +4 -4
- package/dist/browser/{viewport-Cz5rd5Zn.js → viewport-CcbGLmJI.js} +3 -3
- package/dist/browser/{wayfinding-CQCzv2e-.js → wayfinding-4TI6Xwmj.js} +416 -383
- package/dist/esm/components/Kiosk/KioskStore.d.ts +5 -0
- package/dist/esm/components/Kiosk/KioskStore.js +1 -1
- package/dist/esm/components/Map/drawing/config/TextFitter.d.ts +2 -2
- package/dist/esm/components/Map/drawing/config/TextFitter.js +1 -1
- package/dist/esm/components/Map/drawing/config/booth-badge-anchor.d.ts +11 -2
- package/dist/esm/components/Map/drawing/config/booth-badge-anchor.js +1 -1
- package/dist/esm/components/Map/drawing/config/canvases.d.ts +90 -2
- package/dist/esm/components/Map/drawing/config/canvases.js +1 -1
- package/dist/esm/components/Map/drawing/config/config-all.js +1 -1
- package/dist/esm/components/Map/drawing/config/config-booth-badge.d.ts +3 -3
- package/dist/esm/components/Map/drawing/config/config-booth-bookmark.d.ts +1 -1
- package/dist/esm/components/Map/drawing/config/config-booth-bookmark.js +1 -1
- package/dist/esm/components/Map/drawing/config/config-booth-labels-special.d.ts +3 -4
- package/dist/esm/components/Map/drawing/config/config-booth-labels-special.js +2 -2
- package/dist/esm/components/Map/drawing/config/config-booth-labels.d.ts +2 -2
- package/dist/esm/components/Map/drawing/config/config-booth-labels.js +1 -1
- package/dist/esm/components/Map/drawing/config/config-markers.d.ts +17 -1
- package/dist/esm/components/Map/drawing/config/config-markers.js +1 -1
- package/dist/esm/components/Map/drawing/config/config-pins.d.ts +40 -0
- package/dist/esm/components/Map/drawing/config/config-pins.js +1 -0
- package/dist/esm/components/Map/drawing/config/pin-geometry.d.ts +65 -0
- package/dist/esm/components/Map/drawing/config/pin-geometry.js +1 -0
- package/dist/esm/components/Map/traffic/useBuildRoute.d.ts +1 -1
- package/dist/esm/components/Map/traffic/useBuildRoute.js +4 -4
- package/dist/esm/components/Map/traffic/useManageTraffic.js +1 -1
- package/dist/esm/engine/defs.d.ts +5 -0
- package/dist/esm/engine/defs.js +3 -3
- package/dist/esm/engine/update-def.d.ts +13 -1
- package/dist/esm/engine/update-def.js +1 -1
- package/dist/esm/services/url-dispatch.js +1 -1
- package/dist/esm/store/init/init-heatmap.d.ts +1 -1
- package/dist/esm/store/init/init-heatmap.js +1 -1
- package/dist/esm/store/search-buttons/SearchButtonsActions.d.ts +9 -0
- package/dist/esm/store/search-buttons/SearchButtonsActions.js +1 -1
- package/dist/esm/store/search-buttons/SearchButtonsStore.d.ts +15 -0
- package/dist/esm/store/search-buttons/SearchButtonsStore.js +1 -1
- package/dist/esm/test/store-harness.d.ts +13 -0
- package/dist/esm/test/store-harness.js +1 -1
- package/dist/esm/utils/dimming.js +1 -1
- package/dist/esm/wayfinding/adapters/canvasIconProvider.js +1 -1
- package/dist/esm/wayfinding/handlers/kioskHandler.js +1 -1
- package/dist/esm/wayfinding/handlers/yahHandler.js +1 -1
- package/package.json +10 -10
- package/dist/browser/dimming-BUP_9LMs.js +0 -1202
- package/dist/esm/engine/canvases.d.ts +0 -5
- 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
|
|
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: (
|
|
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
|
|
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,11 +1,12 @@
|
|
|
1
1
|
import { Box } from '@expofp/geometry';
|
|
2
|
-
import { type RegularBooth } from '../../../../store/BoothStore';
|
|
2
|
+
import { type RegularBooth } from '../../../../store/BoothStore.js';
|
|
3
3
|
/** What a badge's anchor search reads off its booth. */
|
|
4
4
|
export type BadgeBooth = Pick<RegularBooth, 'rect' | 'rotate'>;
|
|
5
5
|
/** Where a badge sits in one booth corner, and how large it may grow there. */
|
|
6
6
|
export interface BadgeFit {
|
|
7
|
-
/** The badge's top-left corner on the plan, before rotation. */
|
|
7
|
+
/** The x of the badge's top-left corner on the plan, before rotation. */
|
|
8
8
|
readonly x: number;
|
|
9
|
+
/** The y of the badge's top-left corner on the plan, before rotation. */
|
|
9
10
|
readonly y: number;
|
|
10
11
|
/** The largest scale that keeps the badge inside the booth's footprint. */
|
|
11
12
|
readonly maxScale: number;
|
|
@@ -65,6 +66,8 @@ export declare class BoothBadgeAnchors {
|
|
|
65
66
|
/** Drops the idle work {@link prefetch} queued and has not done yet. */
|
|
66
67
|
cancelPrefetch(): void;
|
|
67
68
|
private static scheduleIdle;
|
|
69
|
+
/** Runs the idle work for one {@link FRAME_SLICE_MS} slice, where no idle period is on offer. */
|
|
70
|
+
private static runSlice;
|
|
68
71
|
/**
|
|
69
72
|
* Works out one corner after another while the idle period lasts, for at most a slice, then asks
|
|
70
73
|
* for another.
|
|
@@ -76,6 +79,12 @@ export declare class BoothBadgeAnchors {
|
|
|
76
79
|
* @returns Whether a corner is still unknown after this one.
|
|
77
80
|
*/
|
|
78
81
|
private prefetchNext;
|
|
82
|
+
/**
|
|
83
|
+
* Searches a corner: the anchor, then the largest scale at it.
|
|
84
|
+
* @param corner - The booth corner, clockwise from top-left (0).
|
|
85
|
+
* @param rotation - The badge's rotation at that corner, in radians.
|
|
86
|
+
* @returns The corner's fit.
|
|
87
|
+
*/
|
|
79
88
|
private compute;
|
|
80
89
|
/**
|
|
81
90
|
* The largest scale the booth's rect allows. At odd corners the badge's width and height lie
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Box as
|
|
1
|
+
import{Box as I,pointRotate as x,Polygon as S}from"@expofp/geometry";const b=.5,E=.3,M=10,R=8,P=4,T=50;export class BoothBadgeAnchors{static{this.idle=new Set}static{this.idleScheduled=!1}constructor(t,n,e,i){this.booth=t,this.triangles=n,this.border=e,this.source=i,this.fits=[],this.prefetchRotation=0,this.vertices=null,this.polygon=w(n),this.bbox=trianglesBoundingBox(n)}fit(t,n){let e=this.fits[t];return e||(this.fits[t]=e=this.compute(t,n),this.fits.filter(Boolean).length===4&&(this.vertices=null)),e}prefetch(t){BoothBadgeAnchors.idle.has(this)||(this.prefetchRotation=t,BoothBadgeAnchors.idle.add(this),BoothBadgeAnchors.scheduleIdle())}cancelPrefetch(){BoothBadgeAnchors.idle.delete(this)}static scheduleIdle(){BoothBadgeAnchors.idleScheduled||!BoothBadgeAnchors.idle.size||(BoothBadgeAnchors.idleScheduled=!0,typeof requestIdleCallback=="function"?requestIdleCallback(BoothBadgeAnchors.runIdle):typeof requestAnimationFrame=="function"?requestAnimationFrame(()=>setTimeout(BoothBadgeAnchors.runSlice,0)):setTimeout(BoothBadgeAnchors.runSlice,T))}static runSlice(){const t=performance.now()+P;BoothBadgeAnchors.runIdle({timeRemaining:()=>t-performance.now()})}static runIdle(t){BoothBadgeAnchors.idleScheduled=!1;const n=performance.now()+R;try{for(const e of BoothBadgeAnchors.idle){if(t.timeRemaining()<=0||performance.now()>=n)break;let i=!1;try{i=e.prefetchNext()}finally{i||BoothBadgeAnchors.idle.delete(e)}}}finally{BoothBadgeAnchors.scheduleIdle()}}prefetchNext(){for(let t=1;t<4;t++)if(!this.fits[t])return this.fit(t,this.prefetchRotation+t*Math.PI/2),t<3;return!1}compute(t,n){const e=t===0||t===3?1:-1,i=t===0||t===1?1:-1,s=this.findAnchor(e,i),o=this.clampScale(s.x,s.y,this.rectMaxScale(t%2===1),n);return{x:s.x,y:s.y,maxScale:o}}rectMaxScale(t){const n=this.booth.rect.size.width,e=this.booth.rect.size.height,i=t?e:n,s=t?n:e;return Math.min(i>0?i*b/this.source.x:1/0,s>0?s*E/this.source.y:1/0)}findAnchor(t,n){const{booth:e,border:i,bbox:s}=this;if(s){const h=t>0?s.min.x:s.max.x,y=n>0?s.min.y:s.max.y,f=[];for(const[r,l]of this.distinctVertices()){const d=r+i*t,m=l+i*n,p=Math.abs(d-h)+Math.abs(m-y);p<1/0&&f.push({x:d,y:m,score:p,order:f.length})}f.sort((r,l)=>r.score-l.score||r.order-l.order);for(const r of f){const l={x:r.x,y:r.y};if(this.polygon.containsPoint(l))return l}}const o=t>0?e.rect.min.x+i:e.rect.max.x-i,c=n>0?e.rect.min.y+i:e.rect.max.y-i,u=e.rotate??0;return u?x({x:o,y:c},u,e.rect.center):{x:o,y:c}}clampScale(t,n,e,i){const{polygon:s,source:o}=this;if(!this.triangles.length)return e;const c={x:t,y:n};if(!s.containsPoint(c))return e;let u=0,h=e;for(let y=0;y<M;y++){const f=(u+h)/2,r=o.x*f,l=o.y*f;s.containsPoint(x({x:t+r,y:n},i,c))&&s.containsPoint(x({x:t,y:n+l},i,c))&&s.containsPoint(x({x:t+r,y:n+l},i,c))?u=f:h=f}return u}distinctVertices(){if(this.vertices)return this.vertices;const t=new Set,n=[];for(const e of this.triangles)for(const i of e){const s=`${i[0]},${i[1]}`;t.has(s)||(t.add(s),n.push([i[0],i[1]]))}return this.vertices=n}}export function trianglesBoundingBox(a){if(!a.length)return null;let t=1/0,n=1/0,e=-1/0,i=-1/0;for(const s of a)for(const[o,c]of s)o<t&&(t=o),c<n&&(n=c),o>e&&(e=o),c>i&&(i=c);return I.fromMinMax({x:t,y:n},{x:e,y:i})}function w(a){const t=[],n=[];for(const e of a){const i=t.length;t.push({x:e[0][0],y:e[0][1]}),t.push({x:e[1][0],y:e[1][1]}),t.push({x:e[2][0],y:e[2][1]}),n.push([i,i+1,i+2])}return new S(t,n)}
|
|
@@ -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
|
-
|
|
7
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|