UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

2 lines (1 loc) 5.29 kB
import{Box as j}from"@expofp/geometry";import{reaction as h}from"mobx";import{useEffect as K}from"react";import{POI_CLUSTER_COLOR as W,POI_CLUSTER_MIN_POINTS as q,POI_CLUSTER_RADIUS_PX as $,POI_CLUSTER_SIZE_PX as J,POI_CLUSTER_STROKE_COLOR as Q,POI_CLUSTER_STROKE_WIDTH_PX as ee,POI_CLUSTER_TEXT_SIZE_PX as te,POI_SELECTED_PIN_WIDTH_PX as oe}from"../../constants";import c from"../../store";import re from"../../tools/settings";import{DIM_INTENSITY as ie}from"../../utils/dimming";import{convertLocalToGps as C}from"../../utils/gps";import{createPoiPinheadImage as ne}from"../Map/drawing/config/canvases";import{isOutdoorMarkersEnabled as ce}from"../Map/drawing/config/config-outdoor-poi";import{getMapDimTarget as v}from"./useDimming";import{getLocalRectGeoBounds as se,getVisibleRectFitPadding as ae,isLngLatInVisibleViewport as le}from"./utils/geo-config";import{poiMarkerHitTest as U}from"./utils/poi-marker-hit-test";const s="expofp-poi",a="expofp-poi-clusters",S="expofp-poi-cluster-count",I="expofp-poi-unclustered",y="expofp-poi-selected",P="expofp-poi-pinhead-image",A=[a,S,I,y],pe=A.filter(p=>p!==S),L=p=>`expofp-poi-icon-${p}`;export function usePoiMarkers(p,E,f){K(()=>{if(!ce())return;const e=E.current;if(!p||!e||!f)return;const{gpsConfig:b}=f,l=new Set,k=window.devicePixelRatio||1,w=re.colors?.booths?.selected||"#3b6ef5",F=ne(oe,k,w),T=t=>C(t.center.x,t.center.y,b),O=(t,o)=>{e.hasImage(t)&&e.removeImage(t),e.addImage(t,o,{pixelRatio:k}),l.add(t)},N=t=>{const o=c.poiMarkerStore.markers,i=new Set(o.map(r=>L(r.boothId)));i.add(P);for(const r of[...l])i.has(r)||(e.hasImage(r)&&e.removeImage(r),l.delete(r));for(const r of o){const n=L(r.boothId);(t||!l.has(n))&&O(n,r.icon)}l.has(P)||O(P,F)},B=()=>{const t=c.poiMarkerStore.selectedMarkerId,o=c.poiMarkerStore.outdoorFilter,i=!o.active;let r=c.poiMarkerStore.markers;return t!==null?r=r.filter(n=>n.boothId===t):o.active&&(r=o.matchingMarkers),{cluster:i,data:{type:"FeatureCollection",features:r.map(n=>({type:"Feature",geometry:{type:"Point",coordinates:T(n)},properties:{boothId:n.boothId,icon:L(n.boothId),pinhead:n.boothId===t}}))}}},Y=()=>{let t=null;for(const o of e.getStyle()?.layers??[]){if(o.type!=="symbol")continue;const i=o.layout?.["text-font"];if(!(!Array.isArray(i)||!i.every(r=>typeof r=="string"))){if(!i.some(r=>/italic/i.test(r)))return i;t??=i}}return t??["Noto Sans Regular"]};let g=null;const R=()=>{for(const t of A)e.getLayer(t)&&e.removeLayer(t);e.getSource(s)&&e.removeSource(s),g=null},X=(t,o)=>{if(g!==null&&g!==o&&R(),e.getSource(s)||(e.addSource(s,{type:"geojson",data:t,cluster:o,clusterRadius:$,clusterMinPoints:q}),g=o),e.getLayer(a))return;const i=["!",["has","point_count"]],r=["==",["coalesce",["get","pinhead"],!1],!0];e.addLayer({id:a,type:"circle",source:s,filter:["has","point_count"],paint:{"circle-radius":J/2,"circle-color":W,"circle-stroke-color":Q,"circle-stroke-width":ee,"circle-pitch-alignment":"viewport"}}),e.addLayer({id:S,type:"symbol",source:s,filter:["has","point_count"],layout:{"text-field":["get","point_count_abbreviated"],"text-font":Y(),"text-size":te,"text-allow-overlap":!0,"text-ignore-placement":!0},paint:{"text-color":"#ffffff"}}),e.addLayer({id:I,type:"symbol",source:s,filter:["all",i,["!",r]],layout:{"icon-image":["get","icon"],"icon-anchor":"bottom","icon-allow-overlap":!0,"icon-ignore-placement":!0}}),e.addLayer({id:y,type:"symbol",source:s,filter:["all",i,r],layout:{"icon-image":P,"icon-anchor":"bottom","icon-allow-overlap":!0,"icon-ignore-placement":!0}})},M=()=>{if(!e.getLayer(a))return;const t=v()?1-ie:1;e.setPaintProperty(a,"circle-opacity",t),e.setPaintProperty(a,"circle-stroke-opacity",t),e.setPaintProperty(S,"text-opacity",t),e.setPaintProperty(I,"icon-opacity",t),e.setPaintProperty(y,"icon-opacity",t)},d=(t=!1)=>{N(t);const{cluster:o,data:i}=B();X(i,o),e.getSource(s)?.setData(i),M()},z=t=>{if(!t.length)return;const o=ae(50);if(t.every(m=>le(e,T(m),o)))return;const r=j.fromPoints(t.map(m=>m.center)),n=se(r,b),u=e.cameraForBounds(n,{padding:o,bearing:f.bearing});!u?.center||typeof u.zoom!="number"||e.easeTo({center:u.center,zoom:Math.min(e.getZoom(),u.zoom),bearing:f.bearing,duration:500,essential:!0})},_=t=>{const o=t.features?.[0]?.properties?.boothId;if(typeof o!="number")return;const i=c.boothStore.boothById.get(o);i&&c.clickBooth(i)},x=t=>{const o=t.features?.[0],i=o?.properties?.cluster_id,r=e.getSource(s);if(typeof i!="number"||!r||o?.geometry?.type!=="Point")return;const[n=0,u=0]=o.geometry.coordinates;r.getClusterExpansionZoom(i).then(m=>{e.easeTo({center:[n,u],zoom:Math.min(m,e.getMaxZoom()),duration:500})})};e.on("click",I,_),e.on("click",y,_),e.on("click",a,x),U.set((t,o)=>{const i=pe.filter(n=>!!e.getLayer(n));if(!i.length)return!1;const r=e.project(C(t,o,b));return e.queryRenderedFeatures([r.x,r.y],{layers:i}).length>0});const D=()=>{l.clear(),d(!0)};e.on("style.load",D);const H=h(()=>c.poiMarkerStore.markers,()=>d(!0)),V=h(()=>c.poiMarkerStore.selectedMarkerId,()=>d()),Z=h(()=>c.poiMarkerStore.outdoorFilter.key,()=>{d(),z(c.poiMarkerStore.outdoorFilter.matchingMarkers)}),G=h(()=>v(),()=>M());return d(!0),()=>{H(),V(),Z(),G(),U.set(null),e.off("style.load",D),e.off("click",I,_),e.off("click",y,_),e.off("click",a,x);try{R();for(const t of l)e.hasImage(t)&&e.removeImage(t)}catch{}}},[p,E,f])}