diff --git a/assets/static/index.min.js b/assets/static/index.min.js index b5c4d6d..f5a98d4 100644 --- a/assets/static/index.min.js +++ b/assets/static/index.min.js @@ -1 +1 @@ -!function(){"use strict";function e(e){if(null==e)throw"item is null or undefined";return e}function t(e){if(null==e)throw"item is null or undefined";if(e instanceof HTMLButtonElement)return e;throw"item is not a button"}function n(t,n){e(document.getElementById(t)).innerText=n}function a(e,t,n){document.getElementById(e)?.setAttribute(t,n)}function i(e,t){e instanceof Array?e.forEach((e=>{a(e,"style",t)})):a(e,"style",t)}function o(e){document.querySelectorAll(e).forEach((e=>e.remove()))}function r(e){document.getElementById(e)?.remove()}function l(e,t){document.getElementById(e)?.classList.remove(t)}function s(e){l(e,"hidden")}const c="#a8a29e",d={"#0bd674":"Good","#ffcd1e":"Fair to Good","#ff9500":"Poor","#f4496d":"Very Poor","#a8a29e":"Flat"};let u,g,p,m,f,w,v,h,y,x,b,_;function E(e){const a=new Date(e.starting_at).getHours();let E=new Date(e.starting_at).getHours();if(a>20){let t=24-a;const n=e.wave_height_labels.length-(e.wave_height_labels.length-t)%24;E=0,g=e.wave_height_labels.slice(t,n),u=e.quality.slice(t,n),p=e.wave_height.slice(t,n),m=e.wind_speed.slice(t,n),f=e.wind_direction.slice(t,n),w=e.wind_gust.slice(t,n),v=e.wave_period.slice(t,n),h=e.temperature.slice(t,n),y=e.dewpoint.slice(t,n),x=e.cloud_cover.slice(t,n),b=e.probability_of_precipitation.slice(t,n),_=e.probability_of_thunder.slice(t,n)}else{const t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][new Date(e.starting_at).getDay()],n=[];for(let e=0;e=10&&e<12&&n.push(`${t} ${e} AM`),12===e&&n.push(`${t} ${e} PM`),e>12&&n.push(`${t} 0${e-12} PM`)):n.push(`${t} 12 AM`);const i=e.wave_height_labels.length+a-(e.wave_height_labels.length+a)%24;g=n.concat(e.wave_height_labels).slice(0,i),u=new Array(a).fill("#a8a29e").concat(e.quality).slice(0,i),p=new Array(a).fill(0).concat(e.wave_height).slice(0,i),m=new Array(a).fill(0).concat(e.wind_speed).slice(0,i),f=new Array(a).fill(0).concat(e.wind_direction).slice(0,i),w=new Array(a).fill(0).concat(e.wind_gust).slice(0,i),v=new Array(a).fill(0).concat(e.wave_period).slice(0,i),h=new Array(a).fill(0).concat(e.temperature).slice(0,i),y=new Array(a).fill(0).concat(e.dewpoint).slice(0,i),x=new Array(a).fill(0).concat(e.cloud_cover).slice(0,i),b=new Array(a).fill(0).concat(e.probability_of_precipitation).slice(0,i),_=new Array(a).fill(0).concat(e.probability_of_thunder).slice(0,i)}let A=(new Date).getHours();const I=document.getElementById("current-wave-height");""===I?.innerText&&(I.innerText=e.current_wave_height,"0"==e.current_wave_height&&(i("wave-quality",`background-color: ${c}`),n("wave-quality-text",d[c]),i("wave-quality-text",`color: ${c}`),o(".wave-quality-loader")),i("wave-icon",`transform: rotate(${e.current_wave_direction}deg);`),o(".wavey"));const q=document.getElementById("current-wave-period");""===q?.innerText&&(q.innerText=e.current_wave_period,r("wavey-period-loader")),n("legend-label",g[A]),n("legend-quality",d[u[A]]),n("legend-wave-height",p[A]),n("legend-wind-speed",m[A]),i("legend-wind-icon",`transform: rotate(${f[A]+180}deg);`),n("legend-wave-period",v[A]),n("legend-wind-gust",w[A]),n("forecast-as-of",`Updated ${e.as_of}`),n("forecast-as-of-2",`Updated ${e.as_of}`),o(".loader"),s("forecast"),s("wave-quality"),s("legend-container"),l("forecast-as-of-container","animate-pulse"),l("forecast-as-of-container-2","animate-pulse"),s("temperature-legend-container"),n("temperature-legend-label",g[A]),n("temperature-legend-temperature",h[A]),n("temperature-legend-dewpoint",y[A]),s("precipitation-legend-container"),n("precipitation-legend-label",g[A]),n("precipitation-legend-precipitation",b[A]),n("precipitation-legend-thunder",_[A]),n("precipitation-legend-cloud-cover",x[A]),i("legend",`background-color: ${u[A]};`),i(["legend-container","precipitation-legend-container","temperature-legend-container"],"margin-top: 1rem;");const T={id:"vert",defaults:{width:1,dash:[3,3]},afterInit:(e,t,n)=>{e.corsair={x:0,y:0}},afterDraw:(e,t,n)=>{if(e.tooltip?._active?.length){let t=e.tooltip._active[0].element.x,a=e.scales.y,i=e.ctx;i.save(),i.beginPath(),i.moveTo(t,a.top),i.lineTo(t,a.bottom),i.lineWidth=1,i.setLineDash(n.dash),i.strokeStyle="#fff",i.stroke(),i.restore()}if(A-E>H){const t=e.ctx,n=e.scales.x.getPixelForValue(A-E);t.save(),t.strokeStyle="#5b5b58",t.lineWidth=1,t.beginPath(),t.moveTo(n,0),t.lineTo(n,e.height),t.stroke(),t.fillStyle="#5b5b58",t.font="bold 1rem ui-sans-serif, system-ui, sans-serif",t.fillText("Now",A>14&&24===S?n-45:n+5,15),t.restore()}}};function B(e){let t;t=e>=g.length-a?g.length-a-1:e;k(t+(0===H?E:H))}function k(e){const t=u[e];i("legend",`background-color: ${t}`),n("legend-label",g[e]),n("legend-quality",d[t]),n("legend-wave-height",p[e]),n("legend-wind-speed",m[e]),i("legend-wind-icon",`transform: rotate(${f[e]+180}deg);`),n("legend-wave-period",v[e]),n("legend-wind-gust",w[e]),n("temperature-legend-label",g[e]),n("temperature-legend-temperature",h[e]),n("temperature-legend-dewpoint",y[e]),n("precipitation-legend-label",g[e]),n("precipitation-legend-precipitation",b[e]),n("precipitation-legend-thunder",_[e]),n("precipitation-legend-cloud-cover",x[e])}const $=(e,t,n)=>{const a=Chart.helpers.getRelativePosition(e,n),i=function(e){return 24===S||48===S?e&&e>0?e>=p.length-H?p.length-H-1:e:0:e&&e>0?e>=p.length?p.length-1:e:0}(n.scales.x.getValueForPixel(a.x));B(i)},M=(e,t)=>{const n=0===H?E:H;return 24===S?t%6==0?g[t+n]:null:48===S?t%8==0?g[t+n]:null:t%24==0?g[t+n]:null};const L=()=>window.innerWidth<768?24:window.innerWidth<1024?48:p.length;let S=L(),H=0,C=H+S;const D={size:24===S?14:18,weight:"semi-bold"},F=e=>({aspectRatio:1.75,onHover:$,borderRadius:5,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{enabled:!1}},responsive:!0,interaction:{intersect:!1,axis:"x"},scales:{x:{ticks:{callback:M}},y:{grid:{color:"#1B1B1B"},beginAtZero:!0,max:e??10,ticks:{callback:function(e){return e%2!=0?"":e},font:D}}}}),P=new Chart(document.getElementById("forecast"),{type:"bar",plugins:[T],data:{labels:0===H?g.slice(E,C):g.slice(H,C),datasets:[{label:"wave height (feet)",data:0===H?p.slice(E,C):p.slice(H,C),pointStyle:!1,minBarLength:.1}]},options:{...F(void 0),elements:{bar:{backgroundColor:e=>(e=>0===H?u[e.dataIndex+E]:u[e.dataIndex+H])(e)||"#4ade80"}}}});function N(e){n("forecast-range",e)}function O(){if(0===H){let e=a>20&&(new Date).getHours()>20;N(24===S?e?"Tomorrow":"Today":e?`Tomorrow - ${g[H+25].split(" ")[0]}`:"Today - Tomorrow")}else if(24===S)N(g[H].split(" ")[0]);else{const e=g[C-1]??g[g.length-1];N(`${g[H].split(" ")[0]} - ${e.split(" ")[0]}`)}}function J(){const e=0===H?E:H;let t=g.slice(e,C);P.data.labels=t,P.data.datasets[0].data=p.slice(e,C),P.update(),U.data.labels=t,U.data.datasets[0].data=h.slice(e,C),U.update(),Z.data.labels=t,Z.data.datasets[0].data=b.slice(e,C),Z.update()}O(),window.addEventListener("resize",(()=>{S=L(),H+S>g.length?(C=g.length,H=g.length-S):C=H+S,J(),B(0),0===H&&(t(document.getElementById("forecast-backward")).disabled=!0),H+S=p.length&&(t(document.getElementById("forecast-foreward")).disabled=!0),H>0&&(t(document.getElementById("forecast-backward")).disabled=!1),O()})),document.getElementById("forecast-backward")?.addEventListener("click",(()=>{H-S<0?(H=0,C=S):(C-=S,H-=S),J(),0===H?k(A):B(0),0===H&&(t(document.getElementById("forecast-backward")).disabled=!0),H+S{C+S>g.length?(C=g.length,H=C-S):(H+=S,C+=S),J(),B(0),H+S>=p.length&&(t(document.getElementById("forecast-foreward")).disabled=!0),H>0&&(t(document.getElementById("forecast-backward")).disabled=!1),O()}));const W=(e,t,n)=>({type:"bar",plugins:[T],data:{labels:0===H?g.slice(E,C):g.slice(H,C),datasets:[{label:n,data:e,pointStyle:!1,minBarLength:.1}]},options:{...F(100),elements:{bar:t?{backgroundColor:t,borderColor:t}:{}}}}),R=document.getElementById("temperature-forecast"),U=new Chart(R,W(0===H?h.slice(E,C):h.slice(H,C),"pink","F")),V=document.getElementById("precipitation-forecast"),Z=new Chart(V,W(0===H?b.slice(E,C):b.slice(H,C),null,"%"));function j(e){const t=P.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;U.tooltip.setActiveElements([{datasetIndex:e,index:n}]),U.setActiveElements([{datasetIndex:e,index:n}]),U.update(),Z.tooltip.setActiveElements([{datasetIndex:e,index:n}]),Z.setActiveElements([{datasetIndex:e,index:n}]),Z.update()}else U.tooltip.setActiveElements([],{x:0,y:0}),U.setActiveElements([],{x:0,y:0}),U.update(),Z.tooltip.setActiveElements([],{x:0,y:0}),Z.setActiveElements([],{x:0,y:0}),Z.update()}function z(e){const t=U.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;P.tooltip.setActiveElements([{datasetIndex:e,index:n}]),P.setActiveElements([{datasetIndex:e,index:n}]),P.update(),Z.tooltip.setActiveElements([{datasetIndex:e,index:n}]),Z.setActiveElements([{datasetIndex:e,index:n}]),Z.update()}else P.tooltip.setActiveElements([],{x:0,y:0}),P.setActiveElements([],{x:0,y:0}),P.update(),Z.tooltip.setActiveElements([],{x:0,y:0}),Z.setActiveElements([],{x:0,y:0}),Z.update()}function G(e){const t=Z.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;U.tooltip.setActiveElements([{datasetIndex:e,index:n}]),U.setActiveElements([{datasetIndex:e,index:n}]),U.update(),P.tooltip.setActiveElements([{datasetIndex:e,index:n}]),P.setActiveElements([{datasetIndex:e,index:n}]),P.update()}else U.tooltip.setActiveElements([],{x:0,y:0}),U.setActiveElements([],{x:0,y:0}),U.update(),P.tooltip.setActiveElements([],{x:0,y:0}),P.setActiveElements([],{x:0,y:0}),P.update()}P.canvas.onmousemove=j,U.canvas.onmousemove=z,Z.canvas.onmousemove=G,P.canvas.ontouchmove=j,U.canvas.ontouchmove=z,Z.canvas.ontouchmove=G}function A(t){t.wave_height&&(n("current-wave-height",t.wave_height),i("wave-icon",`transform: rotate(${t.wave_direction}deg);`),o(".wavey")),t.wave_period&&(n("current-wave-period",t.wave_period),r("wavey-period-loader")),(""===e(document.getElementById("wave-quality-text")).innerText||t.wave_height||parseFloat(e(document.getElementById("current-wave-height")).innerText??"0")>=1)&&(i("wave-quality",`background-color: ${t.quality_color};`),n("wave-quality-text",t.quality_text),i("wave-quality-text",`color: ${t.quality_color}`),o(".wave-quality-loader")),n("current-water-temp",t.water_temp),n("current-air-temp",t.air_temp),n("current-air-temp-2",t.air_temp),n("wind",I(t)),n("as-of",`As of ${t.as_of}`),i("wind-icon",`transform: rotate(${t.wind_direction+180}deg);`),o(".latest-loader"),s("wind-icon-container"),s("wave-icon-container"),l("as-of-container","animate-pulse"),s("wave-quality"),t.loaded_from_fallback&&s("wave-fallback-icon");new Date(t.as_of)e.wind_speed===e.gusts||"0"===e.gusts?e.wind_speed:`${e.wind_speed}-${e.gusts}`;function q(t){var n,a;r("forecast-container"),n="forecast-error",a=`\n
\n

\n Error loading forecast data - please refresh the page or try again later.\n

\n

${t}

\n
\n `,e(document.getElementById(n)).innerHTML=a}const T=e(document.querySelector("body"));new MutationObserver((e=>{for(const a of e)if(a.target instanceof HTMLElement&&("realtime-data"===a.target.id&&A(JSON.parse(a.target.innerText)),"water-quality-data"===a.target.id&&(t=JSON.parse(a.target.innerText),o(".water-quality-loader"),s("current-water-quality"),n("current-water-quality-title","Closed for season"===t.water_quality?"-----":t.water_quality.toUpperCase()),n("current-water-quality-status-text",t.water_quality_text),"Advisory"===t.water_quality&&i("current-water-quality-title","color: #facc15;"),"Closed"===t.water_quality&&i("current-water-quality-title","color: #ef4444;")),"forecast-data"===a.target.id))try{E(JSON.parse(a.target.innerText))}catch{setTimeout((()=>{if(a.target instanceof HTMLElement)try{E(JSON.parse(a.target.innerText))}catch(e){setTimeout((()=>{if(a.target instanceof HTMLElement)try{E(JSON.parse(a.target.innerText))}catch(e){q(e)}}),1e3)}}),400)}var t})).observe(T,{attributes:!0,childList:!0,subtree:!0})}(); +!function(){"use strict";function e(e){if(null==e)throw"item is null or undefined";return e}function t(e){if(null==e)throw"item is null or undefined";if(e instanceof HTMLButtonElement)return e;throw"item is not a button"}function n(t,n){e(document.getElementById(t)).innerText=n}function a(e,t,n){document.getElementById(e)?.setAttribute(t,n)}function i(e,t){e instanceof Array?e.forEach((e=>{a(e,"style",t)})):a(e,"style",t)}function o(e){document.querySelectorAll(e).forEach((e=>e.remove()))}function r(e){document.getElementById(e)?.remove()}function l(e,t){document.getElementById(e)?.classList.remove(t)}function s(e){l(e,"hidden")}function c(e){document.getElementById(e).innerHTML+=''}function d(e){i(e,"background-color: #facc15; color: #000; display: flex; align-items: center; flex-direction: row-reverse; gap: 8px"),e instanceof Array?e.forEach((e=>{c(e)})):c(e)}const u="#a8a29e",g={"#0bd674":"Good","#ffcd1e":"Fair to Good","#ff9500":"Poor","#f4496d":"Very Poor","#a8a29e":"Flat"};let p,f,m,w,v,h,y,x,b,_,E,A;function I(e){const a=new Date(e.starting_at).getHours();let c=new Date(e.starting_at).getHours();if(a>20){let t=24-a;const n=e.wave_height_labels.length-(e.wave_height_labels.length-t)%24;c=0,f=e.wave_height_labels.slice(t,n),p=e.quality.slice(t,n),m=e.wave_height.slice(t,n),w=e.wind_speed.slice(t,n),v=e.wind_direction.slice(t,n),h=e.wind_gust.slice(t,n),y=e.wave_period.slice(t,n),x=e.temperature.slice(t,n),b=e.dewpoint.slice(t,n),_=e.cloud_cover.slice(t,n),E=e.probability_of_precipitation.slice(t,n),A=e.probability_of_thunder.slice(t,n)}else{const t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][new Date(e.starting_at).getDay()],n=[];for(let e=0;e=10&&e<12&&n.push(`${t} ${e} AM`),12===e&&n.push(`${t} ${e} PM`),e>12&&n.push(`${t} 0${e-12} PM`)):n.push(`${t} 12 AM`);const i=e.wave_height_labels.length+a-(e.wave_height_labels.length+a)%24;f=n.concat(e.wave_height_labels).slice(0,i),p=new Array(a).fill("#a8a29e").concat(e.quality).slice(0,i),m=new Array(a).fill(0).concat(e.wave_height).slice(0,i),w=new Array(a).fill(0).concat(e.wind_speed).slice(0,i),v=new Array(a).fill(0).concat(e.wind_direction).slice(0,i),h=new Array(a).fill(0).concat(e.wind_gust).slice(0,i),y=new Array(a).fill(0).concat(e.wave_period).slice(0,i),x=new Array(a).fill(0).concat(e.temperature).slice(0,i),b=new Array(a).fill(0).concat(e.dewpoint).slice(0,i),_=new Array(a).fill(0).concat(e.cloud_cover).slice(0,i),E=new Array(a).fill(0).concat(e.probability_of_precipitation).slice(0,i),A=new Array(a).fill(0).concat(e.probability_of_thunder).slice(0,i)}let I=(new Date).getHours();const q=document.getElementById("current-wave-height");""===q?.innerText&&(q.innerText=e.current_wave_height,"0"==e.current_wave_height&&(i("wave-quality",`background-color: ${u}`),n("wave-quality-text",g[u]),i("wave-quality-text",`color: ${u}`),o(".wave-quality-loader")),i("wave-icon",`transform: rotate(${e.current_wave_direction}deg);`),o(".wavey"));const T=document.getElementById("current-wave-period");""===T?.innerText&&(T.innerText=e.current_wave_period,r("wavey-period-loader")),n("legend-label",f[I]),n("legend-quality",g[p[I]]),n("legend-wave-height",m[I]),n("legend-wind-speed",w[I]),i("legend-wind-icon",`transform: rotate(${v[I]+180}deg);`),n("legend-wave-period",y[I]),n("legend-wind-gust",h[I]),n("forecast-as-of",`Updated ${e.as_of}`),n("forecast-as-of-2",`Updated ${e.as_of}`);new Date(e.as_of){e.corsair={x:0,y:0}},afterDraw:(e,t,n)=>{if(e.tooltip?._active?.length){let t=e.tooltip._active[0].element.x,a=e.scales.y,i=e.ctx;i.save(),i.beginPath(),i.moveTo(t,a.top),i.lineTo(t,a.bottom),i.lineWidth=1,i.setLineDash(n.dash),i.strokeStyle="#fff",i.stroke(),i.restore()}if(I-c>H){const t=e.ctx,n=e.scales.x.getPixelForValue(I-c);t.save(),t.strokeStyle="#5b5b58",t.lineWidth=1,t.beginPath(),t.moveTo(n,0),t.lineTo(n,e.height),t.stroke(),t.fillStyle="#5b5b58",t.font="bold 1rem ui-sans-serif, system-ui, sans-serif",t.fillText("Now",I>14&&24===D?n-45:n+5,15),t.restore()}}};function k(e){let t;t=e>=f.length-a?f.length-a-1:e;$(t+(0===H?c:H))}function $(e){const t=p[e];i("legend",`background-color: ${t}`),n("legend-label",f[e]),n("legend-quality",g[t]),n("legend-wave-height",m[e]),n("legend-wind-speed",w[e]),i("legend-wind-icon",`transform: rotate(${v[e]+180}deg);`),n("legend-wave-period",y[e]),n("legend-wind-gust",h[e]),n("temperature-legend-label",f[e]),n("temperature-legend-temperature",x[e]),n("temperature-legend-dewpoint",b[e]),n("precipitation-legend-label",f[e]),n("precipitation-legend-precipitation",E[e]),n("precipitation-legend-thunder",A[e]),n("precipitation-legend-cloud-cover",_[e])}const M=(e,t,n)=>{const a=Chart.helpers.getRelativePosition(e,n),i=function(e){return 24===D||48===D?e&&e>0?e>=m.length-H?m.length-H-1:e:0:e&&e>0?e>=m.length?m.length-1:e:0}(n.scales.x.getValueForPixel(a.x));k(i)},L=(e,t)=>{const n=0===H?c:H;return 24===D?t%6==0?f[t+n]:null:48===D?t%8==0?f[t+n]:null:t%24==0?f[t+n]:null};const S=()=>window.innerWidth<768?24:window.innerWidth<1024?48:m.length;let D=S(),H=0,C=H+D;const F={size:24===D?14:18,weight:"semi-bold"},P=e=>({aspectRatio:1.75,onHover:M,borderRadius:5,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{enabled:!1}},responsive:!0,interaction:{intersect:!1,axis:"x"},scales:{x:{ticks:{callback:L}},y:{grid:{color:"#1B1B1B"},beginAtZero:!0,max:e??10,ticks:{callback:function(e){return e%2!=0?"":e},font:F}}}}),N=new Chart(document.getElementById("forecast"),{type:"bar",plugins:[B],data:{labels:0===H?f.slice(c,C):f.slice(H,C),datasets:[{label:"wave height (feet)",data:0===H?m.slice(c,C):m.slice(H,C),pointStyle:!1,minBarLength:.1}]},options:{...P(void 0),elements:{bar:{backgroundColor:e=>(e=>0===H?p[e.dataIndex+c]:p[e.dataIndex+H])(e)||"#4ade80"}}}});function O(e){n("forecast-range",e)}function J(){if(0===H){let e=a>20&&(new Date).getHours()>20;O(24===D?e?"Tomorrow":"Today":e?`Tomorrow - ${f[H+25].split(" ")[0]}`:"Today - Tomorrow")}else if(24===D)O(f[H].split(" ")[0]);else{const e=f[C-1]??f[f.length-1];O(`${f[H].split(" ")[0]} - ${e.split(" ")[0]}`)}}function W(){const e=0===H?c:H;let t=f.slice(e,C);N.data.labels=t,N.data.datasets[0].data=m.slice(e,C),N.update(),V.data.labels=t,V.data.datasets[0].data=x.slice(e,C),V.update(),j.data.labels=t,j.data.datasets[0].data=E.slice(e,C),j.update()}J(),window.addEventListener("resize",(()=>{D=S(),H+D>f.length?(C=f.length,H=f.length-D):C=H+D,W(),k(0),0===H&&(t(document.getElementById("forecast-backward")).disabled=!0),H+D=m.length&&(t(document.getElementById("forecast-foreward")).disabled=!0),H>0&&(t(document.getElementById("forecast-backward")).disabled=!1),J()})),document.getElementById("forecast-backward")?.addEventListener("click",(()=>{H-D<0?(H=0,C=D):(C-=D,H-=D),W(),0===H?$(I):k(0),0===H&&(t(document.getElementById("forecast-backward")).disabled=!0),H+D{C+D>f.length?(C=f.length,H=C-D):(H+=D,C+=D),W(),k(0),H+D>=m.length&&(t(document.getElementById("forecast-foreward")).disabled=!0),H>0&&(t(document.getElementById("forecast-backward")).disabled=!1),J()}));const R=(e,t,n)=>({type:"bar",plugins:[B],data:{labels:0===H?f.slice(c,C):f.slice(H,C),datasets:[{label:n,data:e,pointStyle:!1,minBarLength:.1}]},options:{...P(100),elements:{bar:t?{backgroundColor:t,borderColor:t}:{}}}}),U=document.getElementById("temperature-forecast"),V=new Chart(U,R(0===H?x.slice(c,C):x.slice(H,C),"pink","F")),Z=document.getElementById("precipitation-forecast"),j=new Chart(Z,R(0===H?E.slice(c,C):E.slice(H,C),null,"%"));function z(e){const t=N.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;V.tooltip.setActiveElements([{datasetIndex:e,index:n}]),V.setActiveElements([{datasetIndex:e,index:n}]),V.update(),j.tooltip.setActiveElements([{datasetIndex:e,index:n}]),j.setActiveElements([{datasetIndex:e,index:n}]),j.update()}else V.tooltip.setActiveElements([],{x:0,y:0}),V.setActiveElements([],{x:0,y:0}),V.update(),j.tooltip.setActiveElements([],{x:0,y:0}),j.setActiveElements([],{x:0,y:0}),j.update()}function G(e){const t=V.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;N.tooltip.setActiveElements([{datasetIndex:e,index:n}]),N.setActiveElements([{datasetIndex:e,index:n}]),N.update(),j.tooltip.setActiveElements([{datasetIndex:e,index:n}]),j.setActiveElements([{datasetIndex:e,index:n}]),j.update()}else N.tooltip.setActiveElements([],{x:0,y:0}),N.setActiveElements([],{x:0,y:0}),N.update(),j.tooltip.setActiveElements([],{x:0,y:0}),j.setActiveElements([],{x:0,y:0}),j.update()}function K(e){const t=j.getElementsAtEventForMode(e,"nearest",{axis:"x",intersect:!1},!0);if(t[0]){const e=t[0].datasetIndex,n=t[0].index;V.tooltip.setActiveElements([{datasetIndex:e,index:n}]),V.setActiveElements([{datasetIndex:e,index:n}]),V.update(),N.tooltip.setActiveElements([{datasetIndex:e,index:n}]),N.setActiveElements([{datasetIndex:e,index:n}]),N.update()}else V.tooltip.setActiveElements([],{x:0,y:0}),V.setActiveElements([],{x:0,y:0}),V.update(),N.tooltip.setActiveElements([],{x:0,y:0}),N.setActiveElements([],{x:0,y:0}),N.update()}N.canvas.onmousemove=z,V.canvas.onmousemove=G,j.canvas.onmousemove=K,N.canvas.ontouchmove=z,V.canvas.ontouchmove=G,j.canvas.ontouchmove=K}function q(t){t.wave_height&&(n("current-wave-height",t.wave_height),i("wave-icon",`transform: rotate(${t.wave_direction}deg);`),o(".wavey")),t.wave_period&&(n("current-wave-period",t.wave_period),r("wavey-period-loader")),(""===e(document.getElementById("wave-quality-text")).innerText||t.wave_height||parseFloat(e(document.getElementById("current-wave-height")).innerText??"0")>=1)&&(i("wave-quality",`background-color: ${t.quality_color};`),n("wave-quality-text",t.quality_text),i("wave-quality-text",`color: ${t.quality_color}`),o(".wave-quality-loader")),n("current-water-temp",t.water_temp),n("current-air-temp",t.air_temp),n("current-air-temp-2",t.air_temp),n("wind",T(t)),n("as-of",`As of ${t.as_of}`),i("wind-icon",`transform: rotate(${t.wind_direction+180}deg);`),o(".latest-loader"),s("wind-icon-container"),s("wave-icon-container"),l("as-of-container","animate-pulse"),s("wave-quality"),t.loaded_from_fallback&&s("wave-fallback-icon");new Date(t.as_of)e.wind_speed===e.gusts||"0"===e.gusts?e.wind_speed:`${e.wind_speed}-${e.gusts}`;function B(t){var n,a;r("forecast-container"),n="forecast-error",a=`\n
\n

\n Error loading forecast data - please refresh the page or try again later.\n

\n

${t}

\n
\n `,e(document.getElementById(n)).innerHTML=a}const k=e(document.querySelector("body"));new MutationObserver((e=>{for(const a of e)if(a.target instanceof HTMLElement&&("realtime-data"===a.target.id&&q(JSON.parse(a.target.innerText)),"water-quality-data"===a.target.id&&(t=JSON.parse(a.target.innerText),o(".water-quality-loader"),s("current-water-quality"),n("current-water-quality-title","Closed for season"===t.water_quality?"-----":t.water_quality.toUpperCase()),n("current-water-quality-status-text",t.water_quality_text),"Advisory"===t.water_quality&&i("current-water-quality-title","color: #facc15;"),"Closed"===t.water_quality&&i("current-water-quality-title","color: #ef4444;")),"forecast-data"===a.target.id))try{I(JSON.parse(a.target.innerText))}catch{setTimeout((()=>{if(a.target instanceof HTMLElement)try{I(JSON.parse(a.target.innerText))}catch(e){setTimeout((()=>{if(a.target instanceof HTMLElement)try{I(JSON.parse(a.target.innerText))}catch(e){B(e)}}),1e3)}}),400)}var t})).observe(k,{attributes:!0,childList:!0,subtree:!0})}(); diff --git a/client/parsers/forecast.js b/client/parsers/forecast.js index f4fc19c..9b7d4f4 100644 --- a/client/parsers/forecast.js +++ b/client/parsers/forecast.js @@ -6,6 +6,7 @@ import { removeElement, removeElements, asButton, + outOfDate, } from "../utilities"; const FLAT_COLOR = "#a8a29e"; @@ -215,6 +216,11 @@ export function parseForecast(data) { setText("forecast-as-of", `Updated ${data.as_of}`); setText("forecast-as-of-2", `Updated ${data.as_of}`); + let oneDayMs = 60 * 60 * 24 * 1_000; + if (new Date(data.as_of) < new Date() - oneDayMs) { + outOfDate(["forecast-as-of-container-2", "forecast-as-of-container"]); + } + removeElements(".loader"); removeHidden("forecast"); removeHidden("wave-quality"); diff --git a/client/parsers/realtime.js b/client/parsers/realtime.js index 7f21a70..88c9d3c 100644 --- a/client/parsers/realtime.js +++ b/client/parsers/realtime.js @@ -7,6 +7,7 @@ import { removeStyle, removeHidden, setAttribute, + outOfDate, } from "../utilities"; /** @@ -92,14 +93,7 @@ export function parseRealtime(data) { let oneDayMs = 60 * 60 * 24 * 1_000; if (new Date(data.as_of) < new Date() - oneDayMs) { - setStyleAttribute( - "as-of-container", - "background-color: #facc15; color: #000; display: flex; align-items: center; flex-direction: row-reverse; gap: 8px", - ); - document.getElementById("as-of-container").innerHTML += - ``; + outOfDate("as-of-container"); } } diff --git a/client/utilities.js b/client/utilities.js index f6ec85f..ce37827 100644 --- a/client/utilities.js +++ b/client/utilities.js @@ -110,3 +110,35 @@ export function removeHidden(id) { export function appendElements(id, html) { nonNull(document.getElementById(id)).innerHTML = html; } + +/** + * Appends the caution svg to an element's innerHTML + * + * @param {string} id + */ +function appendCaution(id) { + document.getElementById(id).innerHTML += + ``; +} + +/** + * Updates the as of container to show it is out of date + * + * @param {string | string[]} id + */ +export function outOfDate(id) { + setStyleAttribute( + id, + "background-color: #facc15; color: #000; display: flex; align-items: center; flex-direction: row-reverse; gap: 8px", + ); + + if (id instanceof Array) { + id.forEach((i) => { + appendCaution(i); + }); + } else { + appendCaution(id); + } +} diff --git a/templates/base.html b/templates/base.html index 0e60f87..3eaacab 100644 --- a/templates/base.html +++ b/templates/base.html @@ -37,7 +37,7 @@ rel="stylesheet" /> - + @@ -66,7 +66,7 @@ @keyup.escape="showLiveFeed = false; showNav = false;" :class="{ 'overflow-hidden': showNav || showLiveFeed }" > - + {% block body %} {% endblock %} {% include "includes/footer.html" %} {% if live_reload %}