UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

2 lines (1 loc) • 5.57 kB
import{Box as q}from"@expofp/geometry";import{reaction as h}from"mobx";import{useEffect as $}from"react";import{POI_CLUSTER_COLOR as J,POI_CLUSTER_MIN_POINTS as Q,POI_CLUSTER_RADIUS_PX as ee,POI_CLUSTER_SIZE_PX as te,POI_CLUSTER_STROKE_COLOR as oe,POI_CLUSTER_STROKE_WIDTH_PX as re,POI_CLUSTER_TEXT_SIZE_PX as ie,POI_MARKER_PIN_WIDTH_PX as ne,POI_SELECTED_PIN_WIDTH_PX as x}from"../../constants";import c from"../../store";import ce from"../../tools/settings";import{DIM_INTENSITY as se}from"../../utils/dimming";import{convertLocalToGps as ae}from"../../utils/gps";import{isOutdoorMarkersEnabled as le}from"../Map/drawing/config/config-outdoor-poi";import{createPoiPinheadImage as pe}from"../Map/drawing/config/poi-pin.js";import{getPoiPinLayout as v,POI_MARKER_PIN_SHAPE as fe,POI_SELECTED_PIN_SHAPE as ue}from"../Map/drawing/config/poi-pin-shape.js";import{getMapDimTarget as A}from"./useDimming";import{getLocalRectGeoBounds as de,getVisibleRectFitPadding as me,isLngLatInVisibleViewport as Ie}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",_="expofp-poi-selected",E="expofp-poi-pinhead-image",N=[a,S,I,_],_e=N.filter(p=>p!==S),L=p=>`expofp-poi-icon-${p}`;export function usePoiMarkers(p,b,u){$(()=>{if(!le())return;const e=b.current;if(!p||!e||!u)return;const{gpsConfig:k}=u,l=new Set,y=window.devicePixelRatio||1,w=ce.colors?.booths?.selected||"#3b6ef5",F=pe(x,y,w),B=v(fe,ne,y).tipOffset,H=v(ue,x,y).tipOffset,O=t=>ae(t.center.x,t.center.y,k),R=(t,o)=>{e.hasImage(t)&&e.removeImage(t),e.addImage(t,o,{pixelRatio:y}),l.add(t)},X=t=>{const o=c.poiMarkerStore.markers,i=new Set(o.map(r=>L(r.boothId)));i.add(E);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))&&R(n,r.icon)}l.has(E)||R(E,F)},Y=()=>{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:O(n)},properties:{boothId:n.boothId,icon:L(n.boothId),pinhead:n.boothId===t}}))}}},z=()=>{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 T=()=>{for(const t of N)e.getLayer(t)&&e.removeLayer(t);e.getSource(s)&&e.removeSource(s),g=null},V=(t,o)=>{if(g!==null&&g!==o&&T(),e.getSource(s)||(e.addSource(s,{type:"geojson",data:t,cluster:o,clusterRadius:ee,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":te/2,"circle-color":J,"circle-stroke-color":oe,"circle-stroke-width":re,"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":z(),"text-size":ie,"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-offset":[0,B],"icon-allow-overlap":!0,"icon-ignore-placement":!0}}),e.addLayer({id:_,type:"symbol",source:s,filter:["all",i,r],layout:{"icon-image":E,"icon-anchor":"bottom","icon-offset":[0,H],"icon-allow-overlap":!0,"icon-ignore-placement":!0}})},M=()=>{if(!e.getLayer(a))return;const t=A()?1-se: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(_,"icon-opacity",t)},d=(t=!1)=>{X(t);const{cluster:o,data:i}=Y();V(i,o),e.getSource(s)?.setData(i),M()},Z=t=>{if(!t.length)return;const o=me(50);if(t.every(m=>Ie(e,O(m),o)))return;const r=q.fromPoints(t.map(m=>m.center)),n=de(r,k),f=e.cameraForBounds(n,{padding:o,bearing:u.bearing});!f?.center||typeof f.zoom!="number"||e.easeTo({center:f.center,zoom:Math.min(e.getZoom(),f.zoom),bearing:u.bearing,duration:500,essential:!0})},P=t=>{const o=t.features?.[0]?.properties?.boothId;if(typeof o!="number")return;const i=c.boothStore.boothById.get(o);i&&c.clickBooth(i)},D=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,f=0]=o.geometry.coordinates;r.getClusterExpansionZoom(i).then(m=>{e.easeTo({center:[n,f],zoom:Math.min(m,e.getMaxZoom()),duration:500})})};e.on("click",I,P),e.on("click",_,P),e.on("click",a,D),U.set((t,o)=>{const i=_e.filter(n=>!!e.getLayer(n));if(!i.length)return!1;const r=e.getCanvas().getBoundingClientRect();return e.queryRenderedFeatures([t-r.left,o-r.top],{layers:i}).length>0});const C=()=>{l.clear(),d(!0)};e.on("style.load",C);const K=h(()=>c.poiMarkerStore.markers,()=>d(!0)),G=h(()=>c.poiMarkerStore.selectedMarkerId,()=>d()),W=h(()=>c.poiMarkerStore.outdoorFilter.key,()=>{d(),Z(c.poiMarkerStore.outdoorFilter.matchingMarkers)}),j=h(()=>A(),()=>M());return d(!0),()=>{K(),G(),W(),j(),U.set(null),e.off("style.load",C),e.off("click",I,P),e.off("click",_,P),e.off("click",a,D);try{T();for(const t of l)e.hasImage(t)&&e.removeImage(t)}catch{}}},[p,b,u])}