UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

2 lines (1 loc) 8.32 kB
import{degToRad as It,lineAngle as ut,pointDistance as lt}from"@expofp/geometry";import{useEffect as xt,useRef as L}from"react";import{getBounds as k,rectToRenderer as Y}from"../../../renderer";import{isDefaultScene as Mt}from"../../../renderer/engine-core/defs";import Lt from"../../../tools/base-runtime-url";import{loadImage as bt}from"../../../utils/loadImage";import{createImageCanvas as Ft}from"../drawing/config/canvases";import{getRouteLayerRegex as Rt,getRouteStopLayerRegex as At,TRAFFIC_VEHICLES as Tt}from"./trafficLayers";import{UpdateQueue as Pt}from"./UpdateQueue";const nt=2,vt=nt*3.5,Q=nt*12,dt=Q*.7,_t=8,Ct="transport_locations",Nt=150,ot="#a4aab6",ht=1e3,St=2e4,ft=500;export function useManageTraffic({permission:e,rendererService:n,dataJsonUrl:c,websocketUrl:s}){const t=L(window.devicePixelRatio),r=L(new Map),o=L(new Map),i=L(),w=L(),m=L(performance.now()),x=L(1),y=L(new Pt),F=L(new Map),E=L(),h=L(ht),I=L(new Map),l=L();xt(()=>{let A;async function N(){if(!(!e||!n.scene))try{let f;try{const a=await fetch(c,{method:"GET",headers:{"Content-Type":"application/json"}});if(!a.ok||a.status===204)return;f=await a.json()}catch(a){console.warn("useManageTraffic failed to get JSON",a)}if(!f||f?.disabled||f?.error)return;t.current=gt(n.scale);const Z=new Map(f.routes.map(({id:a,color:p})=>[a,p])),H=n.scene.rootLayer.children,V=new Map;Z.forEach(a=>{V.set(a,Ht({radius:vt,color:a,scale:window.devicePixelRatio}))});const j=Rt(),q=H.filter(a=>j.test(a.name)),B=At(),G=H.filter(a=>B.test(a.name));f.routes.slice(0,q.length).forEach(({id:a,color:p,path:P,stops:W,hiddenPoints:v},d)=>{F.current.set(a,P);const _=q[d];if(_){const C=new Map(v?.map(u=>[rt(u),u])??[]);for(let u=1;u<P.length;u++){const S=P[u-1],D=P[u];C.has(rt(S))||C.has(rt(D))||_.children.push({points:[S,D],color:p,width:nt})}_.children.length&&y.current.add(()=>n.update(_))}const g=G[d];if(g&&W?.length){const C=V.get(p);W.forEach(u=>{g.children.push({source:C,bounds:Y(k(u.x,u.y,C.width,C.height,t.current))})}),g.children.length&&y.current.add(()=>n.update(g))}});const z=H.find(a=>a.name===Tt),J=new Map;E.current=a=>{try{const{ptScale:p,sceneId:P}=Dt(a);if(!Mt(P))return;t.current=gt(p);const W=[];for(const d of G){const _=d.children;for(const g of _)g.bounds=Y(k(g.bounds.center.x,g.bounds.center.y,g.source.width,g.source.height,t.current,g.bounds.rotation)),W.push(g)}const v=[...r.current.values()];for(const d of v)d.bounds=Y(k(d.bounds.center.x,d.bounds.center.y,d.source.width,d.source.height,t.current,d.bounds.rotation));y.current.add(()=>n.update(...W,...v))}catch(p){console.error("ptscale",p)}},n.renderer.events.addEventListener("viewport:ptscale",E.current),A=requestAnimationFrame(()=>{E.current?.(n.scale)}),Z.forEach((a,p)=>{J.set(p,mt({id:p,width:Q,height:Q,color:a,scale:window.devicePixelRatio}))}),J.set(ot,mt({id:"orphan",width:Q,height:Q,color:ot,scale:window.devicePixelRatio}));let U=null;try{const a=await bt(`${Lt}icons/bus-white.svg`);U=Ft(a,dt,dt,window.devicePixelRatio)}catch(a){console.error(a)}w.current=a=>{try{const p=JSON.parse(a.data);if(p.type!==Ct)return;const P=a.timeStamp||performance.now();x.current=Math.round(P-m.current),m.current=P;const W=Math.max(x.current??ft,ft),v=o.current,d=r.current,_=z.children,g=y.current;let C=!1;p.data.forEach(({id:u,x:S,y:D,route_id:st,hidden:yt})=>{if(v.has(u)&&(v.get(u)?.(),v.delete(u)),yt&&d.has(u)&&d.has(X(u))){const R=d.get(u);R.hidden=!0;const b=d.get(X(u));b.hidden=!0,g.add(()=>n.update(R,b));return}if(I.current.set(u,performance.now()),!d.has(u)){const R=J.get(st)||J.get(ot),b={id:u,source:R,bounds:Y(k(S,D,R.width,R.height,t.current,0))};if(d.set(u,b),U){const $=X(u),at={id:$,source:U,bounds:Y(k(S,D,U.width,U.height,t.current,0))};U.setAttribute("id",$),d.set($,at),_.push(b,at)}else _.push(b);C=!0;return}const K=d.get(u),it=d.get(X(u)),Et=K.bounds.center,et=Wt(Et,{x:S,y:D},F.current.get(st));if(et.reduce((R,b,$)=>$===0?R:R+ct(et[$-1],b),0)>=Nt||document.hidden)pt({rendererService:n,updateQueue:g,vehicle:K,vehicleFinery:it,x:S,y:D,scale:t.current,angle:Ot(K.bounds.center,{x:S,y:D})});else{const R=kt(et,W,b=>{pt({rendererService:n,updateQueue:g,vehicle:K,vehicleFinery:it,x:b.x,y:b.y,scale:t.current,angle:b.angle})});v.set(u,R)}}),C&&g.add(()=>n.update(z))}catch(p){console.error("handleSocketMessage",p)}},M(),O(f.config?(Number(f.config.vehicle_inactive_interval)||20)*1e3:St)}catch(f){console.warn(f)}}N();function M(){i.current?.readyState===WebSocket.OPEN||i.current?.readyState===WebSocket.CONNECTING||(i.current=new WebSocket(s),i.current.onmessage=w.current,i.current.onopen=()=>{h.current=ht},i.current.onclose=()=>{if(!navigator.onLine)return;setTimeout(M,h.current);const f=3e4;h.current=Math.min(h.current*2,f)})}function T(){M()}window.addEventListener("online",T);function O(f){clearInterval(l.current),l.current=window.setInterval(()=>{const Z=performance.now(),H=[],V=[];I.current.forEach((j,q)=>{if(Z-j<f)return;const B=r.current.get(q);B&&(B.hidden=!0,V.push(B),H.push(q));const G=X(q),z=r.current.get(G);z&&(z.hidden=!0,V.push(z),H.push(G))}),V.length&&y.current.add(()=>n.update(...V)),H.forEach(j=>I.current.delete(j))},f)}return()=>{E.current&&n.renderer&&n.renderer.events.removeEventListener("viewport:ptscale",E.current),A!==void 0&&cancelAnimationFrame(A),o.current.forEach(f=>f?.()),o.current.clear(),r.current.clear(),y.current.destroy(),window.removeEventListener("online",T),clearInterval(l.current)}},[e,n,c,s])}function gt(e){return Math.min(e||window.devicePixelRatio,_t)}function Dt(e){return typeof e=="number"?{ptScale:e}:e}function Ot(e,n){return ut(e,n)}function Ht({radius:e,scale:n,color:c}){const s=document.createElement("canvas"),t=s.getContext("2d");t.imageSmoothingEnabled=!1;const r=Math.ceil(e*2*n),o=r/2,i=e*.78,w=e*.33;return s.width=r,s.height=r,t.translate(o,o),t.scale(n,n),t.beginPath(),t.arc(0,0,e,0,2*Math.PI),t.fillStyle="#FFFFFF",t.fill(),t.beginPath(),t.arc(0,0,i,0,2*Math.PI),t.fillStyle=c,t.fill(),t.beginPath(),t.arc(0,0,w,0,2*Math.PI),t.fillStyle="#FFFFFF",t.fill(),s}function mt({id:e,width:n,height:c,color:s,scale:t}){const r=2*t,o=n/2*t,i=c*t,w=.6,m=.01,x=i*w,y=i,F=8*t,E=y+r+x/2+F*2,h=o*2+x+r+F*2,I=document.createElement("canvas");I.setAttribute("id",e),I.width=E,I.height=h;const l=I.getContext("2d"),A=E/2,N=h/2;l.save(),l.translate(A,N),l.rotate(-Math.PI/2),l.translate(-A,-N);const M=A,T=N-y/2+o,O=T+x;return l.shadowColor="rgba(16, 24, 40, 0.2)",l.shadowBlur=F/2,l.beginPath(),l.arc(M,T,o,Math.PI,0,!1),l.bezierCurveTo(M+o,T+i*.3,M+m*o,O,M,O),l.bezierCurveTo(M-m*o,O,M-o,T+i*.3,M-o,T),l.closePath(),l.fillStyle=s,l.fill(),l.strokeStyle="#FFFFFF",l.lineWidth=r,l.stroke(),l.restore(),I}function ct(e,n){return lt(e,n)}function X(e){return`${e}_finery`}function pt({rendererService:e,updateQueue:n,vehicle:c,vehicleFinery:s,x:t,y:r,scale:o,angle:i}){c.bounds=Y(k(t,r,c.source.width,c.source.height,o,i)),c.hidden=!1,s?(s.bounds=Y(k(t,r,s.source.width,s.source.height,o,It(e.angle))),s.hidden=!1,n.add(()=>e.update(s,c))):n.add(()=>e.update(c))}function tt(e,n,c){return{x:e.x+(n.x-e.x)*c,y:e.y+(n.y-e.y)*c}}function wt(e,n){let c=1/0,s={index:0,t:0};for(let t=0;t<n.length-1;t++){const r=n[t],o=n[t+1],i=o.x-r.x,w=o.y-r.y,m=i*i+w*w,x=m?((e.x-r.x)*i+(e.y-r.y)*w)/m:0,y=Math.max(0,Math.min(1,x)),F=tt(r,o,y),E=ct(e,F);E<c&&(c=E,s={index:t,t:y})}return s}function Vt(e,n,c){const s=ct(e,n),t=Math.max(2,Math.ceil(s/c)+1),r=[];for(let o=0;o<t;o++){const i=o/(t-1),w=tt(e,n,i);r.push(w)}return r}function Wt(e,n,c){if(!c||!c.length)return Vt(e,n,10);const s=wt(e,c),t=wt(n,c),r=[],o=i=>r.push(i);s.index+1<c.length?o(tt(c[s.index],c[s.index+1],s.t)):o(c[s.index]);for(let i=s.index+1;i<=t.index&&i<c.length;i++)o(c[i]);return t.index+1<c.length?o(tt(c[t.index],c[t.index+1],t.t)):o(c[t.index]),r}function kt(e,n,c,s){if(e.length<2)return()=>{};let t=null,r;const o=[];let i=0;for(let m=0;m<e.length-1;m++){const x=lt(e[m],e[m+1]);o.push(x),i+=x}const w=m=>{t||(t=m);const x=m-t,y=Math.min(x/n,1),F=y*i;let E=0,h=0;for(;h<o.length&&E+o[h]<F;)E+=o[h],h++;h>=o.length&&(h=o.length-1);const I=e[h],l=e[Math.min(h+1,e.length-1)],A=o[h]||0,N=A===0?0:(F-E)/A,M=I.x+(l.x-I.x)*N,T=I.y+(l.y-I.y)*N,O=ut(I,l);c({x:M,y:T,angle:O}),y<1?r=requestAnimationFrame(w):s&&s()};return r=requestAnimationFrame(w),()=>{r&&cancelAnimationFrame(r)}}function rt(e){return`${e.x},${e.y}`}