UNPKG

ocearo-ui

Version:

Ocean Robot UI: Sailing made smarter

1 lines 14 kB
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[931],{87343:function(e,t,n){Promise.resolve().then(n.bind(n,99670))},53082:function(e,t,n){"use strict";n.d(t,{$:function(){return w},FV:function(){return u},G5:function(){return p},HH:function(){return d},HQ:function(){return v},NU:function(){return M},Qj:function(){return f},Ux:function(){return h},YH:function(){return S},eF:function(){return g},gK:function(){return c},yC:function(){return C}});var i=n(57437),a=n(2265),r=n(14578),o=n(63321),l=n(72079);let s=(0,a.createContext)(),c="#09bfff",d="#cc000c",u="#0fcd4f",g="#ef4444",h=e=>null==e?null:Math.round((180*e/Math.PI+360)%360),f=e=>null==e?null:(e*m).toFixed(1),m=1.94384,p=e=>null!=e?Math.round((e-273.15)*10)/10:null,v=e=>null!=e?Math.round(19.4384*e)/10:null,w=v,M=e=>null!=e?Math.round(e/100*10)/10:null,b={autopilot:!0,anchorWatch:!1,parkingMode:!1,mob:!1,showOcean:!1,ais:!1,showPolar:!0},x={wind:{"environment.wind.angleTrueWater":l.M8C.degToRad(0),"environment.wind.speedTrue":10.288,"environment.wind.angleApparent":l.M8C.degToRad(0),"environment.wind.speedApparent":10.288},temperature:{"environment.water.temperature":290.15,"environment.outside.temperature":294.15,"propulsion.main.exhaustTemperature":368.15,"environment.inside.fridge.temperature":277.15},environment:{"environment.outside.pressure":102300,"environment.inside.relativeHumidity":.74,"environment.inside.voc":.03},performance:{"performance.beatAngle":l.M8C.degToRad(45),"performance.gybeAngle":l.M8C.degToRad(135),"performance.beatAngleVelocityMadeGood":6,"performance.gybeAngleVelocityMadeGood":5,"performance.targetAngle":l.M8C.degToRad(45),"performance.polarSpeed":8,"performance.polarSpeedRatio":.95,"performance.velocityMadeGood":5,"performance.polarVelocityMadeGood":6,"performance.polarVelocityMadeGoodRatio":.9},navigation:{"navigation.speedThroughWater":7,"navigation.headingTrue":l.M8C.degToRad(0),"navigation.courseOverGround":l.M8C.degToRad(20),"navigation.courseGreatCircle.nextPoint.bearingTrue":l.M8C.degToRad(30),"navigation.attitude.roll":l.M8C.degToRad(5)},racing:{"navigation.racing.layline":l.M8C.degToRad(10),"navigation.racing.layline.distance":100,"navigation.racing.layline.time":180,"navigation.racing.oppositeLayline":l.M8C.degToRad(45),"navigation.racing.oppositeLayline.distance":80,"navigation.racing.oppositeLayline.time":180,"navigation.racing.startLineStb":{latitude:0,longitude:0,altitude:0},"navigation.racing.startLinePort":{latitude:0,longitude:0,altitude:0},"navigation.racing.distanceStartline":50,"navigation.racing.timeToStart":120,"navigation.racing.timePortDown":60,"navigation.racing.timePortUp":70,"navigation.racing.timeStbdDown":65,"navigation.racing.timeStbdUp":75}},S=e=>{let{children:t}=e,[n,c]=(0,a.useState)({}),[d,u]=(0,a.useState)(!1),[g,h]=(0,a.useState)(b),f=e=>n[e]||null,m=(0,a.useRef)(null),p=(0,a.useRef)(null);return(0,a.useEffect)(()=>{let e=!0,t=async()=>{let e=new Date,t=e.getFullYear(),n=(e.getMonth()+1).toString().padStart(2,"0"),i="tides/larochelle/".concat(n,"_").concat(t,".json"),a=await fetch(i);if(a.ok){let t=await a.json(),n=e.toISOString().split("T")[0];if(t[n]){let e=null,i=null,a=new Date,r=60*a.getHours()+a.getMinutes();if(t[n].forEach(t=>{let[n,a,o,l]=t,[s,c]=a.split(":").map(Number),d=60*s+c;"tide.high"===n&&(!e||Math.abs(r-d)<Math.abs(r-e.timeInMinutes))?e={height:parseFloat(o),time:a,timeInMinutes:d,coef:l}:"tide.low"===n&&(!i||Math.abs(r-d)<Math.abs(r-i.timeInMinutes))&&(i={height:parseFloat(o),time:a,timeInMinutes:d})}),e&&i){let t="".concat(a.getHours().toString().padStart(2,"0"),":").concat(a.getMinutes().toString().padStart(2,"0")),n=y(e.height,i.height,t,e.time,i.time);c(t=>({...t,"environment.tide.heightNow":n,"environment.tide.heightHigh":e.height,"environment.tide.heightLow":i.height,"environment.tide.timeLow":i.time,"environment.tide.timeHigh":e.time,"environment.tide.coeffNow":e.coef}))}else throw Error("Tide data for today is incomplete.")}}else console.warn("No tide data found")};return(async()=>{let{signalkUrl:t,debugMode:n}=o.Z.getAll(),i=()=>{p.current&&clearInterval(p.current);let e=0;p.current=setInterval(()=>{let t=Math.floor(91*Math.random())-45;e=(e+5)%360,c(n=>({...n,"steering.rudderAngle":l.M8C.degToRad(t),"environment.wind.angleApparent":l.M8C.degToRad(e),"environment.wind.angleTrueWater":x.wind["environment.wind.angleTrueWater"],"environment.wind.speedTrue":x.wind["environment.wind.speedTrue"],"environment.wind.speedApparent":x.wind["environment.wind.speedApparent"],...x.temperature,...x.environment,...x.performance,...x.navigation,...x.racing}))},1e3)};try{if(!n){let[n,i]=t.replace(/https?:\/\//,"").split(":"),a=new r.default({hostname:n||"localhost",port:parseInt(i)||3e3,useTLS:t.startsWith("https"),reconnect:!0,autoConnect:!1,notifications:!1,deltaStreamBehaviour:"self",sendMeta:"all",wsKeepaliveInterval:10});m.current=a,await a.connect(),a.on("delta",t=>{e&&t.updates.forEach(e=>{e.values&&e.values.forEach(e=>{c(t=>({...t,[e.path]:e.value}))})})})}n&&i()}catch(e){console.error("Failed to connect to SignalK:",e),i()}})(),t(),()=>{e=!1,m.current&&m.current.disconnect(),p.current&&clearInterval(p.current)}},[]),(0,i.jsx)(s.Provider,{value:{getSignalKValue:f,getBoatRotationAngle:()=>{let e=f("navigation.headingTrue")||f("navigation.headingMagnetic");return f("navigation.courseOverGroundTrue")||f("navigation.courseOverGroundMagnetic")||e||0},getAISBoatRotationAngle:e=>e?null!==e.cog&&void 0!==e.cog?e.cog:null!==e.cogMagnetic&&void 0!==e.cogMagnetic?e.cogMagnetic:null!==e.heading&&void 0!==e.heading?e.heading:null!==e.headingMagnetic&&void 0!==e.headingMagnetic?e.headingMagnetic:0:0,convertLatLonToXY:(e,t)=>{if(!e||!t)return{x:0,y:0};let n=t.lat*Math.PI/180,i=t.lon*Math.PI/180,a=e.lat*Math.PI/180,r=e.lon*Math.PI/180,o=r-i,l=Math.atan2(Math.sin(o)*Math.cos(a),Math.cos(n)*Math.sin(a)-Math.sin(n)*Math.cos(a)*Math.cos(o)),s=Math.sin((a-n)/2)*Math.sin((a-n)/2)+Math.cos(n)*Math.cos(a)*Math.sin((r-i)/2)*Math.sin((r-i)/2),c=2*Math.atan2(Math.sqrt(s),Math.sqrt(1-s))*6371e3;return{x:c*Math.sin(l),y:-c*Math.cos(l)}},nightMode:d,setNightMode:u,states:g,toggleState:function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0;h(n=>({...n,[e]:void 0!==t?t:!n[e]}))}},children:t})},C=()=>(0,a.useContext)(s),y=function(e,t,n,i,a){let r,o,l,s;if(!n||!i||!a||!/^\d{1,2}:\d{2}$/.test(n)||!/^\d{1,2}:\d{2}$/.test(i)||!/^\d{1,2}:\d{2}$/.test(a))return console.error("Invalid time format provided to calculateTideHeightUsingTwelfths"),(e+t)/2;let c=e=>{let[t,n]=e.split(":").map(Number);return 60*t+n},d=c(i),u=c(a),g=c(n),h=!1;u<=g&&g<=d?(h=!0,r=t,o=e,l=u,s=d):(r=e,o=t,l=d,s=u+(u<d?1440:0));let f=Math.abs(s-l),m=Math.abs(o-r),p=g-l;p<0&&(p+=1440);let v=m/12,w=0;return w=p<=f/6?v*Math.ceil(p/(f/12)):p<=2*f/6?2*v+v*Math.ceil((p-f/6)/(f/12)):p<=3*f/6?5*v:p<=4*f/6?8*v:p<=5*f/6?10*v:m,h?r+w:r-w}},63321:function(e,t,n){"use strict";n.d(t,{Z:function(){return r}});var i=JSON.parse('{"F":[{"name":"Default","modelPath":"default","capabilities":["navigation","rudder","sail","color"]},{"name":"Optimist","modelPath":"optimist","capabilities":["navigation","ais"]},{"name":"Sailboat","modelPath":"sailboat","capabilities":["navigation","ais"]},{"name":"Ship","modelPath":"ship","capabilities":["navigation","ais"]},{"name":"Windsurf","modelPath":"windsurf","capabilities":["navigation","ais"]}]}');class a{isLocalStorageAvailable(){try{return"undefined"!=typeof localStorage}catch(e){return!1}}loadConfig(){if(this.isLocalStorageAvailable()){let e=localStorage.getItem(this.configKey);if(!e)return this.saveConfig(this.defaultConfig),{...this.defaultConfig};try{return JSON.parse(e)}catch(e){return console.error("Failed to parse stored configuration:",e),{...this.defaultConfig}}}return{...this.inMemoryConfig}}saveConfig(e){this.config={...this.config,...e},this.isLocalStorageAvailable()?localStorage.setItem(this.configKey,JSON.stringify(this.config)):this.inMemoryConfig={...this.config}}get(e){return this.config[e]}set(e,t){this.config[e]=t,this.saveConfig(this.config)}resetConfig(){this.config={...this.defaultConfig},this.isLocalStorageAvailable()?localStorage.setItem(this.configKey,JSON.stringify(this.config)):this.inMemoryConfig={...this.defaultConfig}}getAll(){return{...this.config}}getDefaultConfig(){return{...this.defaultConfig}}getSelectedBoat(){let e=this.config.selectedBoat;return e?this.getBoatsData().find(t=>t.name===e):[]}getBoatsData(){return i.F}getComputedSignalKUrl(){return this.config.debugMode?"https://demo.signalk.org:443":"".concat(window.location.protocol,"//").concat(window.location.hostname).concat(window.location.port?":"+window.location.port:"")}constructor(){this.defaultConfig={signalkUrl:"https://demo.signalk.org:443",username:"",password:"",debugMode:!1,selectedBoat:"Default",primaryColor:null,metallicEffect:!1,aisLengthScalingFactor:.7,compassNorthUp:!1},this.configKey="ocearoConfig",this.inMemoryConfig={...this.defaultConfig},this.config=this.loadConfig()}}var r=new a},99670:function(e,t,n){"use strict";n.r(t),n.d(t,{VIEW_MODES:function(){return f},default:function(){return p}});var i=n(57437),a=n(2265),r=n(30166),o=n(20376),l=n.n(o),s=n(53082);class c extends a.Component{static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){this.setState({error:e,errorInfo:t}),console.error("Error caught in Error Boundary:",e,t)}render(){if(this.state.hasError){let{error:e,errorInfo:t}=this.state;return(0,i.jsxs)("div",{className:"flex flex-col items-center justify-center min-h-screen bg-gray-100 text-gray-900",children:[(0,i.jsx)("h1",{className:"text-3xl font-bold text-red-600 mb-4",children:"Something went wrong."}),(0,i.jsxs)("p",{className:"text-lg mb-2",children:[(0,i.jsx)("strong",{children:"Error:"})," ",e?e.toString():"Unknown error"]}),t&&(0,i.jsxs)("details",{className:"whitespace-pre-wrap bg-gray-200 p-4 rounded-lg mb-4",children:[(0,i.jsx)("summary",{className:"cursor-pointer text-blue-500 underline",children:"Stack Trace"}),(0,i.jsx)("pre",{className:"mt-2",children:t.componentStack})]}),(0,i.jsxs)("div",{className:"flex space-x-4",children:[(0,i.jsx)("button",{onClick:this.handleRefresh,className:"px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600",children:"Refresh Page"}),(0,i.jsx)("button",{onClick:this.handleExitFullscreen,className:"px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600",children:"Exit Fullscreen"})]})]})}return this.props.children}constructor(e){super(e),this.handleRefresh=()=>{window.location.reload()},this.handleExitFullscreen=()=>{document.fullscreenElement&&(window.close(),document.exitFullscreen().catch(e=>{console.error("Failed to exit fullscreen:",e)}))},this.state={hasError:!1,error:null,errorInfo:null}}}let d=(0,r.default)(()=>n.e(252).then(n.bind(n,7252)),{loadableGenerated:{webpack:()=>[7252]},loading:()=>(0,i.jsx)("div",{className:"w-full h-full flex items-center justify-center",children:"Loading..."})}),u=(0,r.default)(()=>Promise.all([n.e(676),n.e(268),n.e(12)]).then(n.bind(n,12012)),{loadableGenerated:{webpack:()=>[12012]}}),g=(0,r.default)(()=>Promise.all([n.e(676),n.e(268),n.e(936)]).then(n.bind(n,72936)),{loadableGenerated:{webpack:()=>[72936]}}),h=(0,r.default)(()=>Promise.all([n.e(676),n.e(689),n.e(268),n.e(496),n.e(412)]).then(n.bind(n,6412)),{loadableGenerated:{webpack:()=>[6412]},loading:()=>(0,i.jsx)("div",{className:"w-full h-full flex items-center justify-center",children:(0,i.jsx)("div",{className:"text-white text-2xl",children:"Loading 3D View..."})}),ssr:!1}),f={BOAT:"boat",APP:"app",SPLIT:"split"},m=()=>window.innerWidth>=1366;function p(){let e=(0,a.useRef)(!1),[t,n]=(0,a.useState)(null),[r,o]=(0,a.useState)("navigation"),[p,v]=(0,a.useState)(!1),[w,M]=(0,a.useState)(!1);(0,a.useEffect)(()=>{let t;n(m()?f.SPLIT:f.BOAT),e.current=!0;let i=()=>{clearTimeout(t),t=setTimeout(()=>{n(m()?f.SPLIT:f.BOAT)},250)};return window.addEventListener("resize",i),()=>{window.removeEventListener("resize",i),clearTimeout(t)}},[]);let b=(0,a.useCallback)(()=>{v(e=>!e)},[]),x=(0,a.useCallback)(e=>{n(e)},[]),S=(0,a.useCallback)((e,t)=>{let n=window.innerWidth/5;t.x>n?x(f.BOAT):t.x<-n?x(f.APP):x(f.SPLIT)},[x]),C=(0,a.useCallback)(()=>{document.fullscreenElement?document.exitFullscreen():document.documentElement.requestFullscreen().catch(e=>{console.error("Fullscreen error:",e.message)})},[]),y=(0,a.useCallback)(e=>{t===f.BOAT&&x(f.APP),o(e)},[t,x]),T=(0,a.useCallback)(()=>{w?(x(f.BOAT),M(!1)):(y("settings"),M(!0))},[w,x,y]),P=(0,a.useMemo)(()=>null===t?{}:{leftPane:"transition-all duration-300 ".concat(t===f.BOAT?"w-full":t===f.APP?"hidden":"w-2/5"," bg-leftPaneBg h-full relative"),rightPane:"transition-all duration-300 ".concat(t===f.APP?"w-full":t===f.BOAT?"hidden":"w-3/5"," h-full bg-rightPaneBg p-4")},[t]);return e.current?(0,i.jsx)(c,{children:(0,i.jsx)(s.YH,{children:(0,i.jsxs)("div",{className:"h-screen flex flex-col bg-black relative overflow-hidden",children:[(0,i.jsxs)("div",{className:"flex flex-1 min-h-0",children:[(0,i.jsx)("div",{className:P.leftPane,children:(0,i.jsx)(h,{})}),(0,i.jsx)(l(),{axis:"x",onDrag:S,position:{x:0,y:0},handle:".handle",bounds:"parent",children:(0,i.jsx)("div",{className:"handle w-1 bg-leftPaneBg h-full cursor-col-resize transition-all duration-200 flex items-center justify-center",children:(0,i.jsx)("div",{className:"rounded-full w-3 bg-gray-600 h-40 transition-all duration-200 hover:bg-gray-500"})})}),(0,i.jsx)("div",{className:P.rightPane,children:(0,i.jsx)(d,{view:r})})]}),(0,i.jsx)("div",{className:"w-full h-16 min-h-16 bg-black flex items-center justify-center shrink-0",children:(0,i.jsx)(u,{setRightView:y,toggleAppMenu:b,toggleSettings:T})}),p&&(0,i.jsx)(g,{currentViewMode:t,toggleViewMode:x,handleSetRightView:y,toggleFullscreen:C,setShowAppMenu:v})]})})}):(0,i.jsx)("div",{className:"h-screen bg-black flex items-center justify-center",children:(0,i.jsx)("div",{className:"animate-pulse text-white",children:"Loading..."})})}}},function(e){e.O(0,[870,746,971,117,744],function(){return e(e.s=87343)}),_N_E=e.O()}]);