UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

2 lines (1 loc) • 19.2 kB
import{Fragment as I,jsx as x,jsxs as M}from"react/jsx-runtime";import{Box as w}from"@expofp/geometry";import{CameraSchema as R,SessionsFiltersSchema as $}from"@expofp/schema";import{optimizeWaypointOrder as V}from"@expofp/wayfinding";import{ErrorBoundary as z}from"@sentry/react";import j from"debug";import{reaction as G,runInAction as N}from"mobx";import{createRoot as O}from"react-dom/client";import{install as q}from"resize-observer";import D from"./components/Layout";import{bindBoothHitTest as Y}from"./components/Map/booth-by-xy.js";import{MAX_ROUTE_WAYPOINTS as y}from"./constants";import H from"./data";import{getFpGeo as P}from"./data/fpGeo.js";import U from"./floorplan.loader";import{shouldLoadIntercom as W}from"./intercom";import{registerPlanDisposer as S}from"./plan-lifecycle.js";import{BoundsSchema as X,POISelectorsSchema as v,ZoomToOptionsSchema as k}from"./schemas/sdk.schemas";import{applyDeclarativeConfig as K,applyParameters as Q,applyPathway as Z,initUrlRouting as J}from"./services/url-dispatch";import r,{uiState as _}from"./store";import{bindDetailsEvents as ee}from"./store/details-events";import{bindRootElement as te}from"./store/init/init-ui.js";import{findBooth as b,Route as B,separateExternalIds as F}from"./store/RouteStore";import{GaEventActions as C,initGtag as re,sendEventToGa as L,setConsentSettings as oe}from"./tools/gtag.js";import ie from"./tools/track-event.js";import{cameraToMapSettings as se,mapSettingsToCamera as ne}from"./utils/camera-map-settings";import{getStorage as A}from"./utils/entity-storage";import{getMostFrequent as ae}from"./utils/getMostFrequent";import{convertLocalToGps as he,isCoordinate as g}from"./utils/gps";import{getLocales as le,hasLocale as ce,setLocale as ue}from"./utils/i18n";import{mapEntity as p}from"./utils/mapEntity";const d=j("efp:api");q();export default class fe extends U{init(){re(),K(),this.ignoreQuery||J(this.offHistory),ie("load"),te(r),r.fp=this,S(ee()),Y(),oe(this.consent),L(C.Load,""),this.root=O(this.renderTarget),this.root.render(x(z,{children:x(D,{offHistory:this.offHistory,consent:this.consent})})),L(C.Rendered,""),S(G(()=>r.layerStore.layersLoaded,()=>{const t=this.renderTarget.getRootNode(),o=t instanceof ShadowRoot?t.host:this.renderTarget.parentElement;for(document.querySelectorAll(".expofp-floorplan-loader").forEach(s=>s.remove());o&&this.element.firstChild&&this.element.firstChild!==o;)this.element.removeChild(this.element.firstChild);this.resolveReady(),r.initialized||this.onInit?.(this),r.initialized=!0})),S(()=>clearTimeout(E));const e=W(H);e&&import("./intercom/bootIntercom").then(({bootIntercom:t})=>t(e)).catch(()=>{})}selectBooth(e){if(typeof e!="string"&&!Array.isArray(e)){a("selectBooth","Parameter must be a string or an array of strings.","EFP000000");return}const t=r.boothStore.booths.filter(o=>typeof e=="string"?o.name===e||o.externalId===e:e.includes(o.name)||e.includes(o.externalId));r.selectBooth(t)}selectExhibitor(e){if(typeof e!="string"&&!Array.isArray(e)){a("selectExhibitor","Parameter must be a string or an array of strings.","EFP000100");return}if(!e?.length){r.uiState.menu=!1,r.searchStore.resetSearchBox(),r.uiState.details=null;return}const t=r.exhibitorStore.exhibitors.filter(i=>typeof e=="string"?i.name===e||i.externalId===e:e.includes(i.name)||e.includes(i.externalId));if(!t?.length)return;if(typeof e=="string"){r.selectExhibitor(t[0]),r.moveToList([t[0]]);return}const o=t.flatMap(i=>i.booths.map(n=>n.layer)),s=ae(o.map(i=>i.description));s&&r.layerStore.updateVisibility(s,!0),r.uiState.menu=!1,r.searchStore.resetSearchBox(),r.uiState.details=null,r.uiState.list={type:"filter",items:t,query:{key:"exhibitors",value:t.map(i=>i.name).join(",")}},r.moveToList()}highlightExhibitors(e){if(!Array.isArray(e)){a("highlightExhibitors","Parameter must be an array of strings.","EFP000200");return}r.boothStore.highlightedByExternalIds=[],r.exhibitorStore.highlightedByExternalIds=[...e]}highlightBooths(e){if(!Array.isArray(e)){a("highlightBooths","Parameter must be an array of strings.","EFP000300");return}r.exhibitorStore.highlightedByExternalIds=[],r.boothStore.highlightedByExternalIds=[...e]}highlightEntities(e){if(!Array.isArray(e)){a("highlightEntities","Parameter must be an array of strings.","EFP000400");return}const{boothExternalIds:t,exhibitorExternalIds:o}=F(e);r.boothStore.highlightedByExternalIds=[...t],r.exhibitorStore.highlightedByExternalIds=[...o]}selectRoute(e,t){if(Array.isArray(e)){const o=[...e],s=o.shift(),i=o.pop();if(o.length>y)throw new Error(`The maximum number of waypoints is ${y}.`);if(!s||!i){a("selectRoute","Invalid route format: When providing an array, it must include at least two points: a start and a destination.","EFP000401");return}const n=o.map(m).filter(h=>h!==null);r.routeStore.selectRoute(new B(m(s),m(i),n));return}e||a("selectRoute","At a minimum, the starting point must be passed.","EFP000402"),r.routeStore.selectRoute(new B(m(e),t?m(t):null))}getOptimizedRoutes(e){if(!Array.isArray(e))return a("getOptimizedRoutes","Parameter must be an array.","EFP000500"),[];if(e.length>y)throw new Error(`The maximum number of waypoints is ${y}.`);const t=e.map(m).filter(s=>!!s);if(!t.length)throw new Error("No booths found for the provided waypoints.");const o=new Map;for(const s of t){const i=s.layer?.name??"",n=o.get(i);n?n.push(s):o.set(i,[s])}return Array.from(o.values()).map(s=>({waypoints:V(s.map(i=>[i.name,{x:i.rect.center.x,y:i.rect.center.y}]))}))}selectCurrentPosition(e,t,o){const s=g(e.x)&&g(e.y),i=g(e.lng)&&g(e.lat);if(!s&&!i){a("selectCurrentPosition","A point must be passed. Either (x,y) or (lat,lng) are required.","EFP000600");return}r.routeStore.selectCurrentPosition(e,t,o),this.onCurrentPositionChanged?.(e)}setBookmarks(e){if(!Array.isArray(e)||!e.length){a("setBookmarks","Parameter must be an array.","EFP000700");return}e.forEach(t=>{const o=r.exhibitorStore.exhibitors.find(s=>s.name===t.name||s.externalId===t.externalId);o&&(o.bookmarked=t.bookmarked)})}setEntitiesBookmarks(e){if(!Array.isArray(e)||!e.length){a("setEntitiesBookmarks","Parameter must be an array.","EFP000701");return}const t=["exhibitor","event","speaker","booth"],o=e.find(n=>!n.type||!t.includes(n.type));if(o){a("setEntitiesBookmarks",`Invalid entity type: ${o.type}. Must be one of: ${t.join(", ")}.`,"EFP000702");return}const s=A("bookmarked"),i={exhibitor:{existingIds:new Set(s.exhibitors||[]),finder:n=>r.exhibitorStore.findExhibitor(n),replacer:n=>r.exhibitorStore.replaceBookmarked(n)},event:{existingIds:new Set(s.events||[]),finder:n=>r.eventStore.findByNameOrSlug(n),replacer:n=>r.eventStore.replaceBookmarked(n)},speaker:{existingIds:new Set(s.speakers||[]),finder:n=>r.speakerStore.speakers.find(h=>h.name===n||h.externalId===n||h.slug===n),replacer:n=>r.speakerStore.replaceBookmarked(n)},booth:{existingIds:new Set(s.booths||[]),finder:n=>{const h=r.boothStore.findBooth(n);return h?.exhibitors.length===0?h:void 0},replacer:n=>r.boothStore.replaceBookmarked(n)}};e.forEach(n=>{const h=i[n.type],u=n.name||n.externalId||"",l=h.finder(u);l?n.bookmarked?h.existingIds.add(l.id):h.existingIds.delete(l.id):console.warn(`Entity not found: ${n.type} with query "${u}"`)}),Object.values(i).forEach(n=>{n.replacer(Array.from(n.existingIds))})}setEntitiesVisited(e){if(!Array.isArray(e)||!e.length){a("setEntitiesVisited","Parameter must be an array.","EFP000703");return}const t=["exhibitor","event"],o=e.find(n=>!n.type||!t.includes(n.type));if(o){a("setEntitiesVisited",`Invalid entity type: ${o.type}. Must be one of: ${t.join(", ")}.`,"EFP000704");return}const s=A("visited"),i={exhibitor:{existingIds:new Set(s.exhibitors||[]),finder:n=>r.exhibitorStore.findExhibitor(n),replacer:n=>r.exhibitorStore.replaceVisited(n)},event:{existingIds:new Set(s.events||[]),finder:n=>r.eventStore.findByNameOrSlug(n),replacer:n=>r.eventStore.replaceVisited(n)}};e.forEach(n=>{const h=i[n.type],u=n.name||n.externalId||"",l=h.finder(u);l?n.visited?h.existingIds.add(l.id):h.existingIds.delete(l.id):console.warn(`Entity not found: ${n.type} with query "${u}"`)}),Object.values(i).forEach(n=>{n.replacer(Array.from(n.existingIds))})}setMarkers(e){if(!e||!Array.isArray(e.icons)||!Array.isArray(e.markers)){a("setMarkers","Invalid input.","EFP000800");return}r.routeStore.setMarkers(e)}selectMarker(e,t=!0){return typeof e!="string"&&a("selectMarker","The identifier must be passed.","EFP000900"),r.routeStore.selectMarker(e,t)}drawCircles(e){if(!Array.isArray(e)){a("drawCircles","Invalid input.","EFP000A00");return}r.uiState.debugCircles=e}checkRoutes(){r.routeStore.checkRoutes()}updateLayerVisibility(e,t){typeof e!="string"&&a("updateLayerVisibility","The layer name (string) must be passed.","EFP000B00"),t||a("updateLayerVisibility","Passing a false value to visible will have no effect.","EFP000B01"),r.layerStore.updateVisibility(e,t)}getCenterCoordinates(){return r.fp.getCenterCoordinates()}exhibitorsList(){return r.exhibitorStore.exhibitors.map(e=>p(e))}boothsList(){return r.boothStore.booths.map(e=>p(e))}categoriesList(){return r.categoryStore.categories.map(e=>p(e))}selectCategory(e){if(e==null||typeof e!="string"){r.searchStore.selectSearch();return}const t=e?.toLowerCase(),o=r.categoryStore.categories.find(({name:s,slug:i})=>s?.toLowerCase()===t||i?.toLowerCase()===t);if(!o){a("selectCategory",`Category ${e} not found.`,"EFP000C01");return}r.selectCategory(o)}select(e){if(typeof e!="string"){a("select","Parameter must be a string.","EFP001700");return}const t=e,o=t?.toLowerCase(),s=r.boothStore.booths.find(l=>l.slug?.toLowerCase()===o||l.externalId?.toLowerCase()===o||l.externalId?.toLowerCase()?.replace(/\s+/g,"")===o);if(s){setTimeout(()=>r.selectBooth(s),250);return}const i=r.eventStore.eventItems.find(l=>l.slug?.toLowerCase()===o||l.externalId?.toLowerCase()===o);if(i){r.selectEventItem(i,!0);return}const n=r.exhibitorStore.exhibitors.find(l=>l.slug?.toLowerCase()===o||l.externalId?.toLowerCase()===o);if(n){setTimeout(()=>r.clickExhibitor(n),250);return}const h=r.categoryStore.categories.find(l=>l.slug===t);if(h){r.selectCategory(h);return}const u=r.speakerStore.findBySlug(t);if(u){r.selectSpeaker(u,!0);return}t.includes("heatmap=true")||r.searchStore.selectSearch(t)}showList(e){const t={bookmarks:()=>r.selectBookmarks(),visited:()=>r.selectVisited(),sessions:()=>r.selectSessions(),exhibitors:()=>r.selectExhibitors(),speakers:()=>r.selectSpeakers(),tours:()=>r.selectTours(),language:()=>r.selectLanguage()},o=t[e];if(!o){a("showList",`Unknown list "${e}". Must be one of: ${Object.keys(t).join(", ")}.`,"EFP001800");return}o()}showSessions(e={}){d("showSessions called with filters=%O",e);const t=$.safeParse(e);if(!t.success){a("showSessions",t.error.message,"EFP001C00");return}const o=t.data,{eventStore:s,sessionsFilterStore:i}=r;N(()=>{_.details=null,r.selectSessions(),i.closeFilter(),i.setPending("selectedTracks",T(o.tracks,s.tracks,"track")),i.setPending("selectedVenues",T(o.venues,s.venues,"venue")),i.setPending("date",o.date??"all"),i.setPending("timeOfDay",o.time??"all"),i.setPending("showBookmarksOnly",o.bookmarked??!1),i.setPending("showLiveOnly",o.live??!1),i.commitFilters()})}selectTour(e){if(typeof e!="string"||!e){a("selectTour","A tour id must be passed.","EFP001900");return}const t=r.toursStore.getTourById(e);t?r.toursStore.launchTour(t,t.name,t.description):(console.warn(`Route with id "${e}" not found`),r.selectTours())}openPlanner(e={}){if(typeof e!="object"||e===null){a("openPlanner","An options object must be passed.","EFP001A00");return}const t=e.from?b(e.from):null;e.fromBookmarks?r.routePlannerStore.launchFromBookmarks(t??void 0):r.routePlannerStore.launchFromSlugs(e.items??[],t??void 0)}startBuildRoute(){r.uiState.startBuildRoute()}applyParameters(e){typeof e!="string"&&a("applyParameters","A query string must be passed.","EFP000D00"),Q(e)}getVisibility(){return r.uiState.visibility}setVisibility(e){(typeof e!="object"||!Object.keys(e).length)&&a("setVisibility","The parameter must be passed.","EFP000E00"),r.uiState.setVisibility(e)}findLocation(){r.routeStore.findLocation()}zoomIn(){r.uiState.zoomIn()}zoomOut(){r.uiState.zoomOut()}switchView(){r.maplibreStore.activateMaplibre()}setCamera(e){d("setCamera called with camera=%O",e);const t=R.safeParse(e);if(!t.success){a("setCamera",t.error.message,"EFP001B00");return}r.uiState.setMapSettings(se(t.data))}getCamera(){return ne(r.uiState.mapSettings)}zoomTo(e,t){d("zoomTo called with selectors=%O options=%O",e,t);const o=v.safeParse(e);if(!o.success){a("zoomTo",o.error.message,"EFP001600");return}const s=k.safeParse(t);if(!s.success){a("zoomTo",s.error.message,"EFP001601");return}const i=this.getBounds(e);i&&this.fitBounds(i,t)}getBounds(e){d("getBounds called with selectors=%O",e);const t=v.safeParse(e);if(!t.success){a("getBounds",t.error.message,"EFP001400");return}const o=[];if(e.booths?.forEach(i=>{let n;i.externalId?n=r.boothStore.boothByExternalId.get(i.externalId):i.name&&(n=r.boothStore.boothByName.get(i.name.toLowerCase())),n?.rect&&o.push(n.rect)}),e.exhibitors?.forEach(i=>{let n;i.externalId?n=r.exhibitorStore.exhibitorByExternalId.get(i.externalId):i.name&&(n=r.exhibitorStore.exhibitorByName.get(i.name.toLowerCase())),n?.booths?.forEach(h=>{h.rect&&o.push(h.rect)})}),o.length===0)return;const s=w.fromUnion(...o);return{leftTop:{x:s.min.x,y:s.min.y},rightBottom:{x:s.max.x,y:s.max.y}}}fitBounds(e,t){if(d("fitBounds called with bounds=%O options=%O",e,t),!e){r.uiState.fitBounds();return}const o=X.safeParse(e);if(!o.success){a("fitBounds",o.error.message,"EFP001500");return}const s=k.safeParse(t);if(!s.success){a("fitBounds",s.error.message,"EFP001501");return}const i=w.fromMinMax({x:e.leftTop.x,y:e.leftTop.y},{x:e.rightBottom.x,y:e.rightBottom.y});r.uiState.moveToRect=t?.padding?i.expand(t.padding):i}getBoothRect(e){if(typeof e!="string"){a("getBoothRect","A booth name must be passed.","EFP000F00");return}const t=b(e)?.rect;return t?c.fromBox(t):void 0}convertToGeo(e,t){const o=P()?.properties?.config;if(!o){a("convertToGeo","The coordinates cannot be converted because the GPS configuration is not defined.","EFP001000");return}if(!e||!t){a("convertToGeo","Both coordinates must be passed.","EFP001001");return}return he(e,t,o)}getGeoConfig(){const e=P()?.properties?.config;return e?{bearing:e.bearing??0,p0:e.p0,p1:e.p1,p2:e.p2}:null}releaseResources(){r.maplibreStore.dispose(),this.root?.unmount(),super.releaseResources()}search(e){return typeof e!="string"?(a("search","A search string must be passed.","EFP001100"),Promise.resolve([])):r.fuzzySearchEngineStore.loadEngine().then(()=>(r.searchStore.selectSearch(e),r.uiState.fuzzySearchItems.map(t=>({item:p(t.item),score:t.score}))))}getFloors(){return r.layerStore.floors.map(e=>({name:e.name,shortName:e.shortName,description:e.description,active:e.active,disabled:e.disabled,index:e.index}))}activateFloor(e){if(!e?.name&&e?.index==null){a("activateFloor","Invalid floorId. It must contain either a name or an index.","EFP001200");return}const t=this.getFloors();if(e.name){const o=t.find(s=>s.name===e.name||s.shortName===e.name);if(!o){a("activateFloor",`Floor with name "${e.name}" not found.`,"EFP001201");return}if(o.active)return;this.updateLayerVisibility(o.name,!0);return}if(e.index!==null){const o=t.find(i=>i.index===e.index),s=o?.name;if(!s){a("activateFloor",`Floor at index ${e.index} does not exist.`,"EFP001203");return}if(o.active)return;this.updateLayerVisibility(s,!0);return}}showPathway(e,t){const{boothExternalIds:o,exhibitorExternalIds:s}=t?.length?F(t):{boothExternalIds:[],exhibitorExternalIds:[]};Z({pathwayId:e,boothIds:o,exhibitorIds:s})}showPathwayOnly(e,t){this.activateFloor({name:t}),r.layerStore.showPathWay(e),r.uiState.setPathwayOnlyMode(!0);const o=r.layerStore.findLayer(e),s=r.layerStore.findLayer(t),i=o?.rect||o?.viewbox?o:s,n=i?.viewbox??i?.rect;n&&(r.uiState.moveToRect=n.clone())}hidePathways(){this.highlightBooths([]),r.layerStore.hidePathways(),r.uiState.setPathwayOnlyMode(!1)}showSearch(){r.selectSearch("")}changeLanguage(e){const t=e?.toLowerCase?.();if(!ce(t)){a("changeLanguage",`Language "${e}" was not found. Available languages: ${le().map(o=>o.id).join(",")}`,"EFP001300");return}ue(t)}isGpsTrackingEnabled(){return r.routeStore.gpsEnabled}setGpsTrackingEnabled(e){r.routeStore.setGpsTrackingEnabled(e)}deselectCurrentPosition(){r.routeStore.selectCurrentPosition(null,!1)}deselectRoute(){r.routeStore.selectRoute(null),r.routeStore.setOnlyAccessible(!1)}reset(){this.selectBooth(""),this.selectExhibitor(""),this.selectCategory(),this.deselectCurrentPosition(),this.deselectRoute(),this.highlightEntities([]),r.uiState.kioskData&&r.resetCameraFn?r.resetCameraFn?.():this.fitBounds()}selectAccessibleRoute(e){r.routeStore.setOnlyAccessible(!0),this.selectRoute(e)}}function T(f=[],e,t){const o=new Set;for(const s of f){const i=s.toLowerCase(),n=e.find(h=>String(h.id)===s)??e.find(h=>h.externalId?.toLowerCase()===i)??e.find(h=>h.name?.toLowerCase()===i||h.slug?.toLowerCase()===i);n?o.add(n.id):console.warn(`Entity not found: ${t} with query "${s}"`)}return[...o]}function m(f){return(typeof f=="string"?b(f):r.routeStore.getNearestBooth(f))??null}let E=0;function a(f,e,t){const o=`Error calling "${f}" SDK method.`,s=`${e.endsWith(".")?e:e+"."} More information at`;let i="https://js-sdk.expofp.com/api/packages";if(t&&(i+=`#error-${t}`),console.error(`${o} ${s} ${i}`),r.fp.disableRuntimeAlerts)return;r.uiState.setGlobalErrorMessage({title:o,body:M(I,{children:[s," ",x("a",{href:i,target:"_blank",rel:"noreferrer",children:i})]})}),clearTimeout(E);const n=8e3;E=window.setTimeout(()=>{const h=async()=>{r.uiState.globalErrorMessages.length>0&&(r.uiState.popGlobalErrorMessage(),await new Promise(u=>setTimeout(u,n/2)),h())};h()},n)}class c{get h(){return Math.abs(this.y2-this.y1)}get w(){return Math.abs(this.x2-this.x1)}get cx(){return(this.x1+this.x2)/2}get cy(){return(this.y1+this.y2)/2}constructor(e,t,o,s){if(e>o){const i=e;e=o,o=i}if(t>s){const i=t;t=s,s=i}this.x1=e,this.y1=t,this.x2=o,this.y2=s}static fromBox(e){return new c(e.min.x,e.min.y,e.max.x,e.max.y)}static fromCxcywh(e,t,o,s){return new c(e-o/2,t-s/2,e+o/2,t+s/2)}contains(e){return e.x1>=this.x1&&e.x2<=this.x2&&e.y1>=this.y1&&e.y2<=this.y2}intersects(e){const t=Math.max(this.x1,e.x1),o=Math.min(this.x2,e.x2),s=Math.max(this.y1,e.y1),i=Math.min(this.y2,e.y2);return o>=t&&i>=s}getIntersection(e){const t=Math.max(this.x1,e.x1),o=Math.min(this.x2,e.x2),s=Math.max(this.y1,e.y1),i=Math.min(this.y2,e.y2);return o>=t&&i>=s?new c(t,s,o,i):new c(0,0,0,0)}getRotated90(){return c.fromCxcywh(this.cx,this.cy,this.h,this.w)}normalize(e,t){return new c(this.x1/e,this.y1/t,this.x2/e,this.y2/t)}withPadding(e,t=e){return this.w<e*2||this.h<t*2?this:c.fromCxcywh(this.cx,this.cy,this.w-e*2,this.h-t*2)}scale(e){return new c(this.x1*e,this.y1*e,this.x2*e,this.y2*e)}getArea(){return this.w*this.h}clone(){return new c(this.x1,this.y1,this.x2,this.y2)}translate(e,t){return this.x1+=e,this.x2+=e,this.y1+=t,this.y2+=t,this}equals(e){return e.x1===this.x1&&e.x2===this.x2&&e.y1===this.y1&&e.y2===this.y2}toString(){return this.x1+","+this.y1+","+this.w+","+this.h}containsPoint(e,t){return e>=this.x1&&e<=this.x2&&t>=this.y1&&t<=this.y2}}