windelsis
Version:
`Windelsis` is a JavaScript library that visualizes weather data on interactive maps using Leaflet. It provides tools to render temperature, precipitation, and wind velocity layers, as well as utilities for grid-based weather data management.
1 lines • 41.7 kB
JavaScript
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Windelsis=e():t.Windelsis=e()}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var a in i)t.o(i,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:i[a]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};return(()=>{L.DomUtil.setTransform||(L.DomUtil.setTransform=function(t,e,i){var a=e||new L.Point(0,0);t.style[L.DomUtil.TRANSFORM]=(L.Browser.ie3d?"translate("+a.x+"px,"+a.y+"px)":"translate3d("+a.x+"px,"+a.y+"px,0)")+(i?" scale("+i+")":"")}),L.CanvasLayer=(L.Layer?L.Layer:L.Class).extend({initialize:function(t){this._map=null,this._canvas=null,this._frame=null,this._delegate=null,L.setOptions(this,t)},delegate:function(t){return this._delegate=t,this},needRedraw:function(){return this._frame||(this._frame=L.Util.requestAnimFrame(this.drawLayer,this)),this},_onLayerDidResize:function(t){this._canvas.width=t.newSize.x,this._canvas.height=t.newSize.y},_onLayerDidMove:function(){var t=this._map.containerPointToLayerPoint([0,0]);L.DomUtil.setPosition(this._canvas,t),this.drawLayer()},getEvents:function(){var t={resize:this._onLayerDidResize,moveend:this._onLayerDidMove};return this._map.options.zoomAnimation&&L.Browser.any3d&&(t.zoomanim=this._animateZoom),t},onAdd:function(t){this._map=t,this._canvas=L.DomUtil.create("canvas","leaflet-layer"),this.tiles={};var e=this._map.getSize();this._canvas.width=e.x,this._canvas.height=e.y;var i=this._map.options.zoomAnimation&&L.Browser.any3d;L.DomUtil.addClass(this._canvas,"leaflet-zoom-"+(i?"animated":"hide")),this.options.pane.appendChild(this._canvas),t.on(this.getEvents(),this);var a=this._delegate||this;a.onLayerDidMount&&a.onLayerDidMount(),this.needRedraw();var n=this;setTimeout((function(){n._onLayerDidMove()}),0)},onRemove:function(t){var e=this._delegate||this;e.onLayerWillUnmount&&e.onLayerWillUnmount(),this.options.pane.removeChild(this._canvas),t.off(this.getEvents(),this),this._canvas=null},addTo:function(t){return t.addLayer(this),this},drawLayer:function(){var t=this._map.getSize(),e=this._map.getBounds(),i=this._map.getZoom(),a=this._map.options.crs.project(this._map.getCenter()),n=this._map.options.crs.project(this._map.containerPointToLatLng(this._map.getSize())),o=this._delegate||this;o.onDrawLayer&&o.onDrawLayer({layer:this,canvas:this._canvas,bounds:e,size:t,zoom:i,center:a,corner:n}),this._frame=null},_setTransform:function(t,e,i){var a=e||new L.Point(0,0);t.style[L.DomUtil.TRANSFORM]=(L.Browser.ie3d?"translate("+a.x+"px,"+a.y+"px)":"translate3d("+a.x+"px,"+a.y+"px,0)")+(i?" scale("+i+")":"")},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),i=L.Layer?this._map._latLngToNewLayerPoint(this._map.getBounds().getNorthWest(),t.zoom,t.center):this._map._getCenterOffset(t.center)._multiplyBy(-e).subtract(this._map._getMapPanePos());L.DomUtil.setTransform(this._canvas,i,e)}}),L.canvasLayer=function(t){return new L.CanvasLayer(t)},L.Control.Velocity=L.Control.extend({options:{position:"bottomleft",emptyString:"Unavailable",angleConvention:"bearingCCW",showCardinal:!1,speedUnit:"m/s",directionString:"Direction",speedString:"Speed",onAdd:null,onRemove:null},onAdd:function(t){return this._container=L.DomUtil.create("div","leaflet-control-velocity"),L.DomEvent.disableClickPropagation(this._container),t.on("mousemove",this._onMouseMove,this),this.options.leafletVelocity.options.onAdd&&this.options.leafletVelocity.options.onAdd(),this._container},onRemove:function(t){t.off("mousemove",this._onMouseMove,this),this.options.leafletVelocity.options.onRemove&&this.options.leafletVelocity.options.onRemove()},vectorToSpeed:function(t,e,i){var a=Math.sqrt(Math.pow(t,2)+Math.pow(e,2));return"k/h"===i?this.meterSec2kilometerHour(a):"kt"===i?this.meterSec2Knots(a):"mph"===i?this.meterSec2milesHour(a):a},vectorToDegrees:function(t,e,i){i.endsWith("CCW")&&(e=e>0?e=-e:Math.abs(e));var a=Math.sqrt(Math.pow(t,2)+Math.pow(e,2)),n=180*Math.atan2(t/a,e/a)/Math.PI+180;return"bearingCW"!==i&&"meteoCCW"!==i||(n+=180)>=360&&(n-=360),n},degreesToCardinalDirection:function(t){var e="";return t>=0&&t<11.25||t>=348.75?e="N":t>=11.25&&t<33.75?e="NNW":t>=33.75&&t<56.25?e="NW":t>=56.25&&t<78.75?e="WNW":t>=78.25&&t<101.25?e="W":t>=101.25&&t<123.75?e="WSW":t>=123.75&&t<146.25?e="SW":t>=146.25&&t<168.75?e="SSW":t>=168.75&&t<191.25?e="S":t>=191.25&&t<213.75?e="SSE":t>=213.75&&t<236.25?e="SE":t>=236.25&&t<258.75?e="ESE":t>=258.75&&t<281.25?e="E":t>=281.25&&t<303.75?e="ENE":t>=303.75&&t<326.25?e="NE":t>=326.25&&t<348.75&&(e="NNE"),e},meterSec2Knots:function(t){return t/.514},meterSec2kilometerHour:function(t){return 3.6*t},meterSec2milesHour:function(t){return 2.23694*t},_onMouseMove:function(t){var e=this.options.leafletVelocity._map.containerPointToLatLng(L.point(t.containerPoint.x,t.containerPoint.y));this.options.leafletVelocity._windy.interpolatePoint(e.lng,e.lat);this._container.innerHTML=""}}),L.Map.mergeOptions({positionControl:!1}),L.Map.addInitHook((function(){this.options.positionControl&&(this.positionControl=new L.Control.MousePosition,this.addControl(this.positionControl))})),L.control.velocity=function(t){return new L.Control.Velocity(t)},L.VelocityLayer=(L.Layer?L.Layer:L.Class).extend({options:{displayValues:!0,displayOptions:{velocityType:"Velocity",position:"bottomleft",emptyString:"No velocity data"},maxVelocity:10,colorScale:null,data:null},_map:null,_canvasLayer:null,_windy:null,_context:null,_timer:0,_mouseControl:null,initialize:function(t){L.setOptions(this,t)},onAdd:function(t){this._paneName=this.options.paneName||"overlayPane";var e=t._panes.overlayPane;t.getPane&&((e=t.getPane(this._paneName))||(e=t.createPane(this._paneName))),this._canvasLayer=L.canvasLayer({pane:e}).delegate(this),this._canvasLayer.addTo(t),this._map=t},onRemove:function(t){this._destroyWind()},setData:function(t){this.options.data=t,this._windy&&(this._windy.setData(t),this._clearAndRestart()),this.fire("load")},setOpacity:function(t){this._canvasLayer.setOpacity(t)},setOptions:function(t){this.options=Object.assign(this.options,t),t.hasOwnProperty("displayOptions")&&(this.options.displayOptions=Object.assign(this.options.displayOptions,t.displayOptions),this._initMouseHandler(!0)),t.hasOwnProperty("data")&&(this.options.data=t.data),this._windy&&(this._windy.setOptions(t),t.hasOwnProperty("data")&&this._windy.setData(t.data),this._clearAndRestart()),this.fire("load")},onDrawLayer:function(t,e){var i=this;this._windy?this.options.data&&(this._timer&&clearTimeout(i._timer),this._timer=setTimeout((function(){i._startWindy()}),750)):this._initWindy(this)},_startWindy:function(){var t=this._map.getBounds(),e=this._map.getSize();this.options.data[0].header.la1,this.options.data[0].header.la2,this.options.data[0].header.lo1,this.options.data[0].header.lo2;this._windy.start([[0,0],[e.x,e.y]],e.x,e.y,[[t._southWest.lng,t._southWest.lat],[t._northEast.lng,t._northEast.lat]])},_updateWindDuringDrag:function(){this._dragTimer&&clearTimeout(this._dragTimer),this._dragTimer=setTimeout((()=>{this._clearAndRestart()}),200)},_initWindy:function(e){var i=Object.assign({canvas:e._canvasLayer._canvas,map:this._map},e.options);this._windy=new t(i),this._context=this._canvasLayer._canvas.getContext("2d"),this._canvasLayer._canvas.classList.add("velocity-overlay"),this.onDrawLayer(),this._map.on("drag",(t=>e._updateWindDuringDrag())),this._map.on("zoomstart",e._windy.stop),this._map.on("zoomend",e._clearAndRestart),this._map.on("resize",e._clearWind),this._initMouseHandler(!1)},_initMouseHandler:function(t){if(t&&(this._map.removeControl(this._mouseControl),this._mouseControl=!1),!this._mouseControl&&this.options.displayValues){var e=this.options.displayOptions||{};e.leafletVelocity=this,this._mouseControl=L.control.velocity(e).addTo(this._map)}},_clearAndRestart:function(){this._context&&this._context.clearRect(0,0,3e3,3e3),this._windy&&this._startWindy()},_clearWind:function(){this._windy&&this._windy.stop(),this._context&&this._context.clearRect(0,0,3e3,3e3)},_destroyWind:function(){this._timer&&clearTimeout(this._timer),this._windy&&this._windy.stop(),this._context&&this._context.clearRect(0,0,3e3,3e3),this._mouseControl&&this._map.removeControl(this._mouseControl),this._mouseControl=null,this._windy=null,this._map.removeLayer(this._canvasLayer)}}),L.velocityLayer=function(t){return new L.VelocityLayer(t)};var t=function(t){var e,i,a,n,o,r,s,l,d,h,c=t.minVelocity||0,p=t.maxVelocity||10,u=(t.velocityScale||.005)*(Math.pow(window.devicePixelRatio,1/3)||1),m=t.particleAge||90,y=t.lineWidth||1,g=t.particleMultiplier||1/300,_=Math.pow(window.devicePixelRatio,1/3)||1.6,v=t.frameRate||15,f=1e3/v,w=.97,D=t.colorScale||["rgb(36,104, 180)","rgb(60,157, 194)","rgb(128,205,193 )","rgb(151,218,168 )","rgb(198,231,181)","rgb(238,247,217)","rgb(255,238,159)","rgb(252,217,125)","rgb(255,182,100)","rgb(252,150,75)","rgb(250,112,52)","rgb(245,64,32)","rgb(237,45,28)","rgb(220,24,32)","rgb(180,0,35)"],x=[NaN,NaN,null],b=t.data,M=function(t,e,i,a,n,o){var r=1-t,s=1-e,l=r*s,d=t*s,h=r*e,c=t*e,p=i[0]*l+a[0]*d+n[0]*h+o[0]*c,u=i[1]*l+a[1]*d+n[1]*h+o[1]*c;return[p,u,Math.sqrt(p*p+u*u)]},P=function(t){var e=null,i=null;return t.forEach((function(t){switch(t.header.parameterCategory+","+t.header.parameterNumber){case"1,2":case"2,2":e=t;break;case"1,3":case"2,3":i=t;break;default:0}})),function(t,e){var i=t.data,a=e.data;return{header:t.header,data:function(t){return[i[t],a[t]]},interpolate:M}}(e,i)},C=function(t,a){if(!i)return null;var l,d=S(t-n,360)/r,h=(o-a)/s,c=Math.floor(d),p=c+1,u=Math.floor(h),m=u+1;if(l=i[u]){var y=l[c],g=l[p];if(W(y)&&W(g)&&(l=i[m])){var _=l[c],v=l[p];if(W(_)&&W(v))return e.interpolate(d-c,h-u,y,g,_,v)}}return null},W=function(t){return null!=t},S=function(t,e){return t-e*Math.floor(t/e)},T=function(t,e,i,a,n,o,r){var s=r[0]*o,l=r[1]*o,d=O(t,e,i,a,n);return r[0]=d[0]*s+d[2]*l,r[1]=d[1]*s+d[3]*l,r},O=function(t,e,i,a,n){var o=2*Math.PI,r=e<0?5:-5,s=i<0?5:-5,l=R(i,e+r),d=R(i+s,e),h=Math.cos(i/360*o);return[(l[0]-a)/r/h,(l[1]-n)/r/h,(d[0]-a)/s,(d[1]-n)/s]},N=function(t,e,i){function a(e,i){var a=t[Math.round(e)];return a&&a[Math.round(i)]||x}a.release=function(){t=[]},a.randomize=function(t){var i,n,o=0;do{i=Math.round(Math.floor(Math.random()*e.width)+e.x),n=Math.round(Math.floor(Math.random()*e.height)+e.y)}while(null===a(i,n)[2]&&o++<30);return t.x=i,t.y=n,t},i(e,a)},z=function(t){return t/180*Math.PI},B=function(e,i,a){var n=t.map.containerPointToLatLng(L.point(e,i));return[n.lng,n.lat]},R=function(e,i,a){var n=t.map.latLngToContainerPoint(L.latLng(e,i));return[n.x,n.y]},E=function(e,i){var a,n,o=(a=c,n=p,D.indexFor=function(t){return Math.max(0,Math.min(D.length-1,Math.round((t-a)/(n-a)*(D.length-1))))},D),r=o.map((function(){return[]})),s=Math.round(e.width*e.height*g);/android|blackberry|iemobile|ipad|iphone|ipod|opera mini|webos/i.test(navigator.userAgent)&&(s*=_);for(var l="rgba(0, 0, 0, ".concat(w,")"),d=[],u=0;u<s;u++)d.push(i.randomize({age:Math.floor(Math.random()*m)+0}));var v=t.canvas.getContext("2d");v.lineWidth=y,v.fillStyle=l,v.globalAlpha=.6;var L=Date.now();!function t(){h=requestAnimationFrame(t);var a=Date.now(),n=a-L;n>f&&(L=a-n%f,r.forEach((function(t){t.length=0})),d.forEach((function(t){t.age>m&&(i.randomize(t).age=0);var e=t.x,a=t.y,n=i(e,a),s=n[2];if(null===s)t.age=m;else{var l=e+n[0],d=a+n[1];null!==i(l,d)[2]?(t.xt=l,t.yt=d,r[o.indexFor(s)].push(t)):(t.x=l,t.y=d)}t.age+=1})),v.globalCompositeOperation="destination-in",v.fillRect(e.x,e.y,e.width,e.height),v.globalCompositeOperation="lighter",v.globalAlpha=0===w?0:.9*w,r.forEach((function(t,e){t.length>0&&(v.beginPath(),v.strokeStyle=o[e],t.forEach((function(t){v.moveTo(t.x,t.y),v.lineTo(t.xt,t.yt),t.x=t.xt,t.y=t.yt})),v.stroke())})))}()},$=function(){A.field&&A.field.release(),h&&cancelAnimationFrame(h)},A={params:t,start:function(t,h,c,p){var m={south:z(p[0][1]),north:z(p[1][1]),east:z(p[1][0]),west:z(p[0][0]),width:h,height:c};$(),function(t,h){var c=!0;t.length<2&&(c=!1),c||console.log("Windy Error: data must have at least two components (u,v)");var p=(e=P(t)).header;if(p.hasOwnProperty("gridDefinitionTemplate")&&0!=p.gridDefinitionTemplate&&(c=!1),c||console.log("Windy Error: Only data with Latitude_Longitude coordinates is supported"),c=!0,n=p.lo1,o=p.la1,r=p.dx,s=p.dy,l=p.nx,d=p.ny,p.hasOwnProperty("scanMode")){var u=p.scanMode.toString(2),m=(u=("0"+u).slice(-8)).split("").map(Number).map(Boolean);m[0]&&(r=-r),m[1]&&(s=-s),m[2]&&(c=!1),m[3]&&(c=!1),m[4]&&(c=!1),m[5]&&(c=!1),m[6]&&(c=!1),m[7]&&(c=!1),c||console.log("Windy Error: Data with scanMode: "+p.scanMode+" is not supported.")}(a=new Date(p.refTime)).setHours(a.getHours()+p.forecastTime),i=[];for(var y=0,g=Math.floor(l*r)>=360,_=0;_<d;_++){for(var v=[],f=0;f<l;f++,y++)v[f]=e.data(y);g&&v.push(v[0]),i[_]=v}h({date:a,interpolate:C})}(b,(function(e){!function(t,e,i,a){var n={},o=(i.south-i.north)*(i.west-i.east),r=u*Math.pow(o,.4),s=[],l=e.x;function d(i){for(var a=[],o=e.y;o<=e.yMax;o+=2){var l=B(i,o);if(l){var d=l[0],h=l[1];if(isFinite(d)){var c=t.interpolate(d,h);c&&(c=T(n,d,h,i,o,r,c),a[o+1]=a[o]=c)}}}s[i+1]=s[i]=a}!function t(){for(var i=Date.now();l<e.width;)if(d(l),l+=2,Date.now()-i>1e3)return void setTimeout(t,25);N(s,e,a)}()}(e,function(t,e,i){var a=t[0],n=t[1],o=Math.round(a[0]),r=Math.max(Math.floor(a[1],0),0);return Math.min(Math.ceil(n[0],e),e-1),{x:o,y:r,xMax:e,yMax:Math.min(Math.ceil(n[1],i),i-1),width:e,height:i}}(t,h,c),m,(function(t,e){A.field=e,E(t,e)}))}))},stop:$,createField:N,interpolatePoint:C,setData:function(t){b=t},setOptions:function(t){t.hasOwnProperty("minVelocity")&&(c=t.minVelocity),t.hasOwnProperty("maxVelocity")&&(p=t.maxVelocity),t.hasOwnProperty("velocityScale")&&(u=(t.velocityScale||.005)*(Math.pow(window.devicePixelRatio,1/3)||1)),t.hasOwnProperty("particleAge")&&(m=t.particleAge),t.hasOwnProperty("lineWidth")&&(y=t.lineWidth),t.hasOwnProperty("particleMultiplier")&&(g=t.particleMultiplier),t.hasOwnProperty("opacity")&&(w=+t.opacity),t.hasOwnProperty("frameRate")&&(v=t.frameRate),f=1e3/v}};return A};window.cancelAnimationFrame||(window.cancelAnimationFrame=function(t){clearTimeout(t)})})(),(()=>{function i(t,e){if(t<=e[0].value){const[t,i,a]=e[0].color;return{r:t,g:i,b:a}}if(t>=e[e.length-1].value){const[t,i,a]=e[e.length-1].color;return{r:t,g:i,b:a}}for(let i=0;i<e.length-1;i++){const a=e[i],n=e[i+1];if(t>=a.value&&t<=n.value){const e=(t-a.value)/(n.value-a.value);return{r:Math.round(a.color[0]+e*(n.color[0]-a.color[0])),g:Math.round(a.color[1]+e*(n.color[1]-a.color[1])),b:Math.round(a.color[2]+e*(n.color[2]-a.color[2]))}}}const i=e[e.length-1].color;return{r:i[0],g:i[1],b:i[2]}}t.r(e),t.d(e,{MapManager:()=>p});const a={temperature:[{value:-15,color:[113,190,207]},{value:-8,color:[137,204,197]},{value:-4,color:[120,184,206]},{value:0,color:[98,129,207]},{value:1,color:[128,167,132]},{value:10,color:[181,202,96]},{value:21,color:[242,177,59]},{value:30,color:[235,96,49]},{value:47,color:[112,45,21]}],precipitation:[{value:0,color:[255,255,255]},{value:1,color:[200,255,255]},{value:5,color:[100,200,255]},{value:10,color:[0,100,255]},{value:25,color:[0,0,255]},{value:50,color:[128,0,255]}]};class n{constructor(t,e,i={}){this.map=t,this.data=e,this.canvasLayer=null,this._timer=null,this.options=Object.assign({pixelSize:5,opacity:.3,controlName:"Data Layer",layerControl:t.layerControl,colorScale:a.temperature,demoMode:!1},i)}init(){this._paneName=this.options.paneName||"overlayPane";var t=this.map._panes.overlayPane;return this.map.getPane&&((t=this.map.getPane(this._paneName))||(t=this.map.createPane(this._paneName))),this.canvasLayer=L.canvasLayer({pane:t}).delegate(this),this.options.layerControl.addOverlay(this.canvasLayer,this.options.controlName),this.canvasLayer}onDrawLayer(t){this.data&&this.data.data&&0!==this.data.data.length?(this._timer&&clearTimeout(this._timer),this._timer=setTimeout((()=>{const e=t.canvas.getContext("2d",{willReadFrequently:!0});e.clearRect(0,0,t.canvas.width,t.canvas.height),e.globalAlpha=this.options.opacity,e.globalCompositeOperation="multiply";const a=t.canvas.width,n=t.canvas.height,o=e.getImageData(0,0,a,n),r=o.data;for(let t=0;t<n;t++)for(let e=0;e<a;e++){const n=this.map.containerPointToLatLng([e,t]),o=this.interpolateValue(n.lat,n.lng);if(null==o||Number.isNaN(o))continue;const{r:s,g:l,b:d}=i(o,this.options.colorScale),h=Math.floor(255*this.options.opacity),c=4*(t*a+e);r[c]=s,r[c+1]=l,r[c+2]=d,r[c+3]=h}if(this.options.demoMode){const t=this.data.header,e=t.nx,i=t.ny,o=t.dx,s=t.dy,l=t.lo1,d=t.la1;for(let t=0;t<i;t++)for(let i=0;i<e;i++){const e=d-t*s,h=l+i*o,c=this.map.latLngToContainerPoint([e,h]),p=Math.round(c.x),u=Math.round(c.y);if(p>=0&&p<a&&u>=0&&u<n){const t=4*(u*a+p);r[t]=0,r[t+1]=0,r[t+2]=0,r[t+3]=255}}}e.putImageData(o,0,0)}),100)):console.log(this.data,"No available data to draw")}interpolateValue(t,e){const{header:i,data:a}=this.data,{lo1:n,lo2:o,la1:r,la2:s,nx:l,ny:d,dx:h,dy:c}=i,p=Math.floor((r-t)/c),u=Math.floor((e-n)/h);if(p<0||p>=d-1||u<0||u>=l-1)return null;const m=a[p*l+u],y=a[p*l+(u+1)],g=a[(p+1)*l+u],_=n+u*h,v=n+(u+1)*h,f=r-p*c,w=m+(y-m)*(e-_)/(v-_);return w+(g+(a[(p+1)*l+(u+1)]-g)*(e-_)/(v-_)-w)*(t-f)/(r-(p+1)*c-f)}update(t){this.data=t,this.canvasLayer&&this.map.hasLayer(this.canvasLayer)&&this.canvasLayer.needRedraw()}setOptions(t={}){return Object.assign(this.options,t),this}_clearTemperature(){if(this.canvasLayer&&this.canvasLayer._canvas){this.canvasLayer._canvas.getContext("2d").clearRect(0,0,this.canvasLayer._canvas.width,this.canvasLayer._canvas.height)}}_destroyTemperatureLayer(){this._timer&&clearTimeout(this._timer),this._clearTemperature(),this.canvasLayer&&(this.map.removeLayer(this.canvasLayer),this.canvasLayer=null)}}class o{constructor(t,e){this.latitude=t,this.longitude=e,this.id=h.generatePointKey(t,e),this.weatherData={weather_units:{temperature:"°C",wind_speed:"m/s",wind_direction:"°",precipitation:"mm",precipitation_prob:"%"},temperature:null,wind:{speed:null,direction:null},precipitation:null,precipitation_prob:null,timestamp:null,rawData:null},this.windComponents={u:null,v:null}}setWeatherData(t){if(this.weatherData={...t,temperature:t.temperature??0,wind:{speed:t.wind?.speed??0,direction:t.wind?.direction??0},precipitation:t.precipitation??0,precipitation_prob:t.precipitation_prob??0,timestamp:t.timestamp??null,rawData:t.rawData??null},null!==this.weatherData.wind.speed&&null!==this.weatherData.wind.direction){const{u:t,v:e}=h.convertWindDirection(this.weatherData.wind.speed,this.weatherData.wind.direction);this.windComponents.u=t,this.windComponents.v=e}}convertSpeed(t,e){return"km/h"===e?.27778*t:t}getTemperature(){return this.weatherData.temperature}getPrecipitation(){return this.weatherData.precipitation}getWindSpeed(){return this.weatherData.wind?.speed}getWindDirection(){return this.weatherData.wind?.direction}getWindComponents(){return this.windComponents}isStale(){if(!this.weatherData.timestamp)return!0;const t=new Date(Date.now()-36e5);return this.weatherData.timestamp<t}toString(){return`la:${this.latitude}, lo:${this.longitude}\nTemperature: ${this.weatherData.temperature}°C\nWind: speed ${this.weatherData.wind.speed}m/s | direction ${this.weatherData.wind.direction}°\nComponents: u ${this.u}m/s | v ${this.v}m/s)`}}function r(t,e,i=0){const a=e>.5?e:.5,{lat:n,lng:o}=t.getSouthWest(),{lat:r,lng:s}=t.getNorthEast(),l=(t,e)=>e?Math.ceil(t/a)*a:Math.floor(t/a)*a,d=l(n,!1)-i,h=l(o,!1)-i,c=l(r,!0)+i,p=l(s,!0)+i,u=L.latLngBounds(L.latLng(d,h),L.latLng(c,p)),m=u.getEast()-u.getWest(),y=u.getNorth()-u.getSouth(),g=Math.round(m/e)+1,_=Math.round(y/e)+1;return{bounds:u,cols:g,rows:_,total:g*_}}function s(t,e="temperature"){const{bounds:i,dx:a,dy:n,nx:r,ny:s,gridPointsMap:d}=t;let h=i.getSouthWest().lat,c=i.getNorthWest().lat,p=i.getSouthWest().lng,u=i.getSouthEast().lng,m=[];for(let t=0;t<s;t++){let e=c-t*n;for(let t=0;t<r;t++){let i=p+t*a;if(e<h||i>u)continue;const n=l(e,i);let r=d.has(n)?d.get(n):new o(e,i);m.push(r)}}var y=[];for(let t=0;t<m.length;t++){const i="temperature"===e?m[t].getTemperature():m[t].getPrecipitation();y.push(i)}return{header:{lo1:i.getNorthWest().lng,lo2:i.getSouthEast().lng,la1:i.getNorthWest().lat,la2:i.getSouthEast().lat,nx:r,ny:s,dx:a,dy:n},data:y}}function l(t,e,i=4){return`${t.toFixed(i)}_${e.toFixed(i)}`}function d(t,e=.0625){const i=Math.abs(t.getNorthEast().lng-t.getSouthWest().lng),a=Math.abs(t.getNorthEast().lat-t.getSouthWest().lat);for(let t=0;t<16&&!(a<=.0625*t||i<=.0625*t);t++);return{nx:Math.ceil(i/e)+1,ny:Math.ceil(a/e)+1,dx:e,dy:e}}const h={generateRandomGridData:function(t){const e=20*Math.random()+5,i=10*Math.random()+5,a=360*Math.random(),n=5*Math.random();(t instanceof Map?Array.from(t.values()):t).forEach((t=>{const o=(e+(10*Math.random()-5)).toFixed(2),r=(i+(5*Math.random()-2.5)).toFixed(2),s=(a+(180*Math.random()-45)).toFixed(2),l=(n+(2*Math.random()-1)).toFixed(2),d={weather_units:{temperature:"°C",wind_speed:"m/s",wind_direction:"°",precipitation:"mm"},temperature:parseFloat(o),wind:{speed:parseFloat(r),direction:parseFloat(s)},precipitation:parseFloat(l),timestamp:(new Date).toISOString(),rawData:null};t.setWeatherData(d)}))},convertWindDirection:function(t,e){const i=e*(Math.PI/180);return{u:-t*Math.sin(i),v:-t*Math.cos(i)}},getBoundsAtZoom:function(t,e){const i=t.getCenter(),a=t.getPixelBounds(i,e),n=t.unproject(a.getBottomLeft(),e),o=t.unproject(a.getTopRight(),e);return L.latLngBounds(n,o)},calculateOptimalPointDistance:function(t,e){const i=[.0625,.125,.25,.5,1],a=e.maxGridPoints,n=e.mapAdjustment??0;if(null!=e.pointDistance){const{bounds:i,cols:a,rows:o,total:s}=r(t,e.pointDistance,n);return e.demoMode&&console.log(`Selected point distance: ${e.pointDistance}° (${o}x${a}=${s} points)`),{pointDistance:e.pointDistance,bounds:i,ny:a,nx:o}}for(const o of i){const{bounds:i,cols:s,rows:l,total:d}=r(t,o,n);if(d<=a)return e.demoMode&&console.log(`Selected point distance: ${o}° (${l}x${s}=${d} points)`),{pointDistance:o,bounds:i,ny:s,nx:l};e.demoMode&&console.log(`Distance: ${o}° would exceed maxPoints (${d}>${a})`)}const o=i[i.length-1],{bounds:s,cols:l,rows:d,total:h}=r(t,o,n);return e.demoMode&&console.log(`Fallback point distance: ${o}° (${d}x${l}=${h} points)`),{pointDistance:o,bounds:s,ny:l,nx:d}},weatherDataBuilder:s,tempDataBuilder:function(t){return s(t,"temperature")},precipDataBuilder:function(t){return s(t,"precipitation")},windyDataBuilder:function(t,e){const{bounds:i,dx:a,dy:n,nx:r,ny:s,gridPointsMap:d}=t;e.dateType,e.hour_index;let h=i.getSouthWest().lat,c=i.getNorthWest().lat,p=i.getSouthWest().lng,u=i.getSouthEast().lng,m=[];for(let t=0;t<s;t++){let e=c-t*n;for(let t=0;t<r;t++){let i=p+t*a;if(e<h||i>u)continue;const n=l(e,i);let r=d.has(n)?d.get(n):new o(e,i);m.push(r)}}var y=[],g=[];for(let t=0;t<m.length;t++){const{u:e,v:i}=m[t].getWindComponents();y.push(e),g.push(i)}return[{header:{parameterUnit:"m.s-1",parameterNumberName:"eastward_wind",parameterCategory:2,parameterNumber:2,lo1:i.getNorthWest().lng,lo2:i.getSouthEast().lng,la1:i.getNorthWest().lat,la2:i.getSouthEast().lat,nx:r,ny:s,dx:a,dy:n},data:y},{header:{parameterUnit:"m.s-1",parameterNumberName:"northward_wind",parameterCategory:2,parameterNumber:3,lo1:i.getNorthWest().lng,lo2:i.getSouthEast().lng,la1:i.getNorthWest().lat,la2:i.getSouthEast().lat,nx:r,ny:s,dx:a,dy:n},data:g}]},generatePointKey:l,buildPointsLookup:function(t){const e=new Map;return t.forEach((t=>{const i=l(t.latitude,t.longitude);e.set(i,t)})),e},calculateGridParameters:d,gridBuilder:function(t,e,i,a,n){n.demoMode&&(t.eachLayer((function(e){e instanceof L.Marker&&t.removeLayer(e)})),console.log("northWest",i.getNorthWest()),L.marker(i.getNorthWest()).addTo(t),console.log("northEast",i.getNorthEast()),L.marker(i.getNorthEast()).addTo(t),console.log("southWest",i.getSouthWest()),L.marker(i.getSouthWest()).addTo(t),console.log("southEast",i.getSouthEast()),L.marker(i.getSouthEast()).addTo(t));const{nx:r,ny:s,dx:h,dy:c}=d(i,e);n.demoMode&&console.log("nx:",r,"ny:",s,"dx:",h,"dy:",c);const p=[];let u=0,m=0;for(let t=0;t<s;t++){const e=i.getNorthWest().lat-t*c;for(let t=0;t<r;t++){const n=i.getNorthWest().lng+t*h,r=l(e,n);let s=a.get(r);s||(s=new o(e,n),a.set(r,s),p.push(s),u++),m++}}return n.demoMode&&(console.log("Puntos generados:",u),console.log("Puntos obviados:",m-u)),{bounds:i,pointDistance:e,grid:p,gridPointsMap:a,dx:h,dy:c,nx:r,ny:s}},updateWindyParameters:function(t=null,e){t&&t.setOptions(e)},adjustAndCount:r};async function c(t,e){const i=new Array(t.length),a=[];for(let i=0;i<t.length;i+=100){const n=t.slice(i,i+100),o=n.map((t=>t.latitude)).join(","),r=n.map((t=>t.longitude)).join(","),s="https://api.open-meteo.com/v1/forecast";let l="";switch(e.dateType){case"current":l=`${s}?latitude=${o}&longitude=${r}¤t=temperature_2m,wind_speed_10m,wind_direction_10m,precipitation,precipitation_probability&wind_speed_unit=ms`;break;case"forecast":l=`${s}?latitude=${o}&longitude=${r}&start_date=${e.start_date}&end_date=${e.end_date}&daily=temperature_2m_max,precipitation_sum,wind_speed_10m_max,wind_direction_10m_dominant,precipitation_probability_max&wind_speed_unit=ms`;break;case"forecast_hourly":l=`${s}?latitude=${o}&longitude=${r}&start_date=${e.start_date}&end_date=${e.end_date}&hourly=temperature_2m,precipitation,wind_speed_10m,wind_direction_10m,precipitation_probability&wind_speed_unit=ms`;break;default:throw new Error("Invalid date type")}console.log("Calling URL:",l),a.push(fetch(l).then((t=>{if(!t.ok)throw new Error(`HTTP error! status: ${t.status}`);return t.json()})).then((t=>({data:t,startIndex:i}))))}return(await Promise.all(a)).forEach((({data:t,startIndex:a})=>{(Array.isArray(t)?t:[t]).forEach(((t,n)=>{i[a+n]=function(t,e){if(!t||!t.current&&!t.hourly&&!t.daily)throw new Error("Invalid data format");const i=(e,i=0)=>{const a=t[e],n=t[`${e}_units`];return{temperature:a.temperature_2m_max?.[i]??a.temperature_2m?.[i]??a.temperature_2m,wind:{speed:a.wind_speed_10m_max?.[i]??a.wind_speed_10m?.[i]??a.wind_speed_10m,direction:a.wind_direction_10m_dominant?.[i]??a.wind_direction_10m?.[i]??a.wind_direction_10m},precipitation:a.precipitation_sum?.[i]??a.precipitation?.[i]??a.precipitation,precipitation_prob:a.precipitation_probability_max?.[i]??a.precipitation_probability?.[i]??a.precipitation_probability,weatherUnits:{temperature:n.temperature_2m_max??n.temperature_2m,windSpeed:n.wind_speed_10m_max??n.wind_speed_10m,windDirection:n.wind_direction_10m_dominant??n.wind_direction_10m,precipitation:n.precipitation_sum??n.precipitation,precipitationProb:n.precipitation_probability_max??n.precipitation_probability??"%"},timestamp:a.time?.[i]??a.time,rawData:t}};switch(e.dateType){case"current":return i("current");case"forecast":return i("daily",0);case"forecast_hourly":if(null==e.hour_index)throw new Error("hour_index is required for forecast_hourly");return i("hourly",e.hour_index);default:throw new Error("Invalid date type")}}(t,e)}))})),i}class p{constructor(t,e,i={}){this.apiCaller=e??c,this.map=null,this.velocityLayer=null,this.temperatureRenderer=null,this.precipitationRenderer=null,this.layerControl=null,this.isUpdating=!1,this.lastZoom=null,this.updateTimeout=null,this.currentGrid={bounds:null,pointDistance:null,grid:[],gridPointsMap:null,dx:null,dy:null,nx:null,ny:null},this.gridsMap=null,this.eventHandlers={moveend:null,zoomend:null,click:null},this.handlersPaused=!1,this.options={randomData:i.randomData??!0,demoMode:i.demoMode??!0,center:i.center||[42.8,-8],zoom:i.zoom||8,minZoom:i.minZoom||3,maxZoom:i.maxZoom||18,pointDistance:i.pointDistance??null,maxGridPoints:i.maxGridPoints??600,maxBounds:i.maxBounds?L.latLngBounds([i.maxBounds[0],i.maxBounds[1]]):null,mapAdjustment:i.mapAdjustment||0,windyParameters:{...this.getDefaultWindyParameters(),...i.windyParams},dateType:i.dateType||"current",start_date:i.start_date||null,end_date:i.end_date||null,hour_index:i.hour_index||null,layerControlPosition:i.layerControlPosition??"topleft",temp_color_scale:i.temp_color_scale??a.temperature,prec_color_scale:i.prec_color_scale??a.precipitation},this.initialize(t)}initialize(t){if("string"==typeof t)this.map=L.map(t,{center:this.options.center,zoom:this.options.zoom});else{if(!(t instanceof L.Map))throw new Error("Invalid mapId. It should be a string or an instance of L.Map");this.map=t}this.options.demoMode?this.setupBaseLayers():this.layerControl=L.control.layers({},null,{position:this.options.layerControlPosition}).addTo(this.map),this.currentGrid.gridPointsMap=new Map,this.gridsMap=new Map,this.initializeWindLayer(),this.initializeTemperatureLayer(),this.initializePrecipitationLayer(),this.initializeEventHandlers(),this.addLayerControlListeners()}getDefaultWindyParameters(){return{minVelocity:0,maxVelocity:10,velocityScale:.005,particleAge:90,lineWidth:1,particleMultiplier:1/300,frameRate:15,colorScale:["rgb(0, 0, 128)","rgb(0, 0, 255)","rgb(75, 0, 130)","rgb(138, 43, 226)","rgb(255, 0, 255)","rgb(255, 0, 200)","rgb(255, 0, 150)","rgb(255, 0, 100)","rgb(255, 0, 50)","rgb(255, 0, 0)"]}}getPointDistanceFromBounds(t){return h.calculateOptimalPointDistance(t,this.options)}getPointDistanceFromZoom(t){return t<=7?1:t>7&&t<=8?.5:t>8&&t<=9?.25:t>9&&t<11?.125:.0625}getWeatherDataAt(t,e){const{gridPointsMap:i,dx:a,dy:n,nx:o,ny:r,bounds:s}=this.currentGrid;if(!s)return null;const l=s.getNorthWest().lat,d=s.getSouthWest().lng,c=Math.floor((l-t)/n),p=Math.floor((e-d)/a);if(c<0||c>=r-1||p<0||p>=o-1)return null;const u=[{lat:l-c*n,lng:d+p*a},{lat:l-c*n,lng:d+(p+1)*a},{lat:l-(c+1)*n,lng:d+p*a},{lat:l-(c+1)*n,lng:d+(p+1)*a}].map((({lat:t,lng:e})=>i.get(h.generatePointKey(t,e))));if(u.some((t=>!t)))throw new Error("Missing grid points for interpolation");const[m,y,g,_]=u,[v,f]=[m.longitude,y.longitude],[w,D]=[m.latitude,g.latitude];if(this.options.demoMode){const t=L.rectangle([[w,v],[D,f]],{color:"red",weight:1}).addTo(this.map);this.map.once("click",(()=>this.map.removeLayer(t)))}const x=(i,a,n,o)=>(D-t)/(D-w)*((f-e)/(f-v)*i+(e-v)/(f-v)*a)+(t-w)/(D-w)*((f-e)/(f-v)*n+(e-v)/(f-v)*o),b=x(m.weatherData.temperature,y.weatherData.temperature,g.weatherData.temperature,_.weatherData.temperature),M=x(m.weatherData.precipitation,y.weatherData.precipitation,g.weatherData.precipitation,_.weatherData.precipitation),P=x(m.weatherData.wind.speed,y.weatherData.wind.speed,g.weatherData.wind.speed,_.weatherData.wind.speed),C=x(m.weatherData.wind.direction,y.weatherData.wind.direction,g.weatherData.wind.direction,_.weatherData.wind.direction);return{temperature:b,precipitation:M,precipitationProb:x(m.weatherData.precipitation_prob,y.weatherData.precipitation_prob,g.weatherData.precipitation_prob,_.weatherData.precipitation_prob),wind:{speed:P,direction:C}}}setupBaseLayers(){const t=L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"),e=L.tileLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"),i=L.tileLayer("http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png"),a=L.tileLayer("http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png");this.layerControl=L.control.layers({Satellite:e,OpenStreetMap:t,"Carto Db Dark":i,cartoDbLight:a},null,{position:this.options.layerControlPosition}).addTo(this.map),i.addTo(this.map)}destroy(){if(this.layerControl&&this.layerControl._layers)for(let t in this.layerControl._layers){const e=this.layerControl._layers[t];this.map.hasLayer(e.layer)&&this.map.removeLayer(e.layer)}this.layerControl&&(this.map.removeControl(this.layerControl),this.layerControl=null),this.map.off("moveend",this.eventHandlers.moveend),this.map.off("zoomend",this.eventHandlers.zoomend),this.map.off("click",this.eventHandlers.click),this.updateTimeout&&(clearTimeout(this.updateTimeout),this.updateTimeout=null),this.currentGrid={bounds:null,grid:[],gridPointsMap:null,pointDistance:null,dx:null,dy:null,nx:null,ny:null},this.gridsMap=null,this.isUpdating=!1,this.lastZoom=null}debounce(t,e){let i;return function(...a){clearTimeout(i),i=setTimeout((()=>t.apply(this,a)),e)}}initializeEventHandlers(){this.eventHandlers.moveend=this.debounce((()=>{if(0===this.gridsMap.size)return;const t=this.map.getBounds(),e=this.currentGrid.bounds;if(!(e.contains(t.getNorthEast())&&e.contains(t.getSouthWest()))){const{bounds:e}=h.adjustAndCount(this.options.maxBounds??t,this.currentGrid.pointDistance,this.options.mapAdjustment);this.currentGrid=h.gridBuilder(this.map,this.currentGrid.pointDistance,e,this.currentGrid.gridPointsMap,this.options),this.forceUpdate()}}),300),this.eventHandlers.zoomend=this.debounce((async()=>{if(0===this.gridsMap.size)return;const t=this.map.getBounds(),e=this.currentGrid.bounds,i=e.contains(t.getNorthEast())&&e.contains(t.getSouthWest());var{pointDistance:a,bounds:n}=this.getPointDistanceFromBounds(this.options.maxBounds??t);const o=a!==this.currentGrid.pointDistance;i&&!o||(a=this.options.pointDistance??a,this.currentGrid=h.gridBuilder(this.map,a,n,this.currentGrid.gridPointsMap,this.options),this.forceUpdate())}),300),this.eventHandlers.click=this.debounce((t=>{var e=t.latlng.lat,i=t.latlng.lng;const a={grid:[new o(e,i)]},n={randomData:this.options.randomData,dateType:this.options.dateType};if(this.options.demoMode){const t=this.fetchWeatherData(a,n);console.log("API data:\n",t)}const r=this.getWeatherDataAt(e,i);var s=`<b>Coordinates:</b><br>Lat: ${e.toFixed(5)}<br>Lng: ${i.toFixed(5)}<br>`;s+=r?`<b>Temperature:</b> ${r.temperature.toFixed(2)}°C<br><b>Precipitation:</b> ${r.precipitation.toFixed(2)} mm<br><b>Wind:</b> ${r.wind.speed.toFixed(2)} m/s, ${r.wind.direction.toFixed(0)}°<br><b>Precipitation Probability:</b> ${r.precipitationProb.toFixed(2)}%`:"<b>Warning:</b> The selected point is out of the bounds of the current grid.";L.popup({closeOnClick:!0,className:"windelsis-popup"}).setLatLng(t.latlng).setContent(s).openOn(this.map)}),300),this.map.on("moveend",this.eventHandlers.moveend),this.map.on("zoomend",this.eventHandlers.zoomend),this.map.on("click",this.eventHandlers.click)}pauseHandlers(){this.handlersPaused||(this.map.off("moveend",this.eventHandlers.moveend),this.map.off("zoomend",this.eventHandlers.zoomend),this.handlersPaused=!0,console.log("Handlers paused"))}resumeHandlers(){this.handlersPaused&&(this.map.on("moveend",this.eventHandlers.moveend),this.map.on("zoomend",this.eventHandlers.zoomend),this.handlersPaused=!1,this.eventHandlers.zoomend(),console.log("Handlers resumed"))}toggleUpdates(){return this.handlersPaused?this.resumeHandlers():this.pauseHandlers(),this.handlersPaused}addLayerControlListeners(){this.map.on("overlayadd",(t=>{t.layer===this.temperatureRenderer.canvasLayer?(this.map.hasLayer(this.precipitationRenderer.canvasLayer)&&this.map.removeLayer(this.precipitationRenderer.canvasLayer),this.velocityLayer.setOptions({colorScale:["rgb(255, 255, 255)"]}),this.map.hasLayer(this.velocityLayer)&&(this.velocityLayer.remove(),this.velocityLayer.addTo(this.map))):t.layer===this.precipitationRenderer.canvasLayer&&(this.map.hasLayer(this.temperatureRenderer.canvasLayer)&&this.map.removeLayer(this.temperatureRenderer.canvasLayer),this.velocityLayer.setOptions({colorScale:["rgb(255, 255, 255)"]}),this.map.hasLayer(this.velocityLayer)&&(this.velocityLayer.remove(),this.velocityLayer.addTo(this.map)))})),this.map.on("overlayremove",(t=>{t.layer!==this.temperatureRenderer.canvasLayer&&t.layer!==this.precipitationRenderer.canvasLayer||(this.setWindyParameters(this.options.windyParameters),this.map.hasLayer(this.velocityLayer)&&(this.velocityLayer.remove(),this.velocityLayer.addTo(this.map)))}))}initializeTemperatureLayer(){this.temperatureRenderer=new n(this.map,[],{pixelSize:5,opacity:.3,controlName:"Temperature Layer",colorScale:this.options.temp_color_scale,layerControl:this.layerControl,demoMode:this.options.demoMode}),this.temperatureRenderer.canvasLayer=this.temperatureRenderer.init()}initializePrecipitationLayer(){this.precipitationRenderer=new n(this.map,[],{pixelSize:5,opacity:.3,controlName:"Precipitation Layer",colorScale:this.options.prec_color_scale,layerControl:this.layerControl,demoMode:this.options.demoMode}),this.precipitationRenderer.canvasLayer=this.precipitationRenderer.init()}initializeWindLayer(){this.velocityLayer=L.velocityLayer({displayValues:!0,displayOptions:{velocityType:"Global Wind",emptyString:"No velocity data"}}),this.layerControl.addOverlay(this.velocityLayer,"Wind Layer"),this.velocityLayer.setOptions(this.options.windyParameters)}forceUpdate(){this.updateWeatherData().then((()=>{this.updateTemperatureData(),this.updatePrecipitationData(),this.updateWindData(),this.currentGrid.grid=this.currentGrid.grid.filter((t=>t.isStale())),this.gridsMap.set(this.gridKey,this.currentGrid)}))}async updateWeatherData(){const t=await this.fetchWeatherData(this.currentGrid,this.options);this.options.randomData||t.forEach(((t,e)=>this.currentGrid.grid[e].setWeatherData(t)))}updateTemperatureData(){this.temperatureRenderer.update(h.tempDataBuilder(this.currentGrid))}updatePrecipitationData(){this.precipitationRenderer.update(h.precipDataBuilder(this.currentGrid))}updateWindData(){this.velocityLayer.setData(h.windyDataBuilder(this.currentGrid,this.options))}updateConfig(t={}){if(Object.assign(this.options,{pointDistance:t.pointDistance??this.options.pointDistance,maxGridPoints:t.maxGridPoints??this.options.maxGridPoints,maxBounds:t.maxBounds?L.latLngBounds([t.maxBounds[0],t.maxBounds[1]]):this.options.maxBounds,windyParameters:t.windyParameters?{...this.options.windyParameters,...t.windyParameters}:this.options.windyParameters}),t.windyParameters&&(this.velocityLayer.setOptions(this.options.windyParameters),this.map.hasLayer(this.velocityLayer)&&(this.velocityLayer.remove(),this.velocityLayer.addTo(this.map))),t.temperatureOpacity||t.temperatureColorScale){const e={};t.temperatureOpacity&&(e.opacity=t.temperatureOpacity),t.temperatureColorScale&&(e.colorScale=t.temperatureColorScale),this.temperatureRenderer.setOptions(e),this.map.hasLayer(this.temperatureRenderer.canvasLayer)&&this.updateTemperatureData()}if(t.precipitationOpacity||t.precipitationColorScale){const e={};t.precipitationOpacity&&(e.opacity=t.precipitationOpacity),t.precipitationColorScale&&(e.colorScale=t.precipitationColorScale),this.precipitationRenderer.setOptions(e),this.map.hasLayer(this.precipitationRenderer.canvasLayer)&&this.updatePrecipitationData()}if(t.pointDistance||t.maxBounds||t.maxGridPoints){var{pointDistance:e,bounds:i}=this.getPointDistanceFromBounds(this.options.maxBounds??this.map.getBounds());this.currentGrid=h.gridBuilder(this.map,this.options.pointDistance??e,i,this.currentGrid.gridPointsMap,this.options),this.forceUpdate()}}getCurrentData(){const t="current";if(this.gridsMap.has(t))this.currentGrid=this.gridsMap.get(t);else{const a=this.options.maxBounds??this.map.getBounds();var{pointDistance:e,bounds:i}=this.getPointDistanceFromBounds(a);let n=h.gridBuilder(this.map,e,i,new Map,this.options);this.gridsMap.set(t,n),this.currentGrid=this.gridsMap.get(t)}return this.setDateType("current",{key:t})}getWeatherData(t){const e=`forecast_${t}`;if(this.gridsMap.has(e))this.currentGrid=this.gridsMap.get(e);else{const t=this.options.maxBounds??this.map.getBounds();var{pointDistance:i,bounds:a}=this.getPointDistanceFromBounds(t);const n=h.gridBuilder(this.map,i,a,new Map,this.options);this.gridsMap.set(e,n),this.currentGrid=n}return this.setDateType("forecast",{key:e,date:t})}getHourlyWeatherData(t,e){const i=`forecast_hourly_${t}_${e}`;if(this.gridsMap.has(i))this.currentGrid=this.gridsMap.get(i);else{const t=this.options.maxBounds??this.map.getBounds();var{pointDistance:a,bounds:n}=this.getPointDistanceFromBounds(t);const e=h.gridBuilder(this.map,a,n,new Map,this.options);this.gridsMap.set(i,e),this.currentGrid=e}return this.setDateType("forecast_hourly",{key:i,date:t,hour_index:e})}setDateType(t,e={}){return this.options.dateType=t,"forecast"===t||"forecast_hourly"===t?(this.options.start_date=e.date,this.options.end_date=e.date,this.options.hour_index=e.hour_index||null):(this.options.start_date=null,this.options.end_date=null,this.options.hour_index=null),this.gridKey=e.key,this.forceUpdate()}setWindyParameters(t){this.options.windyParameters={...this.options.windyParameters,...t},this.velocityLayer&&this.velocityLayer.setOptions(this.options.windyParameters)}showWeatherPopup(t,e){const i=h.generatePointKey(t,e),a=this.currentGrid.gridPointsMap.get(i);if(!a)return void console.error("no gridPoint found for the given coordinates:",t,e);const{temperature:n,wind:o,timestamp:r}=a.weatherData,s=`\n <div>\n <h4>Datos Meteorológicos</h4>\n <p><strong>Coordenadas:</strong> Lat: ${t.toFixed(4)}, Lng: ${e.toFixed(4)}</p>\n <p><strong>Temperatura:</strong> ${null!==n?n+" °C":"No disponible"}</p>\n <p><strong>Viento:</strong> ${null!==o.speed?o.speed+" m/s":"No disponible"} \n ${null!==o.direction?" - "+o.direction+"°":""}</p>\n ${r?`<p><strong>Actualizado:</strong> ${new Date(r).toLocaleString()}</p>`:""}\n </div>\n `;L.popup({closeOnClick:!0,autoClose:!1}).setLatLng([t,e]).setContent(s).openOn(this.map)}async fetchWeatherData(t,e){const i=t.grid||t,a={dateType:e.dateType,start_date:e.start_date,end_date:e.end_date,hour_index:e.hour_index};if(e.randomData)h.generateRandomGridData(i);else try{let t=[];return i&&i.length>0&&(t=await this.apiCaller(i,a)),t}catch(t){throw console.error("Fetching weather data failed:",t),t}}}})(),e})()));