autumnplot-gl 4.0.0-beta → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,220 +2,24 @@
2
2
  Hardware-accelerated geospatial data plotting in the browser
3
3
 
4
4
  ## Links
5
- [Github](https://github.com/tsupinie/autumnplot-gl) | [API docs](https://tsupinie.github.io/autumnplot-gl/) | [NPM](https://www.npmjs.com/package/autumnplot-gl)
5
+ [Github](https://github.com/tsupinie/autumnplot-gl) | [Tutorial](https://tsupinie.github.io/autumnplot-gl) | [API docs](https://tsupinie.github.io/autumnplot-gl/docs/api) | [NPM](https://www.npmjs.com/package/autumnplot-gl)
6
6
 
7
7
  ## What is this?
8
8
  Lots of meteorological data web sites have a model where the data live on a central server, get plotted on the server, and then the server serves static images to the client. This creates a bottleneck where adding fields and view sectors takes exponentially more processing power for the server. One way around this is to offload the plotting to the client and to have the browser plot the data on a pan-and-zoomable map. Unfortunately, in the past, this has required developing low-level plotting code, and depending on the mapping library, the performance may be poor.
9
9
 
10
10
  autumnplot-gl provides a solution to this problem by making hardware-accelerated data plotting in the browser easy. This was designed with meteorological data in mind, but anyone wanting to contour geospatial data on a map can use autumnplot-gl.
11
11
 
12
- ## Usage
13
- autumnplot-gl is designed to be used with either [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/guides/) or [MapLibre GL JS](https://maplibre.org/maplibre-gl-js-docs/) mapping libraries. If you're using webpack or another node-based build tool, you can install by running
12
+ ## How do I use this?
14
13
 
15
- ```bash
16
- npm i autumnplot-gl
17
- ```
14
+ Check out the [tutorial](https://tsupinie.github.io/autumnplot-gl) for installation and usage information.
18
15
 
19
- Unfortunately, you may have to modify your build tool configuration to include the WebAssembly binary. For webpack, I've found adding this to webpack.config.js works:
16
+ ## Development
20
17
 
21
- ```javascript
22
- {
23
- "module": {
24
- "rules": [
25
- {
26
- test: /\.wasm$/,
27
- type: "asset/resource",
28
- generator: {
29
- filename: "[name].wasm"
30
- }
31
- }
32
- ]
33
- }
34
- }
35
- ```
18
+ To work on autumnplot-gl itself, it takes a few steps to set up
36
19
 
37
- In addition to the Typescript library, pre-built autumnplot-gl javascript files area available [here](https://tsupinie.github.io/autumnplot-gl/dist/). Adding them to your page exposes the API via the `apgl` global variable (e.g., instead of `new PlateCarreeGrid(...)` in the examples, you'd call `new apgl.PlateCarreeGrid(...)`).
38
-
39
- ### A basic contour plot
40
- The first step in plotting data is to create a grid. Currently, the only supported grids are PlateCarreeGrid (a.k.a. Lat/Lon), RotatedPlateCarreeGrid, and LambertGrid (a.k.a. Lambert Conformal Conic).
41
-
42
- ```javascript
43
- // Create a grid object that covers the continental United States
44
- const nx = 121, ny = 61;
45
- const grid = new PlateCarreeGrid(nx, ny, -130, 20, -65, 55);
46
- ```
47
-
48
- Next, create a RawScalarField with the data. autumnplot-gl doesn't care about how data get to the browser, but it should end up in a `Float32Array` or `Float16Array` in row-major order with the first element being at the southwest corner of the grid. If you're using [zarr.js](https://github.com/gzuidhof/zarr.js/), you can use the `getRaw()` function on a `ZarrArray` to get data in the correct format. Also, `Float16Array`s are not in the Javascript standard library (for now), so for the time being, you'll need to use [this library](https://github.com/petamoriken/float16). However, the nice part about using a `Float16Array` is that your data will be stored as float16s in VRAM, so they'll take up half the space as the same data as float32s. Once you have your data in that format, to create the raw data field:
49
-
50
- ```javascript
51
- // Create the raw data field
52
- const height_field = new RawScalarField(grid, height_data);
53
- ```
54
-
55
- Next, to contour the field, create a Contour object and pass it some options. See [here](https://tsupinie.github.io/autumnplot-gl/interfaces/ContourOptions.html) for a full list of options.
56
-
57
- ```javascript
58
- // Contour the data
59
- const height_contour = new Contour(height_field, {color: '#000000', interval: 30});
60
- ```
61
-
62
- Next, create the actual layer that gets added to the map. The first argument (`'height-contour'` here) is an id. It doesn't mean much, but it does need to be unique between the different `PlotLayer`s you add to the map.
63
-
64
- ```javascript
65
- // Create the map layer
66
- const height_layer = new PlotLayer('height-contour', height_contour);
67
- ```
68
-
69
- Finally, add it to the map. The interface for Mapbox and MapLibre are the same, at least currently, though there's nothing that says they'll stay that way in the future. Assuming you're using MapLibre:
70
-
71
- ```javascript
72
- const map = new maplibregl.Map({
73
- container: 'map',
74
- style: 'https://api.maptiler.com/maps/basic-v2/style.json?key=' + maptiler_api_key,
75
- center: [-97.5, 38.5],
76
- zoom: 4
77
- });
78
-
79
- map.on('load', () => {
80
- map.addLayer(height_layer, 'railway_transit_tunnel');
81
- });
82
- ```
83
-
84
- The `'railway_transit_tunnel'` argument is a layer in the map style, and this means to add your layer just below that layer on the map. This usually produces better results than just blindly slapping all your layers on top of all the map (though the map style itself may require some tweaking to produce the best results).
85
-
86
- ### Contour Labeling
87
-
88
- Typically, when plotting meteorological data, contours are labeled with their values, which you can do with `ContourLabels`:
89
-
90
- ```javascript
91
- const labels = new ContourLabels(height_contour, {text_color: '#ffffff', halo: true});
92
- const label_layer = new PlotLayer('label', labels);
93
-
94
- map.on('load', () => {
95
- map.addLayer(label_layer, 'railway_transit_tunnel');
96
- });
97
- ```
98
-
99
- ### Barbs
100
-
101
- Wind barb plotting is similar to the contours, but it requires using a `RawVectorField` with u and v data.
102
-
103
- ```javascript
104
- const vector_field = new RawVectorField(grid, u_data, v_data);
105
- const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
106
- const barb_layer = new PlotLayer('barbs', barbs);
107
-
108
- map.on('load', () => {
109
- map.addLayer(barb_layer, 'railway_transit_tunnel');
110
- });
111
- ```
112
-
113
- The wind barbs are automatically rotated based on the grid projection. Also, the density of the wind barbs is automatically varied based on the map zoom level. The `'thin_fac': 16` option means to plot every 16th wind barb in the i and j directions, and this is defined at zoom level 1. So at zoom level 2, it will plot every 8th wind barb, and at zoom level 3 every 4th wind barb, and so on. Because it divides in 2 for every deeper zoom level, `'thin_fac'` should be a power of 2.
114
-
115
- ### Filled contours or raster plots
116
-
117
- Plotting filled contours is also similar to plotting regular contours, but there's some additional steps for the color map. A couple color maps are available by default (see [here](#built-in-color-maps) for more details), but if you have the colors you want, creating your own is (relatively) painless (hopefully). First, set up the colormap. Here, we'll just use the bluered colormap included by default.
118
-
119
- ```javascript
120
- // colormaps is imported via `import {colormaps} from 'autumnplot-gl'`
121
- const colormap = colormaps.bluered(-10, 10, 20);
122
- const fills = new ContourFilled(height, {cmap: colormap, opacity: 0.6});
123
- const height_fill_layer = new PlotLayer('height-fill', fills);
124
-
125
- map.on('load', () => {
126
- map.addLayer(height_fill_layer, 'railway_transit_tunnel');
127
- });
128
- ```
129
-
130
- Making a raster plot is very similar (the two classes support the same options):
131
-
132
- ```javascript
133
- const raster = new Raster(height, {cmap: colormap, opacity: 0.6});
134
- ```
135
-
136
- Normally, when you have a color fill, you have a color bar on the plot. To create an SVG color bar:
137
-
138
- ```javascript
139
- const colorbar_svg = makeColorBar(colormap, {label: "Height Perturbation (m)",
140
- ticks: [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10],
141
- orientation: 'horizontal',
142
- tick_direction: 'bottom'});
143
-
144
- document.getElementById('colorbar-container').appendChild(colorbar_svg);
145
- ```
146
-
147
- ### Varying the data plots
148
- The previous steps have gone through plotting a static dataset on a map, but in many instances, you want to view a dataset that changes, say over time. In order to switch the data currently plotted, you can call `updateField()` on the plot component (e.g, `ContourFilled`, `Barbs`, etc.) to switch what field is plotted.
149
-
150
- ```javascript
151
- // Create the initial field
152
- const height_field_f00 = new RawScalarField(grid, height_data_f00);
153
- const fills = new Contour(height_data_f00, {interval: 30});
154
-
155
- // Update the field plotted
156
- const height_field_f01 = new RawScalarField(grid, height_data_f01);
157
- fills.updateField(height_field_f01);
158
- ```
159
-
160
- Another way to vary the data is to use `MultiPlotLayer`. The main difference between this and using `updateField()` is that `MultiPlotLayer` will put all data for all times onto VRAM at once. In contrast, with `PlotLayer` and `updateField()`, only the data currently plotted are stored on VRAM. For large grids, this may take up a large amount of VRAM, so you may not want to use this, and it may be removed in later versions.
161
-
162
- ```javascript
163
- // Contour some data
164
- const height_contour_f00 = new Contour(height_f00);
165
- const height_contour_f01 = new Contour(height_f01);
166
- const height_contour_f02 = new Contour(height_f02);
167
-
168
- // Create a varying map layer
169
- const height_layer_time = new MultiPlotLayer('height-contour-time');
170
-
171
- // Add the contoured data to it
172
- height_layer_time.addField(height_contour_f00, '20230112_1200');
173
- height_layer_time.addField(height_contour_f01, '20230112_1300');
174
- height_layer_time.addField(height_contour_f02, '20230112_1400');
175
-
176
- // Add to the map like normal
177
- map.on('load', () => {
178
- map.addLayer(height_layer_time, 'railway_transit_tunnel');
179
- });
180
- ```
181
-
182
- The second argument to `addField()` is the key to associate with this field. This example uses the absolute time, but you could just as easily use `'f00'`, `'f01'`, ... or anything else that's relevant as long as it's unique. Now to set the active time (i.e., the time that gets plotted):
183
-
184
- ```javascript
185
- // Set the active field in the map layer (the map updates automatically)
186
- height_layer.setActiveKey('20230112_1200');
187
- ```
188
-
189
- ### Typescript Considerations
190
-
191
- autumnplot-gl is written in Typescript to facilitate type info in large projects. Typescript isn't necessary to use autumnplot-gl, but if you want to use it, there are some considerations.
192
-
193
- Many of the plot component classes have generic types. The Typescript compiler can generally figure out the generic type parameters, but if you're declaring a variable to be a plot component, you'll probably need to specify those ahead of time. The first type parameter is the array type (either Float32Array or Float16Array), and the second is the type of the Map you're using.
194
-
195
- ```typescript
196
- // Import the map from maplibre-gl, if that's what you're using. Mapbox should be similar.
197
- import { Map } from 'maplibre-gl';
198
-
199
- // Declare a contour field which contours an array of float float32s with the MapLibre map.
200
- const cntr: Contour<Float32Array, Map>;
201
- ```
202
-
203
- ## Built-in color maps
204
- autumnplot-gl comes with several built-in color maps, accessible via `import {colormaps} from 'autumnplot-gl'`. These are basic blue/red and red/blue diverging color maps plus a selection from [PivotalWeather](https://www.pivotalweather.com). The blue/red and red/blue are functions that take a minimum contour level, a maximum contour level, and a number of colors. For example, this creates a blue/red colormap starting at -10, ending at 10, and with 20 colors:
205
-
206
- ```javascript
207
- const colormap = colormaps.bluered(-10, 10, 20);
208
- ```
209
-
210
- Here are all the colormaps available:
211
-
212
- ![colormaps](https://github.com/tsupinie/autumnplot-gl/assets/885575/348eb23a-67ed-48b3-9c69-b7d834ba1b03)
213
-
214
-
215
- ## Map tiles
216
- The above exmple uses map tiles from [Maptiler](https://www.maptiler.com/). Map tiles from Maptiler or Mapbox or others are free up to a (reasonably generous) limit, but the pricing can be a tad steep after reaching the limit. The tiles from these services are extremely detailed, and really what you're paying for there is the hardware to store, process, and serve that data. While these tiles are very nice, the detail is way overkill for a lot of uses in meteorology.
217
-
218
- So, I've created some [less-detailed map tiles](https://tsupinie.github.io/autumnplot-gl/tiles/) that are small enough that they can be hosted without dedicated hardware. However the tradeoff is that they're only useful down to zoom level 8 or 9 on the map, such that the viewport is somewhere between half a US state and a few counties in size. If that's good enough for you, then these tiles could be useful.
219
-
220
- ## Closing thoughts
221
- Even though autumnplot-gl is currently an extremely new package with relatively limited capability, I hope folks see potential and find it useful. Any contributions to fill out some missing features are welcome.
20
+ 1. Install [node.js](https://nodejs.org/en/download/) if you don't have it already
21
+ 2. Install [emscripten](https://emscripten.org/docs/getting_started/downloads.html) and source the relevant SDK environment for your shell
22
+ 3. Clone the autumnplot-gl git repo (`git clone https://github.com/tsupinie/autumnplot-gl ; cd autumnplot-gl`)
23
+ 4. Install the dependencies (`npm install`)
24
+ 5. Build the WASM module (`cd src/cpp ; make js ; cd -`)
25
+ 6. Start the dev server (`npm run start`)
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.apgl=t():e.apgl=t()}(this,()=>(()=>{"use strict";const e=Symbol("Comlink.proxy"),t=Symbol("Comlink.endpoint"),r=Symbol("Comlink.releaseProxy"),n=Symbol("Comlink.thrown"),o=e=>"object"==typeof e&&null!==e||"function"==typeof e,s=new Map([["proxy",{canHandle:t=>o(t)&&t[e],serialize(e){const{port1:t,port2:r}=new MessageChannel;return a(e,t),[r,[r]]},deserialize:e=>(e.start(),f(e,[],undefined))}],["throw",{canHandle:e=>o(e)&&n in e,serialize({value:e}){let t;return t=e instanceof Error?{isError:!0,value:{message:e.message,name:e.name,stack:e.stack}}:{isError:!1,value:e},[t,[]]},deserialize(e){if(e.isError)throw Object.assign(new Error(e.value.message),e.value);throw e.value}}]]);function a(t,r=self){r.addEventListener("message",function o(s){if(!s||!s.data)return;const{id:c,type:f,path:u}=Object.assign({path:[]},s.data),p=(s.data.argumentList||[]).map(d);let h;try{const r=u.slice(0,-1).reduce((e,t)=>e[t],t),n=u.reduce((e,t)=>e[t],t);switch(f){case"GET":h=n;break;case"SET":r[u.slice(-1)[0]]=d(s.data.value),h=!0;break;case"APPLY":h=n.apply(r,p);break;case"CONSTRUCT":h=function(t){return Object.assign(t,{[e]:!0})}(new n(...p));break;case"ENDPOINT":{const{port1:e,port2:r}=new MessageChannel;a(t,r),h=function(e,t){return l.set(e,t),e}(e,[e])}break;case"RELEASE":h=void 0;break;default:return}}catch(e){h={value:e,[n]:0}}Promise.resolve(h).catch(e=>({value:e,[n]:0})).then(e=>{const[t,n]=v(e);r.postMessage(Object.assign(Object.assign({},t),{id:c}),n),"RELEASE"===f&&(r.removeEventListener("message",o),i(r))})}),r.start&&r.start()}function i(e){(function(e){return"MessagePort"===e.constructor.name})(e)&&e.close()}function c(e){if(e)throw new Error("Proxy has been released and is not useable")}function f(e,n=[],o=function(){}){let s=!1;const a=new Proxy(o,{get(t,o){if(c(s),o===r)return()=>p(e,{type:"RELEASE",path:n.map(e=>e.toString())}).then(()=>{i(e),s=!0});if("then"===o){if(0===n.length)return{then:()=>a};const t=p(e,{type:"GET",path:n.map(e=>e.toString())}).then(d);return t.then.bind(t)}return f(e,[...n,o])},set(t,r,o){c(s);const[a,i]=v(o);return p(e,{type:"SET",path:[...n,r].map(e=>e.toString()),value:a},i).then(d)},apply(r,o,a){c(s);const i=n[n.length-1];if(i===t)return p(e,{type:"ENDPOINT"}).then(d);if("bind"===i)return f(e,n.slice(0,-1));const[l,v]=u(a);return p(e,{type:"APPLY",path:n.map(e=>e.toString()),argumentList:l},v).then(d)},construct(t,r){c(s);const[o,a]=u(r);return p(e,{type:"CONSTRUCT",path:n.map(e=>e.toString()),argumentList:o},a).then(d)}});return a}function u(e){const t=e.map(v);return[t.map(e=>e[0]),(r=t.map(e=>e[1]),Array.prototype.concat.apply([],r))];var r}const l=new WeakMap;function v(e){for(const[t,r]of s)if(r.canHandle(e)){const[n,o]=r.serialize(e);return[{type:"HANDLER",name:t,value:n},o]}return[{type:"RAW",value:e},l.get(e)||[]]}function d(e){switch(e.type){case"HANDLER":return s.get(e.name).deserialize(e.value);case"RAW":return e.value}}function p(e,t,r){return new Promise(n=>{const o=new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-");e.addEventListener("message",function t(r){r.data&&r.data.id&&r.data.id===o&&(e.removeEventListener("message",t),n(r.data))}),e.start&&e.start(),e.postMessage(Object.assign({id:o},t),r)})}var h=function(){function e(e,t){if(isNaN(e)||isNaN(t))throw new Error("Invalid LngLat object: (".concat(e,", ").concat(t,")"));if(this.lng=+e,this.lat=+t,this.lat>90||this.lat<-90)throw new Error("Invalid LngLat latitude value: must be between -90 and 90")}return e.prototype.toMercatorCoord=function(){return{x:(n=this.lng,(180+n)/360),y:(e=this.lat,t=Math.sin(e*Math.PI/180),r=(180-90/Math.PI*Math.log((1+t)/(1-t)))/360,Math.min(1.5,Math.max(-.5,r)))};var e,t,r,n},e.fromMercatorCoord=function(t,r){return new e(function(e){return 360*e-180}(t),function(e){return 180*Math.atan(Math.sinh((180-360*e)*Math.PI/180))/Math.PI}(r))},e}(),m=function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,s=r.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(n=s.next()).done;)a.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=s.return)&&r.call(s)}finally{if(o)throw o.error}}return a};return a({makeBBElements:function(e,t,r,n,o,s){for(var a=r.filter(function(e){return e<=s}).length,i=2*a,c=new Float32Array(2*a),f=new Float32Array(i),u=0,l=0,v=0;v<o;v++)for(var d=0;d<n;d++){var p=v*n+d,m=e[p],y=t[p],g=r[p];if(!(g>s||void 0===y||void 0===m)){var x=new h(y,m).toMercatorCoord();c[u+0]=x.x,c[u+1]=x.y,f[l+0]=Math.min(d/(n-1),.99999)+g,f[l+1]=v/(o-1),u+=2,l+=2}}return{pts:c,tex_coords:f}},makeDomainVerticesAndTexCoords:function(e,t,r,n,o,s){for(var a=new Float32Array(4*(r-1)*(n+1)).fill(0),i=new Float32Array(4*(r-1)*(n+1)).fill(0),c=0,f=0,u=0;u<r-1;u++)for(var l=0;l<n;l++){var v=u+l*r,d=new h(t[v],e[v]).toMercatorCoord(),p=new h(t[v+1],e[v+1]).toMercatorCoord(),m=u/(r-1)*(1-2*o)+o,y=(u+1)/(r-1)*(1-2*o)+o,g=l/(n-1)*(1-2*s)+s;0==l&&(a[c]=d.x,a[c+1]=d.y,c+=2,i[f]=m,i[f+1]=g,f+=2),a[c]=d.x,a[c+1]=d.y,a[c+2]=p.x,a[c+3]=p.y,c+=4,i[f]=m,i[f+1]=g,i[f+2]=y,i[f+3]=g,f+=4,l==n-1&&(a[c]=p.x,a[c+1]=p.y,c+=2,i[f]=y,i[f+1]=g,f+=2)}return{vertices:a,tex_coords:i}},makePolyLines:function(e){if(0==e.length||0==e[0].vertices.length)return{vertices:new Float32Array([]),extrusion:new Float32Array([])};var t=Object.fromEntries(Object.entries(e[0]).map(function(e){var t=m(e,2),r=t[0],n=t[1];return[r,"number"==typeof n||"number"==typeof n[0]?1:n[0].length]}));t.extrusion=2,t.vertices+=1;var r=4*e.map(function(e){return e.vertices.length}).reduce(function(e,t){return e+t})-2*e.length,n=Object.fromEntries(Object.entries(t).map(function(e){var t=m(e,2),n=t[0],o=t[1];return[n,r*o]})),o={vertices:new Float32Array(n.vertices),extrusion:new Float32Array(n.extrusion)};"offsets"in e[0]&&(o.offsets=new Float32Array(n.offsets)),"data"in e[0]&&(o.data=new Float32Array(n.data)),"zoom"in e[0]&&(o.zoom=new Float32Array(n.zoom));var s=Object.fromEntries(Object.keys(n).map(function(e){return[e,0]})),a=function(e,t,r){var n=t[0]-e[0],o=t[1]-e[1],s=Math.hypot(n,o),a=-n/s;return[o/s,r?-a:a]};return e.forEach(function(e){var t,r=e.vertices.map(function(e){var t=(new(h.bind.apply(h,function(e,t,r){if(r||2===arguments.length)for(var n,o=0,s=t.length;o<s;o++)!n&&o in t||(n||(n=Array.prototype.slice.call(t,0,o)),n[o]=t[o]);return e.concat(n||Array.prototype.slice.call(t))}([void 0],m(e),!1)))).toMercatorCoord();return[t.x,t.y]});if(0!=e.vertices.length){var n,i,c,f=void 0!==e.offsets,u=void 0!==e.offsets?e.offsets:r,l=r[0],v=(r[1],u[0]),d=u[1],p=1e-4,y=m(a(v,d,!f),2),g=y[0],x=y[1];o.vertices[s.vertices++]=l[0],o.vertices[s.vertices++]=l[1],o.vertices[s.vertices++]=p,o.extrusion[s.extrusion++]=g,o.extrusion[s.extrusion++]=x;for(var b=1;b<r.length;b++)l=r[b],n=r[b-1],v=u[b],i=u[b-1],g=(t=m(a(i,v,!f),2))[0],x=t[1],c=p,p+=Math.hypot(r[b-1][0]-r[b][0],r[b-1][1]-r[b][1]),o.vertices[s.vertices++]=n[0],o.vertices[s.vertices++]=n[1],o.vertices[s.vertices++]=-c,o.vertices[s.vertices++]=n[0],o.vertices[s.vertices++]=n[1],o.vertices[s.vertices++]=c,o.vertices[s.vertices++]=l[0],o.vertices[s.vertices++]=l[1],o.vertices[s.vertices++]=-p,o.vertices[s.vertices++]=l[0],o.vertices[s.vertices++]=l[1],o.vertices[s.vertices++]=p,o.extrusion[s.extrusion++]=g,o.extrusion[s.extrusion++]=x,o.extrusion[s.extrusion++]=-g,o.extrusion[s.extrusion++]=-x,o.extrusion[s.extrusion++]=g,o.extrusion[s.extrusion++]=x,o.extrusion[s.extrusion++]=-g,o.extrusion[s.extrusion++]=-x;if(o.vertices[s.vertices++]=l[0],o.vertices[s.vertices++]=l[1],o.vertices[s.vertices++]=p,o.extrusion[s.extrusion++]=-g,o.extrusion[s.extrusion++]=-x,void 0!==o.offsets&&void 0!==e.offsets){var w=e.offsets,E=void 0,M=w[0];for(o.offsets[s.offsets++]=M[0],o.offsets[s.offsets++]=M[1],b=1;b<w.length;b++)M=w[b],E=w[b-1],o.offsets[s.offsets++]=E[0],o.offsets[s.offsets++]=E[1],o.offsets[s.offsets++]=E[0],o.offsets[s.offsets++]=E[1],o.offsets[s.offsets++]=M[0],o.offsets[s.offsets++]=M[1],o.offsets[s.offsets++]=M[0],o.offsets[s.offsets++]=M[1];o.offsets[s.offsets++]=M[0],o.offsets[s.offsets++]=M[1]}if(void 0!==o.data&&void 0!==e.data){var A=e.data,S=void 0,L=A[0];for(o.data[s.data++]=L,b=1;b<A.length;b++)L=A[b],S=A[b-1],o.data[s.data++]=S,o.data[s.data++]=S,o.data[s.data++]=L,o.data[s.data++]=L;o.data[s.data++]=L}if(void 0!==o.zoom&&void 0!==e.zoom)for(b=0;b<4*r.length-2;b++)o.zoom[s.zoom++]=e.zoom}}),o}}),{}})());
2
+ //# sourceMappingURL=983.autumnplot-gl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"983.autumnplot-gl.js","mappings":"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","sources":["webpack://apgl/webpack/universalModuleDefinition","webpack://apgl/./node_modules/comlink/dist/esm/comlink.mjs","webpack://apgl/./src/Map.ts","webpack://apgl/./src/PlotLayer.worker.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"apgl\"] = factory();\n\telse\n\t\troot[\"apgl\"] = factory();\n})(this, () => {\nreturn ","/**\r\n * Copyright 2019 Google Inc. All Rights Reserved.\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\nconst proxyMarker = Symbol(\"Comlink.proxy\");\r\nconst createEndpoint = Symbol(\"Comlink.endpoint\");\r\nconst releaseProxy = Symbol(\"Comlink.releaseProxy\");\r\nconst throwMarker = Symbol(\"Comlink.thrown\");\r\nconst isObject = (val) => (typeof val === \"object\" && val !== null) || typeof val === \"function\";\r\n/**\r\n * Internal transfer handle to handle objects marked to proxy.\r\n */\r\nconst proxyTransferHandler = {\r\n canHandle: (val) => isObject(val) && val[proxyMarker],\r\n serialize(obj) {\r\n const { port1, port2 } = new MessageChannel();\r\n expose(obj, port1);\r\n return [port2, [port2]];\r\n },\r\n deserialize(port) {\r\n port.start();\r\n return wrap(port);\r\n },\r\n};\r\n/**\r\n * Internal transfer handler to handle thrown exceptions.\r\n */\r\nconst throwTransferHandler = {\r\n canHandle: (value) => isObject(value) && throwMarker in value,\r\n serialize({ value }) {\r\n let serialized;\r\n if (value instanceof Error) {\r\n serialized = {\r\n isError: true,\r\n value: {\r\n message: value.message,\r\n name: value.name,\r\n stack: value.stack,\r\n },\r\n };\r\n }\r\n else {\r\n serialized = { isError: false, value };\r\n }\r\n return [serialized, []];\r\n },\r\n deserialize(serialized) {\r\n if (serialized.isError) {\r\n throw Object.assign(new Error(serialized.value.message), serialized.value);\r\n }\r\n throw serialized.value;\r\n },\r\n};\r\n/**\r\n * Allows customizing the serialization of certain values.\r\n */\r\nconst transferHandlers = new Map([\r\n [\"proxy\", proxyTransferHandler],\r\n [\"throw\", throwTransferHandler],\r\n]);\r\nfunction expose(obj, ep = self) {\r\n ep.addEventListener(\"message\", function callback(ev) {\r\n if (!ev || !ev.data) {\r\n return;\r\n }\r\n const { id, type, path } = Object.assign({ path: [] }, ev.data);\r\n const argumentList = (ev.data.argumentList || []).map(fromWireValue);\r\n let returnValue;\r\n try {\r\n const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);\r\n const rawValue = path.reduce((obj, prop) => obj[prop], obj);\r\n switch (type) {\r\n case \"GET\" /* GET */:\r\n {\r\n returnValue = rawValue;\r\n }\r\n break;\r\n case \"SET\" /* SET */:\r\n {\r\n parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);\r\n returnValue = true;\r\n }\r\n break;\r\n case \"APPLY\" /* APPLY */:\r\n {\r\n returnValue = rawValue.apply(parent, argumentList);\r\n }\r\n break;\r\n case \"CONSTRUCT\" /* CONSTRUCT */:\r\n {\r\n const value = new rawValue(...argumentList);\r\n returnValue = proxy(value);\r\n }\r\n break;\r\n case \"ENDPOINT\" /* ENDPOINT */:\r\n {\r\n const { port1, port2 } = new MessageChannel();\r\n expose(obj, port2);\r\n returnValue = transfer(port1, [port1]);\r\n }\r\n break;\r\n case \"RELEASE\" /* RELEASE */:\r\n {\r\n returnValue = undefined;\r\n }\r\n break;\r\n default:\r\n return;\r\n }\r\n }\r\n catch (value) {\r\n returnValue = { value, [throwMarker]: 0 };\r\n }\r\n Promise.resolve(returnValue)\r\n .catch((value) => {\r\n return { value, [throwMarker]: 0 };\r\n })\r\n .then((returnValue) => {\r\n const [wireValue, transferables] = toWireValue(returnValue);\r\n ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);\r\n if (type === \"RELEASE\" /* RELEASE */) {\r\n // detach and deactive after sending release response above.\r\n ep.removeEventListener(\"message\", callback);\r\n closeEndPoint(ep);\r\n }\r\n });\r\n });\r\n if (ep.start) {\r\n ep.start();\r\n }\r\n}\r\nfunction isMessagePort(endpoint) {\r\n return endpoint.constructor.name === \"MessagePort\";\r\n}\r\nfunction closeEndPoint(endpoint) {\r\n if (isMessagePort(endpoint))\r\n endpoint.close();\r\n}\r\nfunction wrap(ep, target) {\r\n return createProxy(ep, [], target);\r\n}\r\nfunction throwIfProxyReleased(isReleased) {\r\n if (isReleased) {\r\n throw new Error(\"Proxy has been released and is not useable\");\r\n }\r\n}\r\nfunction createProxy(ep, path = [], target = function () { }) {\r\n let isProxyReleased = false;\r\n const proxy = new Proxy(target, {\r\n get(_target, prop) {\r\n throwIfProxyReleased(isProxyReleased);\r\n if (prop === releaseProxy) {\r\n return () => {\r\n return requestResponseMessage(ep, {\r\n type: \"RELEASE\" /* RELEASE */,\r\n path: path.map((p) => p.toString()),\r\n }).then(() => {\r\n closeEndPoint(ep);\r\n isProxyReleased = true;\r\n });\r\n };\r\n }\r\n if (prop === \"then\") {\r\n if (path.length === 0) {\r\n return { then: () => proxy };\r\n }\r\n const r = requestResponseMessage(ep, {\r\n type: \"GET\" /* GET */,\r\n path: path.map((p) => p.toString()),\r\n }).then(fromWireValue);\r\n return r.then.bind(r);\r\n }\r\n return createProxy(ep, [...path, prop]);\r\n },\r\n set(_target, prop, rawValue) {\r\n throwIfProxyReleased(isProxyReleased);\r\n // FIXME: ES6 Proxy Handler `set` methods are supposed to return a\r\n // boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\r\n const [value, transferables] = toWireValue(rawValue);\r\n return requestResponseMessage(ep, {\r\n type: \"SET\" /* SET */,\r\n path: [...path, prop].map((p) => p.toString()),\r\n value,\r\n }, transferables).then(fromWireValue);\r\n },\r\n apply(_target, _thisArg, rawArgumentList) {\r\n throwIfProxyReleased(isProxyReleased);\r\n const last = path[path.length - 1];\r\n if (last === createEndpoint) {\r\n return requestResponseMessage(ep, {\r\n type: \"ENDPOINT\" /* ENDPOINT */,\r\n }).then(fromWireValue);\r\n }\r\n // We just pretend that `bind()` didn’t happen.\r\n if (last === \"bind\") {\r\n return createProxy(ep, path.slice(0, -1));\r\n }\r\n const [argumentList, transferables] = processArguments(rawArgumentList);\r\n return requestResponseMessage(ep, {\r\n type: \"APPLY\" /* APPLY */,\r\n path: path.map((p) => p.toString()),\r\n argumentList,\r\n }, transferables).then(fromWireValue);\r\n },\r\n construct(_target, rawArgumentList) {\r\n throwIfProxyReleased(isProxyReleased);\r\n const [argumentList, transferables] = processArguments(rawArgumentList);\r\n return requestResponseMessage(ep, {\r\n type: \"CONSTRUCT\" /* CONSTRUCT */,\r\n path: path.map((p) => p.toString()),\r\n argumentList,\r\n }, transferables).then(fromWireValue);\r\n },\r\n });\r\n return proxy;\r\n}\r\nfunction myFlat(arr) {\r\n return Array.prototype.concat.apply([], arr);\r\n}\r\nfunction processArguments(argumentList) {\r\n const processed = argumentList.map(toWireValue);\r\n return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\r\n}\r\nconst transferCache = new WeakMap();\r\nfunction transfer(obj, transfers) {\r\n transferCache.set(obj, transfers);\r\n return obj;\r\n}\r\nfunction proxy(obj) {\r\n return Object.assign(obj, { [proxyMarker]: true });\r\n}\r\nfunction windowEndpoint(w, context = self, targetOrigin = \"*\") {\r\n return {\r\n postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),\r\n addEventListener: context.addEventListener.bind(context),\r\n removeEventListener: context.removeEventListener.bind(context),\r\n };\r\n}\r\nfunction toWireValue(value) {\r\n for (const [name, handler] of transferHandlers) {\r\n if (handler.canHandle(value)) {\r\n const [serializedValue, transferables] = handler.serialize(value);\r\n return [\r\n {\r\n type: \"HANDLER\" /* HANDLER */,\r\n name,\r\n value: serializedValue,\r\n },\r\n transferables,\r\n ];\r\n }\r\n }\r\n return [\r\n {\r\n type: \"RAW\" /* RAW */,\r\n value,\r\n },\r\n transferCache.get(value) || [],\r\n ];\r\n}\r\nfunction fromWireValue(value) {\r\n switch (value.type) {\r\n case \"HANDLER\" /* HANDLER */:\r\n return transferHandlers.get(value.name).deserialize(value.value);\r\n case \"RAW\" /* RAW */:\r\n return value.value;\r\n }\r\n}\r\nfunction requestResponseMessage(ep, msg, transfers) {\r\n return new Promise((resolve) => {\r\n const id = generateUUID();\r\n ep.addEventListener(\"message\", function l(ev) {\r\n if (!ev.data || !ev.data.id || ev.data.id !== id) {\r\n return;\r\n }\r\n ep.removeEventListener(\"message\", l);\r\n resolve(ev.data);\r\n });\r\n if (ep.start) {\r\n ep.start();\r\n }\r\n ep.postMessage(Object.assign({ id }, msg), transfers);\r\n });\r\n}\r\nfunction generateUUID() {\r\n return new Array(4)\r\n .fill(0)\r\n .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))\r\n .join(\"-\");\r\n}\n\nexport { createEndpoint, expose, proxy, proxyMarker, releaseProxy, transfer, transferHandlers, windowEndpoint, wrap };\n//# sourceMappingURL=comlink.mjs.map\n","\n\n// Stub in required method and property types for the mapping library. God help me if these start to diverge between Mapbox and MapLibre.\ntype StyleSpecification = {\n glyphs?: string;\n}\n\n/** Type with the required methods for mapping libraries */\ntype MapLikeType = {\n triggerRepaint: () => void;\n getCanvas: () => HTMLCanvasElement;\n getStyle: () => StyleSpecification;\n\n getZoom: () => number;\n getMaxZoom: () => number;\n getBearing: () => number;\n getPitch: () => number;\n};\n\ninterface LambertConformalConicParameters {\n lon_0: number,\n lat_0: number,\n lat_std: [number, number] | number;\n a: number;\n b: number;\n}\n\nfunction lambertConformalConic(params: LambertConformalConicParameters) {\n // Formulas from https://pubs.usgs.gov/pp/1395/report.pdf\n\n const compute_t = (lat: number) => {\n const sin_lat = Math.sin(lat);\n return Math.tan(Math.PI / 4 - lat / 2) * Math.pow((1 + eccen * sin_lat) / (1 - eccen * sin_lat), eccen / 2);\n };\n const compute_m = (lat: number) => {\n const sin_lat = Math.sin(lat);\n return Math.cos(lat) / Math.sqrt(1 - eccen * eccen * sin_lat * sin_lat);\n }\n\n // WGS 84 spheroid\n const semimajor = params.a;\n const semiminor = params.b;\n const eccen = Math.sqrt(1 - (semiminor * semiminor) / (semimajor * semimajor));\n const radians = Math.PI / 180;\n\n let {lon_0, lat_0, lat_std} = params;\n lat_std = Array.isArray(lat_std) && lat_std[0] == lat_std[1] ? lat_std[0] : lat_std;\n\n lon_0 *= radians;\n lat_0 *= radians;\n\n let F: number, n: number;\n const t_0 = compute_t(lat_0);\n\n if (Array.isArray(lat_std)) {\n let [lat_1, lat_2] = lat_std;\n lat_1 *= radians;\n lat_2 *= radians;\n\n const t_1 = compute_t(lat_1);\n const t_2 = compute_t(lat_2);\n const m_1 = compute_m(lat_1);\n const m_2 = compute_m(lat_2);\n\n n = Math.log(m_1 / m_2) / Math.log(t_1 / t_2);\n F = m_1 / (n * Math.pow(t_1, n));\n }\n else {\n let lat_1 = lat_std;\n lat_1 *= radians;\n\n const t_1 = compute_t(lat_1);\n const m_1 = compute_m(lat_1);\n n = Math.sin(lat_1);\n F = m_1 / (n * Math.pow(t_1, n));\n }\n\n const rho_0 = semimajor * F * Math.pow(t_0, n);\n\n const compute_lcc = (lon: number, lat: number) : [number, number] => {\n lon *= radians;\n lat *= radians;\n\n const t = compute_t(lat);\n const rho = semimajor * F * Math.pow(t, n);\n const theta = n * (lon - lon_0);\n const x = rho * Math.sin(theta);\n const y = rho_0 - rho * Math.cos(theta);\n\n return [x, y];\n }\n\n const eccen2 = eccen * eccen;\n const eccen4 = eccen2 * eccen2;\n const eccen6 = eccen4 * eccen2;\n const eccen8 = eccen6 * eccen2;\n\n/*\n const A = eccen2 / 2 + 5 * eccen4 / 24 + eccen6 / 12 + 13 * eccen8 / 360;\n const B = 7 * eccen4 / 48 + 29 * eccen6 / 240 + 811 * eccen8 / 11520;\n const C = 7 * eccen6 / 120 + 81 * eccen8 / 1120;\n const D = 4279 * eccen8 / 161280;\n const Ap = A - C;\n const Bp = 2 * B - 4 * D;\n const Cp = 4 * C;\n const Dp = 8 * D;\n*/\n\n const Ap = eccen2 / 2 + 5 * eccen4 / 24 + 3 * eccen6 / 120 - 73 * eccen8 / 2016;\n const Bp = 7 * eccen4 / 24 + 29 * eccen6 / 120 + 233 * eccen8 / 6720;\n const Cp = 7 * eccen6 / 30 + 81 * eccen8 / 280;\n const Dp = 4729 * eccen8 / 20160;\n\n const compute_lcc_inverse = (x: number, y: number) : [number, number] => {\n const theta = Math.atan2(x, rho_0 - y); // These arguments are backwards from what I'd expect ...\n const lon = theta / n + lon_0;\n const rho = Math.hypot(x, rho_0 - y) * Math.sign(n);\n const t = Math.pow(rho / (semimajor * F), 1 / n);\n\n const chi = Math.PI / 2 - 2 * Math.atan(t);\n const sin_2chi = Math.sin(2 * chi);\n const cos_2chi = Math.cos(2 * chi);\n\n const lat = chi + sin_2chi * (Ap + cos_2chi * (Bp + cos_2chi * (Cp + Dp * cos_2chi)));\n\n return [lon / radians, lat / radians];\n }\n\n return (a: number, b: number, opts?: {inverse: boolean}) : [number, number] => {\n opts = opts === undefined ? {inverse: false} : opts;\n return opts.inverse ? compute_lcc_inverse(a, b) : compute_lcc(a, b);\n }\n}\n\ninterface RotateSphereParams {\n np_lon: number,\n np_lat: number,\n lon_shift: number,\n}\n\nfunction rotateSphere(params: RotateSphereParams) {\n const radians = Math.PI / 180;\n const np_lat = params.np_lat * radians;\n const np_lon = params.np_lon * radians;\n const lon_shift = params.lon_shift * radians;\n\n const sin_np_lat = Math.sin(np_lat);\n const cos_np_lat = Math.cos(np_lat);\n\n const compute_rotation = (lon: number, lat: number) : [number, number] => {\n lon *= radians;\n lat *= radians;\n\n const sin_lat = Math.sin(lat);\n const cos_lat = Math.cos(lat);\n const sin_lon_diff = Math.sin(lon - lon_shift);\n const cos_lon_diff = Math.cos(lon - lon_shift);\n\n const lat_p = Math.asin(sin_np_lat * sin_lat - cos_np_lat * cos_lat * cos_lon_diff);\n let lon_p = np_lon + Math.atan2((cos_lat * sin_lon_diff), (sin_np_lat * cos_lat * cos_lon_diff + cos_np_lat * sin_lat));\n\n if (lon_p > Math.PI) lon_p -= 2 * Math.PI;\n\n return [lon_p / radians, lat_p / radians];\n }\n\n const compute_rotation_inverse = (lon_p: number, lat_p: number) : [number, number] => {\n lon_p *= radians;\n lat_p *= radians;\n\n const sin_lat_p = Math.sin(lat_p);\n const cos_lat_p = Math.cos(lat_p);\n const sin_lon_p_diff = Math.sin(lon_p - np_lon);\n const cos_lon_p_diff = Math.cos(lon_p - np_lon);\n\n const lat = Math.asin(sin_np_lat * sin_lat_p + cos_np_lat * cos_lat_p * cos_lon_p_diff);\n let lon = lon_shift + Math.atan2((cos_lat_p * sin_lon_p_diff), (sin_np_lat * cos_lat_p * cos_lon_p_diff - cos_np_lat * sin_lat_p));\n\n if (lon_p > Math.PI) lon_p -= 2 * Math.PI;\n\n return [lon / radians, lat / radians];\n }\n\n return (a: number, b: number, opts?: {inverse: boolean}) => {\n opts = opts === undefined ? {inverse: false} : opts;\n return opts.inverse ? compute_rotation_inverse(a, b) : compute_rotation(a, b);\n }\n}\n\ninterface VerticalPerspectiveParams {\n lat_0: number,\n lon_0: number,\n alt: number,\n a: number,\n b: number,\n}\n\nfunction verticalPerspective(params: VerticalPerspectiveParams) {\n // WGS 84 spheroid\n const semimajor = params.a;\n const semiminor = params.b;\n const eccen = Math.sqrt(1 - (semiminor * semiminor) / (semimajor * semimajor));\n const radians = Math.PI / 180;\n\n let {lat_0, lon_0, alt} = params;\n const alt_0 = 0;\n const alt_00 = 0;\n const eccen2 = eccen * eccen;\n\n lat_0 *= radians;\n lon_0 *= radians;\n\n const sin_lat_0 = Math.sin(lat_0);\n const cos_lat_0 = Math.cos(lat_0);\n\n const N1 = semimajor / Math.sqrt(1 - (eccen * sin_lat_0) ** 2);\n let lat_g = lat_0, P = 0;\n\n for (let i = 0; i < 2; i++) {\n P = Math.cos(lat_0) / Math.cos(lat_g) * (alt + N1 + alt_00) / semimajor;\n lat_g = lat_0 - Math.asin(N1 * eccen * eccen * sin_lat_0 * cos_lat_0 / (P * semimajor));\n }\n\n const compute_perspective = (lon: number, lat: number) : [number, number] => {\n lon *= radians;\n lat *= radians;\n\n const sin_lat = Math.sin(lat);\n const cos_lat = Math.cos(lat);\n\n const N = semimajor / Math.sqrt(1 - (eccen * sin_lat) ** 2);\n const C = (N + alt_0) / semimajor * cos_lat;\n const S = ((N * (1 - eccen * eccen) + alt_0) / semimajor) * sin_lat;\n const K = alt / (P * Math.cos(lat_0 - lat_g) - S * sin_lat_0 - C * cos_lat_0 * Math.cos(lon - lon_0));\n const x = K * C * Math.sin(lon - lon_0);\n const y = K * (P * Math.sin(lat_0 - lat_g) + S * cos_lat_0 - C * sin_lat_0 * Math.cos(lon - lon_0));\n\n return [x, y];\n }\n\n const B = P * Math.cos(lat_0 - lat_g);\n const D = P * Math.sin(lat_0 - lat_g);\n const L = 1 - eccen2 * cos_lat_0 * cos_lat_0;\n const G = 1 - eccen2 * sin_lat_0 * sin_lat_0;\n const J = 2 * eccen2 * sin_lat_0 * cos_lat_0;\n const E = 1; // If alt_0 = 0, set E = 1\n const t = P * P * (1 - (eccen * Math.cos(lat_g)) ** 2) - E * (1 - eccen2);\n\n const compute_perspective_inverse = (x: number, y: number) : [number, number] => {\n const u = -2 * B * L * alt - 2 * D * G * y + B * J * y + D * J * alt;\n const v = L * alt * alt + G * y * y - alt * J * y + (1 - eccen2) * x * x;\n const K_prime = (-u + Math.sqrt(u * u - 4 * t * v)) / (2 * t);\n const X = semimajor * ((B - alt / K_prime) * cos_lat_0 - (y / K_prime - D) * sin_lat_0);\n const Y = semimajor * x / K_prime;\n const S = (y / K_prime - D) * cos_lat_0 + (B - alt / K_prime) * sin_lat_0;\n const lon = lon_0 + Math.atan2(Y, X);\n const lat = Math.atan2(S, Math.sqrt((1 - eccen2) * (1 - eccen2 - S * S)));\n\n return [lon / radians, lat / radians];\n }\n\n return (a: number, b: number, opts?: {inverse: boolean}) => {\n opts = opts === undefined ? {inverse: false} : opts;\n return opts.inverse ? compute_perspective_inverse(a, b) : compute_perspective(a, b);\n }\n}\n\nfunction mercatorXfromLng(lng: number) {\n return (180 + lng) / 360;\n}\n\nfunction lngFromMercatorX(x: number) {\n return 360 * x - 180;\n}\n\nfunction mercatorYfromLat(lat: number) {\n const sin_lat = Math.sin(lat * Math.PI / 180);\n const y = (180 - (90 / Math.PI * Math.log((1 + sin_lat) / (1 - sin_lat)))) / 360;\n return Math.min(1.5, Math.max(-0.5, y));\n}\n\nfunction latFromMercatorY(y: number) {\n return Math.atan(Math.sinh((180 - y * 360) * Math.PI / 180)) * 180 / Math.PI;\n}\n\n/**\n * A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.\n * These coordinates are based on the [WGS84 (EPSG:4326) standard](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84).\n *\n * MapLibre GL uses longitude, latitude coordinate order (as opposed to latitude, longitude) to match the\n * [GeoJSON specification](https://tools.ietf.org/html/rfc7946).\n *\n * @param {number} lng Longitude, measured in degrees.\n * @param {number} lat Latitude, measured in degrees.\n * @example\n * var ll = new LngLat(-123.9749, 40.7736);\n * ll.lng; // = -123.9749\n */\n class LngLat {\n public lng: number;\n public lat: number;\n\n constructor(lng: number, lat: number) {\n if (isNaN(lng) || isNaN(lat)) {\n throw new Error(`Invalid LngLat object: (${lng}, ${lat})`);\n }\n this.lng = +lng;\n this.lat = +lat;\n if (this.lat > 90 || this.lat < -90) {\n throw new Error('Invalid LngLat latitude value: must be between -90 and 90');\n }\n }\n\n public toMercatorCoord() {\n return {x: mercatorXfromLng(this.lng), y: mercatorYfromLat(this.lat)};\n }\n\n public static fromMercatorCoord(x: number, y: number) {\n return new LngLat(lngFromMercatorX(x), latFromMercatorY(y));\n }\n}\n\nexport {LngLat, lambertConformalConic, rotateSphere, verticalPerspective};\nexport type {MapLikeType};","\nimport { getMinZoom } from \"./utils\";\nimport { LineData, Polyline } from \"./AutumnTypes\";\n\nimport * as Comlink from 'comlink';\nimport { LngLat } from \"./Map\";\n\nfunction makeBBElements(field_lats: Float32Array, field_lons: Float32Array, min_zoom: Uint8Array, field_ni: number, field_nj: number, map_max_zoom: number) {\n \n const n_coords_per_pt_pts = 2;\n const n_coords_per_pt_tc = 2;\n\n const field_n_access = min_zoom.filter(mz => mz <= map_max_zoom).length;\n const n_elems_pts = field_n_access * n_coords_per_pt_pts;\n const n_elems_tc = field_n_access * n_coords_per_pt_tc;\n\n let pts = new Float32Array(n_elems_pts);\n let tex_coords = new Float32Array(n_elems_tc);\n\n let istart_pts = 0;\n let istart_tc = 0;\n\n for (let ilat = 0; ilat < field_nj; ilat++) {\n for (let ilon = 0; ilon < field_ni; ilon++) {\n const idx = ilat * field_ni + ilon;\n const lat = field_lats[idx];\n const lon = field_lons[idx];\n const zoom = min_zoom[idx];\n\n if (zoom > map_max_zoom || lon === undefined || lat === undefined) continue; // TAS: Adding the checks for lat/lon here may be a bug waiting to happen? Not sure.\n\n const pt_ll = new LngLat(lon, lat).toMercatorCoord();\n\n pts[istart_pts + 0] = pt_ll.x; \n pts[istart_pts + 1] = pt_ll.y; \n\n // Pack the min zoom in with the texture coordinates; only works because the min zoom is always an integer\n // Another gotcha is that if the i texcoord is 1, then that bump up the zoom that gets unpacked on the GPU, which causes may cause the last column of billboards to\n // disappear. To fix this, cap the texcoord at 0.99999, which should be good for textures up to 10^5 pixels in size.\n tex_coords[istart_tc + 0] = Math.min(ilon / (field_ni - 1), 0.99999) + zoom;\n tex_coords[istart_tc + 1] = ilat / (field_nj - 1);\n\n istart_pts += n_coords_per_pt_pts;\n istart_tc += n_coords_per_pt_tc;\n }\n }\n\n return {'pts': pts, 'tex_coords': tex_coords};\n}\n\nfunction makeDomainVerticesAndTexCoords(field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, texcoord_margin_r: number, texcoord_margin_s: number) {\n const verts = new Float32Array(2 * 2 * (field_ni - 1) * (field_nj + 1)).fill(0);\n const tex_coords = new Float32Array(2 * 2 * (field_ni - 1) * (field_nj + 1)).fill(0);\n\n let ivert = 0\n let itexcoord = 0;\n\n for (let i = 0; i < field_ni - 1; i++) {\n for (let j = 0; j < field_nj; j++) {\n const idx = i + j * field_ni;\n\n const pt = new LngLat(field_lons[idx], field_lats[idx]).toMercatorCoord();\n const pt_ip1 = new LngLat(field_lons[idx + 1], field_lats[idx + 1]).toMercatorCoord();\n\n const r = i / (field_ni - 1) * (1 - 2 * texcoord_margin_r) + texcoord_margin_r;\n const rp1 = (i + 1) / (field_ni - 1) * (1 - 2 * texcoord_margin_r) + texcoord_margin_r;\n const s = j / (field_nj - 1) * (1 - 2 * texcoord_margin_s) + texcoord_margin_s;\n\n if (j == 0) {\n verts[ivert] = pt.x; verts[ivert + 1] = pt.y;\n ivert += 2\n\n tex_coords[itexcoord] = r; tex_coords[itexcoord + 1] = s;\n itexcoord += 2;\n }\n\n verts[ivert ] = pt.x; verts[ivert + 1] = pt.y;\n verts[ivert + 2] = pt_ip1.x; verts[ivert + 3] = pt_ip1.y;\n ivert += 4;\n\n tex_coords[itexcoord ] = r; tex_coords[itexcoord + 1] = s;\n tex_coords[itexcoord + 2] = rp1; tex_coords[itexcoord + 3] = s;\n itexcoord += 4;\n\n if (j == field_nj - 1) {\n verts[ivert] = pt_ip1.x; verts[ivert + 1] = pt_ip1.y;\n ivert += 2;\n\n tex_coords[itexcoord] = rp1; tex_coords[itexcoord + 1] = s;\n itexcoord += 2;\n }\n }\n }\n\n return {'vertices': verts, 'tex_coords': tex_coords};\n}\n\n/*\nfunction makePolylinesMiter(lines) {\n const n_points_per_vert = Object.fromEntries(Object.entries(lines[0]).map(([k, v]) => {\n let n_verts;\n if (v.length === undefined) {\n n_verts = 1;\n }\n else {\n n_verts = k == 'verts' ? v[0].length : v.length;\n }\n return [k, n_verts];\n }));\n n_points_per_vert['extrusion'] = 2;\n\n const n_verts = lines.map(l => l['verts'].length).reduce((a, b) => a + b);\n const ary_lens = Object.fromEntries(Object.entries(n_points_per_vert).map(([k, nppv]) => [k, (n_verts * 2 + lines.length * 2) * nppv]));\n\n let ret = Object.fromEntries(Object.entries(ary_lens).map(([k, v]) => [k, new Float32Array(v)]));\n\n let ilns = Object.fromEntries(Object.keys(ary_lens).map(k => [k, 0]));\n\n const is_cw_winding = (pt_prev, pt_this, pt_next) => {\n const winding = (pt_this[0] - pt_prev[0]) * (pt_this[1] + pt_prev[1]) \n + (pt_next[0] - pt_this[0]) * (pt_next[1] + pt_this[1]) \n + (pt_prev[0] - pt_next[0]) * (pt_prev[1] + pt_next[1]);\n\n return winding > 0;\n }\n\n const calculate_extrusion = (pt_prev, pt_this, pt_next) => {\n let line_vec_x_prev, line_vec_y_prev, line_vec_mag_prev, \n line_vec_x_next, line_vec_y_next, line_vec_mag_next;\n let ext_x, ext_y;\n\n if (pt_prev !== null) {\n line_vec_x_prev = pt_this[0] - pt_prev[0];\n line_vec_y_prev = pt_this[1] - pt_prev[1];\n line_vec_mag_prev = Math.hypot(line_vec_x_prev, line_vec_y_prev);\n line_vec_x_prev /= line_vec_mag_prev;\n line_vec_y_prev /= line_vec_mag_prev;\n }\n\n if (pt_next !== null) {\n line_vec_x_next = pt_next[0] - pt_this[0];\n line_vec_y_next = pt_next[1] - pt_this[1];\n line_vec_mag_next = Math.hypot(line_vec_x_next, line_vec_y_next);\n line_vec_x_next /= line_vec_mag_next;\n line_vec_y_next /= line_vec_mag_next;\n }\n\n if (pt_prev === null) {\n // First point in the line gets just the normal for the first segment\n ext_x = line_vec_y_next; ext_y = -line_vec_x_next;\n }\n else if (pt_this === null) {\n // Last point in the line gets just the normal for the last segment\n ext_x = line_vec_y_prev; ext_y = -line_vec_x_prev;\n }\n else {\n // Miter join: compute the extrusion vector halfway between the next and previous normal\n const dot = line_vec_x_prev * line_vec_x_next + line_vec_y_prev * line_vec_y_next;\n const ext_fac = Math.sqrt((1 - dot) / (1 + dot));\n const sign = is_cw_winding(pt_prev, pt_this, pt_this) ? -1 : 1;\n ext_x = line_vec_y_prev + sign * line_vec_x_prev * ext_fac;\n ext_y = sign * line_vec_y_prev * ext_fac - line_vec_x_prev;\n }\n\n return [ext_x, ext_y];\n }\n\n lines.forEach(line => {\n const verts = line['verts'];\n let ext_x, ext_y;\n\n let ivt = 0;\n ret['verts'][ilns['verts']] = verts[ivt][0]; ret['verts'][ilns['verts'] + 1] = verts[ivt][1];\n\n [ext_x, ext_y] = calculate_extrusion(null, verts[ivt], verts[ivt + 1]);\n ret['extrusion'][ilns['extrusion']] = ext_x; ret['extrusion'][ilns['extrusion'] + 1] = ext_y;\n\n for (ivt = 0; ivt < verts.length; ivt++) {\n const ary_ivt = ilns['verts'] + 2 * (2 * ivt + 1);\n ret['verts'][ary_ivt + 0] = verts[ivt][0]; ret['verts'][ary_ivt + 1] = verts[ivt][1];\n ret['verts'][ary_ivt + 2] = verts[ivt][0]; ret['verts'][ary_ivt + 3] = verts[ivt][1];\n\n if (ivt == 0) {\n [ext_x, ext_y] = calculate_extrusion(null, verts[ivt], verts[ivt + 1]);\n }\n else if (ivt == verts.length - 1) {\n [ext_x, ext_y] = calculate_extrusion(verts[ivt - 1], verts[ivt], null);\n }\n else {\n [ext_x, ext_y] = calculate_extrusion(verts[ivt - 1], verts[ivt], verts[ivt + 1]);\n }\n\n ret['extrusion'][ary_ivt + 0] = ext_x; ret['extrusion'][ary_ivt + 1] = ext_y;\n ret['extrusion'][ary_ivt + 2] = -ext_x; ret['extrusion'][ary_ivt + 3] = -ext_y;\n }\n\n ivt = verts.length - 1;\n ret['verts'][ilns['verts'] + 2 * (2 * ivt + 1) + 4] = verts[ivt][0]; \n ret['verts'][ilns['verts'] + 2 * (2 * ivt + 1) + 5] = verts[ivt][1];\n \n [ext_x, ext_y] = calculate_extrusion(verts[ivt - 1], verts[ivt], null);\n\n ret['extrusion'][ilns['extrusion'] + 2 * (2 * ivt + 1) + 4] = -ext_x; \n ret['extrusion'][ilns['extrusion'] + 2 * (2 * ivt + 1) + 5] = -ext_y;\n\n for (let key in ret) {\n if (key == 'verts' || key == 'extrusion') continue;\n\n for (ivt = 0; ivt < (verts.length * 2 + 2) * n_points_per_vert[key]; ivt += n_points_per_vert[key]) {\n if (line[key].length !== undefined) {\n line[key].forEach((cd, icd) => {\n ret[key][ilns[key] + ivt + icd] = cd;\n })\n }\n else {\n ret[key][ilns[key] + ivt] = line[key];\n }\n }\n }\n\n Object.keys(ilns).forEach(k => {\n ilns[k] += (verts.length * 2 + 2) * n_points_per_vert[k];\n })\n })\n\n return ret;\n}\n*/\n\nfunction makePolylines(lines: LineData[]) : Polyline {\n if (lines.length == 0 || lines[0].vertices.length == 0) {\n return {vertices: new Float32Array([]), extrusion: new Float32Array([])};\n }\n\n const n_points_per_vert = Object.fromEntries(Object.entries(lines[0]).map(([k, v]) => {\n let n_verts: number;\n if (typeof v === 'number') {\n n_verts = 1;\n }\n else if (typeof v[0] === 'number') {\n n_verts = 1;\n }\n else {\n n_verts = v[0].length;\n }\n return [k, n_verts];\n }));\n n_points_per_vert['extrusion'] = 2;\n n_points_per_vert['vertices'] += 1;\n\n const n_verts = lines.map(l => l.vertices.length).reduce((a, b) => a + b);\n const n_out_verts = n_verts * 4 - lines.length * 2;\n const ary_lens = Object.fromEntries(Object.entries(n_points_per_vert).map(([k, nppv]) => [k, n_out_verts * nppv]));\n\n let ret: Polyline = {\n vertices: new Float32Array(ary_lens['vertices']),\n extrusion: new Float32Array(ary_lens['extrusion']),\n }\n\n if ('offsets' in lines[0]) {\n ret.offsets = new Float32Array(ary_lens['offsets']);\n }\n\n if ('data' in lines[0]) {\n ret.data = new Float32Array(ary_lens['data']);\n }\n\n if ('zoom' in lines[0]) {\n ret.zoom = new Float32Array(ary_lens['zoom']);\n }\n\n let ilns = Object.fromEntries(Object.keys(ary_lens).map(k => [k, 0]));\n\n const compute_normal_vec = (pt1: [number, number], pt2: [number, number], flip_y_coord: boolean) => {\n const line_vec_x = pt2[0] - pt1[0];\n const line_vec_y = pt2[1] - pt1[1];\n const line_vec_mag = Math.hypot(line_vec_x, line_vec_y);\n\n const ext_x = line_vec_y / line_vec_mag;\n const ext_y = -line_vec_x / line_vec_mag;\n\n return [ext_x, flip_y_coord ? -ext_y : ext_y];\n }\n\n lines.forEach(line => {\n const verts = line.vertices.map(v => {\n const v_ll = new LngLat(...v).toMercatorCoord();\n return [v_ll.x, v_ll.y] as [number, number];\n });\n\n if (line.vertices.length == 0) {\n return;\n }\n\n const has_offsets = line.offsets !== undefined;\n const extrusion_verts = line.offsets !== undefined ? line.offsets : verts;\n\n let pt_prev: [number, number], pt_this = verts[0], pt_next = verts[1];\n let ept_prev: [number, number], ept_this = extrusion_verts[0], ept_next = extrusion_verts[1];\n let len_prev: number, len_this = 0.0001;\n let [ext_x, ext_y] = compute_normal_vec(ept_this, ept_next, !has_offsets);\n\n ret.vertices[ilns.vertices++] = pt_this[0]; ret.vertices[ilns.vertices++] = pt_this[1]; ret.vertices[ilns.vertices++] = len_this;\n ret.extrusion[ilns.extrusion++] = ext_x; ret.extrusion[ilns.extrusion++] = ext_y;\n\n for (let ivt = 1; ivt < verts.length; ivt++) {\n pt_this = verts[ivt]; pt_prev = verts[ivt - 1];\n ept_this = extrusion_verts[ivt]; ept_prev = extrusion_verts[ivt - 1];\n\n [ext_x, ext_y] = compute_normal_vec(ept_prev, ept_this, !has_offsets);\n len_prev = len_this; len_this += Math.hypot(verts[ivt - 1][0] - verts[ivt][0], verts[ivt - 1][1] - verts[ivt][1]);\n\n ret.vertices[ilns.vertices++] = pt_prev[0]; ret.vertices[ilns.vertices++] = pt_prev[1]; ret.vertices[ilns.vertices++] = -len_prev;\n ret.vertices[ilns.vertices++] = pt_prev[0]; ret.vertices[ilns.vertices++] = pt_prev[1]; ret.vertices[ilns.vertices++] = len_prev;\n\n ret.vertices[ilns.vertices++] = pt_this[0]; ret.vertices[ilns.vertices++] = pt_this[1]; ret.vertices[ilns.vertices++] = -len_this;\n ret.vertices[ilns.vertices++] = pt_this[0]; ret.vertices[ilns.vertices++] = pt_this[1]; ret.vertices[ilns.vertices++] = len_this;\n\n ret.extrusion[ilns.extrusion++] = ext_x; ret.extrusion[ilns.extrusion++] = ext_y;\n ret.extrusion[ilns.extrusion++] = -ext_x; ret.extrusion[ilns.extrusion++] = -ext_y;\n\n ret.extrusion[ilns.extrusion++] = ext_x; ret.extrusion[ilns.extrusion++] = ext_y;\n ret.extrusion[ilns.extrusion++] = -ext_x; ret.extrusion[ilns.extrusion++] = -ext_y;\n }\n\n ret.vertices[ilns.vertices++] = pt_this[0]; ret.vertices[ilns.vertices++] = pt_this[1]; ret.vertices[ilns.vertices++] = len_this;\n ret.extrusion[ilns.extrusion++] = -ext_x; ret.extrusion[ilns.extrusion++] = -ext_y;\n\n if (ret.offsets !== undefined && line.offsets !== undefined) {\n const offsets = line.offsets;\n let off_prev: [number, number], off_this = offsets[0];\n\n ret.offsets[ilns.offsets++] = off_this[0]; ret.offsets[ilns.offsets++] = off_this[1];\n\n for (let ivt = 1; ivt < offsets.length; ivt++) {\n off_this = offsets[ivt]; off_prev = offsets[ivt - 1];\n\n ret.offsets[ilns.offsets++] = off_prev[0]; ret.offsets[ilns.offsets++] = off_prev[1];\n ret.offsets[ilns.offsets++] = off_prev[0]; ret.offsets[ilns.offsets++] = off_prev[1];\n ret.offsets[ilns.offsets++] = off_this[0]; ret.offsets[ilns.offsets++] = off_this[1];\n ret.offsets[ilns.offsets++] = off_this[0]; ret.offsets[ilns.offsets++] = off_this[1];\n }\n\n ret.offsets[ilns.offsets++] = off_this[0]; ret.offsets[ilns.offsets++] = off_this[1];\n }\n\n if (ret.data !== undefined && line.data !== undefined) {\n const data = line.data;\n let data_prev: number, data_this = data[0];\n\n ret.data[ilns.data++] = data_this;\n \n for (let ivt = 1; ivt < data.length; ivt++) {\n data_this = data[ivt]; data_prev = data[ivt - 1];\n\n ret.data[ilns.data++] = data_prev;\n ret.data[ilns.data++] = data_prev;\n ret.data[ilns.data++] = data_this;\n ret.data[ilns.data++] = data_this;\n }\n\n ret.data[ilns.data++] = data_this;\n }\n \n if (ret.zoom !== undefined && line.zoom !== undefined) {\n for (let ivt = 0; ivt < verts.length * 4 - 2; ivt++) {\n ret.zoom[ilns.zoom++] = line['zoom'];\n }\n }\n })\n\n return ret;\n}\n\nconst ep_interface = {\n 'makeBBElements': makeBBElements, \n 'makeDomainVerticesAndTexCoords': makeDomainVerticesAndTexCoords,\n 'makePolyLines': makePolylines\n}\n\ntype PlotLayerWorker = typeof ep_interface;\n\nComlink.expose(ep_interface);\n\nexport type {PlotLayerWorker}"],"names":["root","factory","exports","module","define","amd","this","proxyMarker","Symbol","createEndpoint","releaseProxy","throwMarker","isObject","val","transferHandlers","Map","canHandle","serialize","obj","port1","port2","MessageChannel","expose","deserialize","port","start","createProxy","target","value","serialized","Error","isError","message","name","stack","Object","assign","ep","self","addEventListener","callback","ev","data","id","type","path","argumentList","map","fromWireValue","returnValue","parent","slice","reduce","prop","rawValue","apply","proxy","transfers","transferCache","set","transfer","undefined","Promise","resolve","catch","then","wireValue","transferables","toWireValue","postMessage","removeEventListener","closeEndPoint","endpoint","constructor","isMessagePort","close","throwIfProxyReleased","isReleased","isProxyReleased","Proxy","get","_target","requestResponseMessage","p","toString","length","r","bind","_thisArg","rawArgumentList","last","processArguments","construct","processed","v","arr","Array","prototype","concat","WeakMap","handler","serializedValue","msg","fill","Math","floor","random","Number","MAX_SAFE_INTEGER","join","l","lng","lat","isNaN","toMercatorCoord","x","y","sin_lat","sin","PI","log","min","max","fromMercatorCoord","LngLat","lngFromMercatorX","atan","sinh","latFromMercatorY","field_lats","field_lons","min_zoom","field_ni","field_nj","map_max_zoom","field_n_access","filter","mz","n_elems_tc","pts","Float32Array","tex_coords","istart_pts","istart_tc","ilat","ilon","idx","lon","zoom","pt_ll","texcoord_margin_r","texcoord_margin_s","verts","ivert","itexcoord","i","j","pt","pt_ip1","rp1","s","lines","vertices","extrusion","n_points_per_vert","fromEntries","entries","k","n_out_verts","a","b","ary_lens","nppv","ret","offsets","ilns","keys","compute_normal_vec","pt1","pt2","flip_y_coord","line_vec_x","line_vec_y","line_vec_mag","hypot","ext_y","forEach","line","v_ll","pt_prev","ept_prev","len_prev","has_offsets","extrusion_verts","pt_this","ept_this","ept_next","len_this","ext_x","ivt","off_prev","off_this","data_prev","data_this"],"sourceRoot":""}