UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

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