UNPKG

weatherlayers-gl

Version:

WeatherLayers GL - Weather Visualization Layers for deck.gl

15 lines (13 loc) 11.2 kB
/*! * Copyright (c) 2021-2026 WeatherLayers.com * * WeatherLayers Cloud Client 2026.5.1 * * A valid access token is required to use the library. Contact support@weatherlayers.com for details. * * Homepage - https://weatherlayers.com/ * Demo - https://demo.weatherlayers.com/ * Docs - https://docs.weatherlayers.com/ * WeatherLayers Cloud Terms of Use - https://weatherlayers.com/terms-of-use.html */ export{colorRampCanvas,parsePalette}from"cpt2js";const t="2026.5.1",e="2026-05-11T19:53:53.177Z",a=new Map;function n(t,e){a.set(t,e)}const i=new Map;const r=new class{constructor(){this.queue=Promise.resolve()}async run(t){const e=this.queue;let a;this.queue=new Promise((t=>{a=t}));try{return await e,await t()}finally{a()}}};async function s(t,e){const n=await async function(t){if(a.has(t))return a.get(t);try{if("geotiff"===t)return await import("geotiff")}catch(e){throw new Error(`Optional dependency '${t}' is missing, install it with a package manager or provide with \`setLibrary('${t}', library)\``,{cause:e})}}("geotiff");let i;try{i=await n.fromUrl(t,{allowFullFile:!0,blockSize:Number.MAX_SAFE_INTEGER,fetch:(t,a)=>fetch(t,{...a,headers:{...a?.headers,...e?.headers}})},e?.signal)}catch(e){throw new Error(`Image ${t} can't be decoded.`,{cause:e})}const r=await i.getImage(0),s=await r.readRasters({interleave:!0,signal:e?.signal});if(!(s instanceof Uint8Array||s instanceof Uint8ClampedArray||s instanceof Float32Array))throw new Error("Unsupported data format");const o=function(t,e){if(null==e)return t;const a=t.slice(0);for(let t=0;t<a.length;t++)Math.abs(a[t]-e)<2*Number.EPSILON&&(a[t]=NaN);return a}(s,r.getGDALNoData());return{data:o,width:r.getWidth(),height:r.getHeight()}}function o(t){return async(e,a)=>{if(!1===a?.cache)return t(e);const n=a?.cache??i,r=e+(a?.headers?":"+JSON.stringify(a?.headers):""),s=n.get(r);if(s)return s;const o={...a,cache:void 0},c=t(e,o);return n.set(r,c),c.then((t=>{n.set(r,t)})),c}}const c=o((async(t,e)=>{if(t.includes(".png")||t.includes(".webp")||t.includes("image/png")||t.includes("image/webp"))return async function(t,e){let a;if(e?.headers||e?.signal){const n=await fetch(t,{headers:e.headers,signal:e.signal});if(!n.ok)throw new Error(`URL ${t} can't be loaded. Status: ${n.status}`);const i=await n.blob();a=URL.createObjectURL(i)}const n=new Image;try{await new Promise(((e,i)=>{n.addEventListener("load",e),n.addEventListener("error",i),n.crossOrigin="anonymous",n.src=a??t}))}catch(e){throw new Error(`URL ${t} can't be loaded.`,{cause:e})}finally{a&&URL.revokeObjectURL(a)}try{await r.run((()=>n.decode()))}catch(e){throw new Error(`Image ${t} can't be decoded.`,{cause:e})}const i=document.createElement("canvas");i.width=n.width,i.height=n.height;const s=i.getContext("2d");s.drawImage(n,0,0);const o=s.getImageData(0,0,i.width,i.height),{data:c,width:l,height:h}=o;return{data:c,width:l,height:h}}(t,e);if(t.includes(".tif")||t.includes("image/tif"))return s(t,e);throw new Error("Unsupported data format")})),l=o((async(t,e)=>{const a=await fetch(t,{headers:e?.headers});if(!a.ok)throw new Error(`URL ${t} can't be loaded. Status: ${a.status}`);return a.json()}));function h(t,e,a){if(!e){if(0===a)return t;throw new Error("Invalid state")}if(a<=0)return t;if(a>=1)return e;{const n=new Date(t),i=new Date(e);return new Date(n.getTime()+(i.getTime()-n.getTime())*a).toISOString()}}function d(t,e,a){if(!e){if(t===a)return 0;throw new Error("Invalid state")}if(a<=t)return 0;if(a>=e)return 1;{const n=new Date(t),i=new Date(e);return(new Date(a).getTime()-n.getTime())/(i.getTime()-n.getTime())}}function m(t,e){return[...t].reverse().find((t=>t<=e))}function u(t,e){return t.find((t=>t>=e))}function f(t,e){const a=new Date(t);return new Date(a.getTime()+1e3*e*60*60).toISOString()}function g(t,e,a){return[f(t,e),f(t,a)]}function w(t){if(!t)return t;const e=new Date(t);if(!e.getDate())return t;return`${e.getUTCFullYear()}/${`${e.getUTCMonth()+1}`.padStart(2,"0")}/${`${e.getUTCDate()}`.padStart(2,"0")} ${`${e.getUTCHours()}`.padStart(2,"0")}:${`${e.getUTCMinutes()}`.padStart(2,"0")} UTC`}const p={SCALAR:"SCALAR",VECTOR:"VECTOR"},D={METRIC:"METRIC",METRIC_KILOMETERS:"METRIC_KILOMETERS",IMPERIAL:"IMPERIAL",NAUTICAL:"NAUTICAL"},S="producer",_="processor",C="item",y="data",I="search",T="palette",E=D.METRIC;function A(t,e){const a=t.providers.find((t=>t.roles.includes(S))),n=t.providers.find((t=>t.roles.includes(_)));return[...a?[`<a href="${a.url}"${e?` class="${e}"`:""}>${a.name}</a>`]:[],...n?[`<a href="${n.url}"${e?` class="${e}"`:""}>${n.name}</a>`]:[]].join(" via ")}function $(t,e){const a=t["weatherLayers:units"],n=a.find((t=>t.system===e))??a.find((t=>t.system===E))??a[0],{unit:i,scale:r,offset:s,decimals:o}=n;return{unit:i,scale:r,offset:s,decimals:o}}class U{constructor(t){this._cache=new Map,this._datasetStacCollectionCache=new Map,this._datasetDataStacItemCache=new Map,this._config=t}getConfig(){return{...this._config}}setConfig(t){this._config=t}updateConfig(t){this.setConfig({...this._config,...t})}_getAuthenticatedUrl(e,a={}){const n=a.accessToken??this._config.accessToken??null,i=new URL(e);return i.searchParams.has("access_token")||null==n||i.searchParams.set("access_token",n),i.searchParams.has("version")||i.searchParams.set("version",t),i.toString()}_cacheDatasetStacCollection(t){this._datasetStacCollectionCache.set(t.id,t)}_cacheDatasetDataStacItem(t,e){this._datasetDataStacItemCache.has(t)||this._datasetDataStacItemCache.set(t,new Map),this._datasetDataStacItemCache.get(t).set(e.properties.datetime,e)}async _loadStacCatalog(t={}){const e=t.url??this._config.url??"https://catalog.weatherlayers.com",a=this._getAuthenticatedUrl(`${e}/catalog`,t);return await l(a,{cache:this._cache})}async _loadDatasetStacCollections(t={}){const e=(await this._loadStacCatalog(t)).links.find((t=>t.rel===y));if(!e)throw new Error("STAC Catalog data link not found");const a=this._getAuthenticatedUrl(e.href,t),n=(await l(a,{cache:this._cache})).collections;for(const t of n)this._cacheDatasetStacCollection(t);return n}async _loadDatasetStacCollection(t,e={}){await this._loadDatasetStacCollections(e);let a=this._datasetStacCollectionCache.get(t);if(!a)throw new Error(`STAC Collection ${t} not found`);return this._cacheDatasetStacCollection(a),a}async _loadDatasetStacCollectionPalette(t,e={}){const a=await this._loadDatasetStacCollection(t,e),n=Object.values(a.assets??{}).find((t=>t.roles.includes(T)&&"application/json"===t.type));if(!n)throw new Error(`STAC Collection ${t} palette asset not found`);const i=this._getAuthenticatedUrl(n.href,this._config);return await l(i,{cache:this._cache})}async _searchDatasetDataStacItems(t,e,a,n={}){const i=(await this._loadStacCatalog(n)).links.find((t=>t.rel===I));if(!i)throw new Error("STAC Catalog search link not found");const r=new URL(i.href);r.searchParams.set("collections",t),r.searchParams.set("datetime",function(t){if(Array.isArray(t)&&2===t.length){const[e,a]=t;return`${e??".."}/${a??".."}`}throw new Error("Invalid datetime range")}(e)),"number"==typeof a&&a>1&&r.searchParams.set("datetime_step",`${a}`);const s=this._getAuthenticatedUrl(r.toString(),n),o=(await l(s,{cache:this._cache})).features;for(const e of o)this._cacheDatasetDataStacItem(t,e);return o}async _loadDatasetDataStacItem(t,e,a={}){const n=a.datetimeStep??this._config.datetimeStep??1;let i=this._datasetDataStacItemCache.get(t)?.get(e);if(!i){i=(await this._searchDatasetDataStacItems(t,[e,e],n,a))[0]}if(!i)throw new Error(`STAC Item ${t}/${e} not found`);return i}async _loadStacItemData(t,e={}){const a=e.dataFormat??this._config.dataFormat??"byte.webp",n=t.assets[`data.${a}`];if(!n)throw new Error("STAC Item data asset not found");const i=this._getAuthenticatedUrl(n.href,this._config),r=await c(i,{cache:this._cache,signal:e.signal});return{datetime:t.properties.datetime,referenceDatetime:t.properties["forecast:reference_datetime"],horizon:t.properties["forecast:horizon"],image:r}}async _loadDatasetDataStacItemDataNow(t,e={}){const a=(await this._loadDatasetStacCollection(t,e)).links.find((t=>t.rel===C&&"!now"===t.datetime));if(!a)throw new Error("STAC Collection now item link not found");const n=this._getAuthenticatedUrl(a.href,this._config),i=await l(n,{cache:this._cache});return await this._loadStacItemData(i,e)}async _loadDatasetDataStacItemData(t,e,a={}){const n=await this._loadDatasetDataStacItem(t,e);return await this._loadStacItemData(n,a)}async loadCatalog(t={}){return(await this._loadDatasetStacCollections(t)).map((t=>t.id))}async loadDataset(t,e={}){const a=await this._loadDatasetStacCollection(t,e),n=e.unitSystem??this._config.unitSystem??E,i=e.attributionLinkClass??this._config.attributionLinkClass??"";return{title:a.title,unitFormat:$(a,n),attribution:A(a,i),bounds:a.extent.spatial.bbox[0],datetimeRange:a.extent.temporal.interval[0],datetimes:a.links.filter((t=>t.rel===C)).map((t=>t.datetime)).filter((t=>!!t)),palette:await this._loadDatasetStacCollectionPalette(t),layers:a["weatherLayers:layers"],controls:a["weatherLayers:controls"]}}async loadDatasetSlice(t,e,a={}){const n=a.datetimeStep??this._config.datetimeStep??1;return{datetimes:(await this._searchDatasetDataStacItems(t,e,n,a)).map((t=>t.properties.datetime))}}async loadDatasetData(t,e,a={}){const n=a.datetimeStep??this._config.datetimeStep??1,i=a.datetimeInterpolate??this._config.datetimeInterpolate??!1,r=await this._loadDatasetStacCollection(t,a);if(!e){const e=await this._loadDatasetDataStacItemDataNow(t,a);return{datetime:e.datetime,referenceDatetime:e.referenceDatetime,horizon:e.horizon,image:e.image,datetime2:null,referenceDatetime2:null,horizon2:null,image2:null,imageWeight:0,imageType:r["weatherLayers:imageType"],imageUnscale:e.image.data instanceof Uint8Array||e.image.data instanceof Uint8ClampedArray?r["weatherLayers:imageUnscale"]:null,bounds:r.extent.spatial.bbox[0]}}let s=this._datasetDataStacItemCache.has(t)?Array.from(this._datasetDataStacItemCache.get(t).values()):[],o=s.map((t=>t.properties.datetime)).sort();if((!o.length||o[0]>e||o[o.length-1]<e)&&(s=await this._searchDatasetDataStacItems(t,[e,e],n,a),o=s.map((t=>t.properties.datetime)).sort()),!o.length)throw new Error(`STAC Item ${t}/${e} not found`);const c=m(o,e),l=u(o,e);let h,f;if(i&&c&&l&&c!==l)h=c,f=l;else{if(!c)throw new Error(`STAC Item ${t}/${e} not found`);h=c,f=null}const[g,w]=await Promise.all([this._loadDatasetDataStacItemData(t,h,a),i&&f?this._loadDatasetDataStacItemData(t,f,a):null]);return{datetime:g.datetime,referenceDatetime:g.referenceDatetime,horizon:g.horizon,image:g.image,datetime2:w?w.datetime:null,referenceDatetime2:w?w.referenceDatetime:null,horizon2:w?w.horizon:null,image2:w?w.image:null,imageWeight:w?d(g.datetime,w.datetime,e):0,imageType:r["weatherLayers:imageType"],imageUnscale:g.image.data instanceof Uint8Array||g.image.data instanceof Uint8ClampedArray?r["weatherLayers:imageUnscale"]:null,bounds:r.extent.spatial.bbox[0]}}}export{U as Client,e as DATETIME,p as ImageType,D as UnitSystem,t as VERSION,w as formatDatetime,u as getClosestEndDatetime,m as getClosestStartDatetime,d as getDatetimeWeight,h as interpolateDatetime,l as loadJson,c as loadTextureData,f as offsetDatetime,g as offsetDatetimeRange,n as setLibrary};