autumnplot-gl 4.0.0 → 4.1.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.
Files changed (77) hide show
  1. package/README.md +2 -0
  2. package/dist/812.autumnplot-gl.js +2 -0
  3. package/dist/812.autumnplot-gl.js.map +1 -0
  4. package/dist/983.autumnplot-gl.js +1 -1
  5. package/dist/983.autumnplot-gl.js.map +1 -1
  6. package/dist/autumnplot-gl.js +1 -1
  7. package/dist/autumnplot-gl.js.map +1 -1
  8. package/dist/marchingsquares.wasm +0 -0
  9. package/lib/AutumnTypes.d.ts +6 -4
  10. package/lib/AutumnTypes.js +4 -1
  11. package/lib/Barbs.d.ts +11 -2
  12. package/lib/Barbs.js +9 -0
  13. package/lib/BillboardCollection.d.ts +2 -2
  14. package/lib/BillboardCollection.js +14 -14
  15. package/lib/ColorBar.d.ts +6 -1
  16. package/lib/ColorBar.js +10 -4
  17. package/lib/Colormap.d.ts +8 -1
  18. package/lib/Colormap.js +24 -1
  19. package/lib/Contour.d.ts +16 -1
  20. package/lib/Contour.js +14 -2
  21. package/lib/{ContourCreator.d.ts → ContourCreator.worker.d.ts} +10 -11
  22. package/lib/{ContourCreator.js → ContourCreator.worker.js} +15 -14
  23. package/lib/Fill.d.ts +29 -11
  24. package/lib/Fill.js +38 -18
  25. package/lib/Hodographs.d.ts +13 -3
  26. package/lib/Hodographs.js +11 -1
  27. package/lib/Map.d.ts +3 -4
  28. package/lib/Map.js +49 -51
  29. package/lib/Paintball.d.ts +13 -5
  30. package/lib/Paintball.js +96 -46
  31. package/lib/PlotComponent.d.ts +8 -3
  32. package/lib/PlotComponent.js +35 -1
  33. package/lib/PlotLayer.worker.js +1 -1
  34. package/lib/RawField.d.ts +221 -27
  35. package/lib/RawField.js +405 -58
  36. package/lib/StationPlot.d.ts +22 -6
  37. package/lib/StationPlot.js +88 -22
  38. package/lib/TextCollection.d.ts +5 -0
  39. package/lib/TextCollection.js +79 -9
  40. package/lib/WasmInterface.d.ts +7 -0
  41. package/lib/WasmInterface.js +11 -0
  42. package/lib/WorkerPool.d.ts +8 -0
  43. package/lib/WorkerPool.js +77 -0
  44. package/lib/cpp/marchingsquares.js +127 -13
  45. package/lib/cpp/marchingsquares.wasm +0 -0
  46. package/lib/cpp/marchingsquares_embind.d.ts +16 -3
  47. package/lib/grids/AutoZoom.d.ts +21 -0
  48. package/lib/grids/AutoZoom.js +63 -0
  49. package/lib/grids/DomainBuffer.d.ts +14 -0
  50. package/lib/grids/DomainBuffer.js +16 -0
  51. package/lib/grids/Geostationary.d.ts +35 -0
  52. package/lib/grids/Geostationary.js +47 -0
  53. package/lib/grids/Grid.d.ts +36 -0
  54. package/lib/grids/Grid.js +12 -0
  55. package/lib/grids/GridCoordinates.d.ts +10 -0
  56. package/lib/grids/GridCoordinates.js +64 -0
  57. package/lib/grids/LambertGrid.d.ts +73 -0
  58. package/lib/grids/LambertGrid.js +92 -0
  59. package/lib/grids/PlateCarreeGrid.d.ts +46 -0
  60. package/lib/grids/PlateCarreeGrid.js +55 -0
  61. package/lib/grids/PlateCarreeRotatedGrid.d.ts +53 -0
  62. package/lib/grids/PlateCarreeRotatedGrid.js +65 -0
  63. package/lib/grids/RadarSweepGrid.d.ts +46 -0
  64. package/lib/grids/RadarSweepGrid.js +74 -0
  65. package/lib/grids/StructuredGrid.d.ts +49 -0
  66. package/lib/grids/StructuredGrid.js +103 -0
  67. package/lib/grids/UnstructuredGrid.d.ts +56 -0
  68. package/lib/grids/UnstructuredGrid.js +102 -0
  69. package/lib/index.d.ts +15 -4
  70. package/lib/index.js +15 -7
  71. package/lib/utils.d.ts +11 -2
  72. package/lib/utils.js +63 -1
  73. package/package.json +3 -2
  74. package/lib/Grid.d.ts +0 -270
  75. package/lib/Grid.js +0 -600
  76. package/lib/ParticleTracer.d.ts +0 -19
  77. package/lib/ParticleTracer.js +0 -37
@@ -76,8 +76,35 @@ function positionToAlignmentAndOffset(pos, off_size) {
76
76
  }
77
77
  return { horizontal_align: ha, vertical_align: va, offset_x: xoff, offset_y: yoff };
78
78
  }
79
+ function symbolCategory(symbol) {
80
+ const sym = symbol.toLowerCase();
81
+ if (sym.includes('fzra') || (sym.includes('fz') && sym.includes('ra')))
82
+ return 'freezing_rain';
83
+ if (sym.includes('pl'))
84
+ return 'sleet';
85
+ if (sym.includes('sn') || sym.includes('sg') || sym.includes('gs'))
86
+ return 'snow';
87
+ if (sym.includes('ra') || sym.includes('dz'))
88
+ return 'rain';
89
+ if (sym.includes('du') || sym.includes('ds') || sym.includes('ss') || sym.includes('blsa') || sym.includes('bldu') || sym.includes('blpy'))
90
+ return 'blowing_dust';
91
+ if (sym.includes('ts') || sym.includes('thdr'))
92
+ return 'thunder';
93
+ if (sym.includes('fg'))
94
+ return 'fog';
95
+ return 'none';
96
+ }
79
97
  /**
80
98
  * Station model plots for observed data
99
+ *
100
+ * ## Grid Compatibility
101
+ * - :white_check_mark: `PlateCarreeGrid`
102
+ * - :white_check_mark: `PlateCarreeRotatedGrid`
103
+ * - :white_check_mark: `LambertGrid`
104
+ * - :white_check_mark: `UnstructuredGrid`
105
+ * - :x: `RadarSweepGrid`
106
+ * - :x: `Geostationary`
107
+ *
81
108
  * @example
82
109
  * // Specify how to set up the station plot
83
110
  * const station_plot_locs = {
@@ -120,32 +147,51 @@ class StationPlot extends PlotComponent {
120
147
  if (font_url_template === undefined)
121
148
  throw "The map style doesn't have any glyph information. Please pass the font_url_template option to StationPlot";
122
149
  const font_url = font_url_template.replace('{fontstack}', this.opts.font_face);
150
+ const coords = this.field.grid.getEarthCoords();
151
+ const zoom = this.field.grid.getMinVisibleZoom(this.opts.thin_fac);
123
152
  let ibarb = 0;
124
- const sub_component_promises = Object.entries(this.opts.config).map(async ([k_, config]) => {
153
+ let sub_component_promises = [];
154
+ Object.entries(this.opts.config).forEach(async ([k_, config]) => {
125
155
  const k = k_;
126
156
  if (config.type == 'number' || config.type == 'string') {
127
157
  const pos = config.pos;
128
158
  const color = config.color === undefined ? Color.fromHex('#000000') : Color.normalizeColor(config.color);
129
159
  const halo_color = config.halo_color === undefined ? Color.fromHex('#ffffff') : Color.normalizeColor(config.halo_color);
130
160
  const halo = config.halo === undefined ? true : config.halo;
131
- const coords = this.field.grid.getEarthCoords();
132
- const zoom = this.field.grid.getMinVisibleZoom(this.opts.thin_fac);
161
+ let cmap = null;
133
162
  let text_specs;
134
163
  if (config.type == 'number') {
164
+ cmap = config.cmap === undefined ? null : config.cmap;
135
165
  const comp = this.field.getScalar(k);
136
166
  const formatter = config.formatter === undefined ? (val) => val === null ? 'null' : val.toString() : config.formatter;
137
- text_specs = comp.map((v, i) => ({ text: formatter(v), lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
167
+ text_specs = comp.map((v, i) => {
168
+ const spec = {
169
+ text: formatter(v),
170
+ lat: coords.lats[i],
171
+ lon: coords.lons[i],
172
+ min_zoom: zoom[i],
173
+ };
174
+ if (v !== null)
175
+ spec.data_value = v;
176
+ return spec;
177
+ });
138
178
  }
139
179
  else {
140
180
  const comp = this.field.getStrings(k);
141
- text_specs = comp.map((v, i) => ({ text: v === null ? '' : v, lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
181
+ text_specs = comp.map((v, i) => ({
182
+ text: v === null ? '' : v,
183
+ lat: coords.lats[i],
184
+ lon: coords.lons[i],
185
+ min_zoom: zoom[i],
186
+ }));
142
187
  }
143
188
  const tc_opts = {
144
189
  ...positionToAlignmentAndOffset(pos),
145
190
  font_size: this.opts.font_size, halo: halo,
146
191
  text_color: color, halo_color: halo_color,
192
+ cmap: cmap
147
193
  };
148
- return await TextCollection.make(gl, text_specs, font_url, tc_opts);
194
+ sub_component_promises.push([TextCollection.make(gl, text_specs, font_url, tc_opts)]);
149
195
  }
150
196
  else if (config.type == 'barb') {
151
197
  const comp = this.field.getVector(k);
@@ -154,29 +200,49 @@ class StationPlot extends PlotComponent {
154
200
  }
155
201
  else if (config.type == 'symbol') {
156
202
  const pos = config.pos;
157
- const color = config.color === undefined ? Color.fromHex('#000000') : Color.normalizeColor(config.color);
203
+ const color = config.color === undefined ? '#000000' : config.color;
158
204
  const halo_color = config.halo_color === undefined ? Color.fromHex('#ffffff') : Color.normalizeColor(config.halo_color);
159
205
  const halo = config.halo === undefined ? true : config.halo;
160
206
  const comp = this.field.getStrings(k);
161
- const coords = this.field.grid.getEarthCoords();
162
- const zoom = this.field.grid.getMinVisibleZoom(this.opts.thin_fac);
163
207
  const wxsym_font_url = font_url_template.replace('{fontstack}', 'wx_symbols');
164
- const text_specs = comp.map((v, i) => ({ text: v === null ? '' : String.fromCharCode(SYMBOLS[v]),
165
- lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
166
- const tc_opts = {
167
- ...positionToAlignmentAndOffset(pos),
168
- font_size: this.opts.font_size, halo: halo,
169
- text_color: color, halo_color: halo_color,
170
- };
171
- if (tc_opts.offset_x !== undefined)
172
- tc_opts.offset_x -= 3;
173
- return await TextCollection.make(gl, text_specs, wxsym_font_url, tc_opts);
208
+ const text_spec_data = [];
209
+ comp.forEach((v, i) => {
210
+ const v_cat = v === null ? 'none' : symbolCategory(v);
211
+ const text_color = typeof color === 'string' ? color : color(v, v_cat);
212
+ const text_spec_data_filtered = text_spec_data.filter(tsd => tsd.color == text_color);
213
+ let text_spec_color;
214
+ if (text_spec_data_filtered.length == 0) {
215
+ text_spec_color = { specs: [], color: text_color };
216
+ text_spec_data.push(text_spec_color);
217
+ }
218
+ else {
219
+ text_spec_color = text_spec_data_filtered[0];
220
+ }
221
+ text_spec_color.specs.push({
222
+ text: v === null ? '' : String.fromCharCode(SYMBOLS[v]),
223
+ lat: coords.lats[i],
224
+ lon: coords.lons[i],
225
+ min_zoom: zoom[i],
226
+ });
227
+ });
228
+ const promises = [];
229
+ text_spec_data.forEach(tsd => {
230
+ const tc_opts = {
231
+ ...positionToAlignmentAndOffset(pos),
232
+ font_size: this.opts.font_size, halo: halo,
233
+ text_color: Color.normalizeColor(tsd.color), halo_color: halo_color,
234
+ };
235
+ if (tc_opts.offset_x !== undefined)
236
+ tc_opts.offset_x -= 3;
237
+ promises.push(TextCollection.make(gl, tsd.specs, wxsym_font_url, tc_opts));
238
+ });
239
+ sub_component_promises.push(promises);
174
240
  }
175
241
  else {
176
242
  throw `Unknown station plot configuration type ${config.type}`;
177
243
  }
178
244
  });
179
- this.text_components = (await Promise.all(sub_component_promises)).filter((c) => c !== undefined);
245
+ this.text_components = await Promise.all(sub_component_promises.map(p => Promise.all(p)));
180
246
  map.triggerRepaint();
181
247
  }
182
248
  /** @internal */
@@ -209,12 +275,12 @@ class StationPlot extends PlotComponent {
209
275
  const map_height = gl_elems.map.getCanvas().height;
210
276
  const map_zoom = gl_elems.map.getZoom();
211
277
  let itext = 0, ibarb = 0;
212
- Object.values(this.opts.config).forEach(comp => {
278
+ Object.values(this.opts.config).forEach((comp, idx) => {
213
279
  if (comp.type == 'barb') {
214
280
  barb_components[ibarb++].render(gl, arg);
215
281
  }
216
282
  else {
217
- text_components[itext++].render(gl, arg, [map_width, map_height], map_zoom);
283
+ text_components[itext++].forEach(tc => tc.render(gl, arg, [map_width, map_height], map_zoom));
218
284
  }
219
285
  });
220
286
  }
@@ -1,5 +1,6 @@
1
1
  import { RenderMethodArg, WebGLAnyRenderingContext } from "./AutumnTypes";
2
2
  import { Color } from "./Color";
3
+ import { ColorMap, ColorMapGPUInterface } from "./Colormap";
3
4
  import { ShaderProgramManager } from "./ShaderManager";
4
5
  import { WGLBuffer, WGLTexture } from "autumn-wgl";
5
6
  interface TextSpec {
@@ -7,6 +8,7 @@ interface TextSpec {
7
8
  lon: number;
8
9
  text: string;
9
10
  min_zoom?: number;
11
+ data_value?: number;
10
12
  }
11
13
  type HorizontalAlign = 'left' | 'center' | 'right';
12
14
  type VerticalAlign = 'baseline' | 'middle' | 'top';
@@ -15,6 +17,7 @@ interface TextCollectionOptions {
15
17
  vertical_align?: VerticalAlign;
16
18
  font_size?: number;
17
19
  text_color?: Color;
20
+ cmap?: ColorMap | null;
18
21
  halo_color?: Color;
19
22
  halo?: boolean;
20
23
  offset_x?: number;
@@ -25,7 +28,9 @@ declare class TextCollection {
25
28
  readonly anchors: WGLBuffer;
26
29
  readonly offsets: WGLBuffer;
27
30
  readonly texcoords: WGLBuffer;
31
+ readonly data: WGLBuffer | null;
28
32
  readonly texture: WGLTexture;
33
+ readonly cmap_gpu: ColorMapGPUInterface | null;
29
34
  readonly opts: Required<TextCollectionOptions>;
30
35
  private constructor();
31
36
  static make(gl: WebGLAnyRenderingContext, text_locs: TextSpec[], fontstack_url_template: string, opts?: TextCollectionOptions): Promise<TextCollection>;
@@ -1,5 +1,6 @@
1
1
  import { getRendererData, isWebGL2Ctx } from "./AutumnTypes";
2
2
  import { Color } from "./Color";
3
+ import { ColorMap, ColorMapGPUInterface } from "./Colormap";
3
4
  import { LngLat } from "./Map";
4
5
  import { ShaderProgramManager } from "./ShaderManager";
5
6
  import { Cache, normalizeOptions } from "./utils";
@@ -18,8 +19,16 @@ in vec3 a_pos;
18
19
  in vec2 a_offset;
19
20
  in vec2 a_tex_coord;
20
21
 
22
+ #ifdef DATA
23
+ in highp float a_value;
24
+ #endif
25
+
21
26
  out highp vec2 v_tex_coord;
22
27
 
28
+ #ifdef DATA
29
+ out highp float v_value;
30
+ #endif
31
+
23
32
  mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
24
33
  return mat4(x_scale, 0.0, 0.0, 0.0,
25
34
  0.0, y_scale, 0.0, 0.0,
@@ -41,14 +50,25 @@ void main() {
41
50
 
42
51
  gl_Position = projectTile(a_pos.xy + globe_offset) + u_font_size / 12. * 1.5 * map_stretch_matrix * vec4(offset, 0., 0.);
43
52
  v_tex_coord = a_tex_coord;
53
+
54
+ #ifdef DATA
55
+ v_value = a_value;
56
+ #endif
44
57
  }`
45
58
  const text_fragment_shader_src = `#version 300 es
46
59
 
47
60
  in highp vec2 v_tex_coord;
61
+
62
+ #ifdef DATA
63
+ in highp float v_value;
64
+ #endif
65
+
48
66
  uniform sampler2D u_sdf_sampler;
49
67
  uniform int u_is_halo;
50
68
 
69
+ #ifndef DATA
51
70
  uniform lowp vec4 u_text_color;
71
+ #endif
52
72
  uniform lowp vec4 u_halo_color;
53
73
 
54
74
  #define SDF_FILL 0.75
@@ -62,7 +82,13 @@ void main() {
62
82
  lowp float step_width = 0.08;
63
83
  lowp float alpha = smoothstep(SDF_FILL - step_width, SDF_FILL + step_width, sdf_val);
64
84
 
65
- lowp vec4 color = u_is_halo == 1 ? u_halo_color : u_text_color;
85
+ #ifdef DATA
86
+ lowp vec4 text_color = apply_colormap(v_value);
87
+ #else
88
+ lowp vec4 text_color = u_text_color;
89
+ #endif
90
+
91
+ lowp vec4 color = u_is_halo == 1 ? u_halo_color : text_color;
66
92
 
67
93
  if (u_is_halo == 1) {
68
94
  alpha = min(smoothstep(SDF_HALO - step_width, SDF_HALO + step_width, sdf_val), 1.0 - alpha);
@@ -171,6 +197,7 @@ const text_collection_opt_defaults = {
171
197
  vertical_align: 'baseline',
172
198
  font_size: 12,
173
199
  text_color: new Color([0, 0, 0, 1]),
200
+ cmap: null,
174
201
  halo_color: new Color([0, 0, 0, 1]),
175
202
  halo: false,
176
203
  offset_x: 0,
@@ -179,6 +206,7 @@ const text_collection_opt_defaults = {
179
206
  class TextCollection {
180
207
  constructor(gl, text_locs, font_atlas, opts) {
181
208
  this.opts = normalizeOptions(opts, text_collection_opt_defaults);
209
+ const text_color_hex = this.opts.text_color === undefined ? new Color([0, 0, 0, 1]) : this.opts.text_color;
182
210
  const is_webgl2 = isWebGL2Ctx(gl);
183
211
  const format = is_webgl2 ? gl.R8 : gl.LUMINANCE;
184
212
  const type = gl.UNSIGNED_BYTE;
@@ -196,11 +224,15 @@ class TextCollection {
196
224
  const anchor_data = new Float32Array(n_verts * 3);
197
225
  const offset_data = new Float32Array(n_verts * 2);
198
226
  const tc_data = new Float32Array(n_verts * 2);
199
- let i_anch = 0, i_off = 0, i_tc = 0;
227
+ const value_data = new Float32Array(n_verts);
228
+ let i_anch = 0, i_off = 0, i_tc = 0, i_dat = 0;
229
+ let has_data = false;
200
230
  text_locs.forEach(loc => {
201
231
  const { lat, lon, text } = loc;
202
232
  const min_zoom = loc.min_zoom === undefined ? 0 : loc.min_zoom;
233
+ const data_value = loc.data_value === undefined ? NaN : loc.data_value;
203
234
  const { x: anchor_x, y: anchor_y } = new LngLat(lon, lat).toMercatorCoord();
235
+ has_data = has_data || loc.data_value !== undefined;
204
236
  let x_offset = this.opts.offset_x;
205
237
  let y_offset = this.opts.offset_y;
206
238
  const init_i_off = i_off;
@@ -254,6 +286,12 @@ class TextCollection {
254
286
  tc_data[i_tc++] = glyph_info.atlas_j / font_atlas.atlas_height;
255
287
  tc_data[i_tc++] = (glyph_info.atlas_i + glyph_info.width) / font_atlas.atlas_width;
256
288
  tc_data[i_tc++] = glyph_info.atlas_j / font_atlas.atlas_height;
289
+ value_data[i_dat++] = data_value;
290
+ value_data[i_dat++] = data_value;
291
+ value_data[i_dat++] = data_value;
292
+ value_data[i_dat++] = data_value;
293
+ value_data[i_dat++] = data_value;
294
+ value_data[i_dat++] = data_value;
257
295
  x_offset += glyph_info.advance - glyph_info.left;
258
296
  }
259
297
  if (this.opts.horizontal_align == 'center') {
@@ -277,18 +315,40 @@ class TextCollection {
277
315
  }
278
316
  }
279
317
  });
280
- this.shader_manager = new ShaderProgramManager(text_vertex_shader_src, text_fragment_shader_src, []);
318
+ const shader_defines = [];
319
+ let fragment_src = text_fragment_shader_src;
320
+ if (has_data) {
321
+ shader_defines.push('DATA');
322
+ this.data = new WGLBuffer(gl, value_data, 1, gl.TRIANGLE_STRIP);
323
+ const cmap = this.opts.cmap === null ? new ColorMap([0, 1], [text_color_hex], { overflow_color: text_color_hex, underflow_color: text_color_hex }) : this.opts.cmap;
324
+ this.cmap_gpu = new ColorMapGPUInterface(cmap);
325
+ this.cmap_gpu.setupShaderVariables(gl, gl.NEAREST);
326
+ fragment_src = ColorMapGPUInterface.applyShader(fragment_src);
327
+ }
328
+ else {
329
+ this.data = null;
330
+ this.cmap_gpu = null;
331
+ }
332
+ this.shader_manager = new ShaderProgramManager(text_vertex_shader_src, fragment_src, shader_defines);
281
333
  this.anchors = new WGLBuffer(gl, anchor_data, 3, gl.TRIANGLE_STRIP);
282
334
  this.offsets = new WGLBuffer(gl, offset_data, 2, gl.TRIANGLE_STRIP);
283
335
  this.texcoords = new WGLBuffer(gl, tc_data, 2, gl.TRIANGLE_STRIP);
336
+ this.data = has_data ? new WGLBuffer(gl, value_data, 1, gl.TRIANGLE_STRIP) : null;
284
337
  }
285
338
  static async make(gl, text_locs, fontstack_url_template, opts) {
286
339
  const FONT_GROUP_SIZE = 256;
287
340
  const characters = text_locs.map(tl => [...tl.text]).flat().map(c => c.charCodeAt(0)).filter((c, i, ary) => ary.indexOf(c) == i);
288
- const char_code_min = Math.min(...characters);
289
- const char_code_max = Math.max(...characters);
290
- const stack_start = Math.floor(char_code_min / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
291
- const stack_end = Math.floor(char_code_max / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
341
+ let stack_start, stack_end;
342
+ if (characters.length > 0) {
343
+ const char_code_min = Math.min(...characters);
344
+ const char_code_max = Math.max(...characters);
345
+ stack_start = Math.floor(char_code_min / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
346
+ stack_end = Math.floor(char_code_max / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
347
+ }
348
+ else {
349
+ stack_start = 0;
350
+ stack_end = 0;
351
+ }
292
352
  const fontstack_urls = [];
293
353
  for (let istack = stack_start; istack <= stack_end; istack += FONT_GROUP_SIZE) {
294
354
  fontstack_urls.push(fontstack_url_template.replace('{range}', `${istack}-${istack + FONT_GROUP_SIZE - 1}`));
@@ -301,13 +361,23 @@ class TextCollection {
301
361
  render(gl, arg, [map_width, map_height], map_zoom) {
302
362
  const render_data = getRendererData(arg);
303
363
  const program = this.shader_manager.getShaderProgram(gl, render_data.shaderData);
364
+ const attributes = { 'a_pos': this.anchors, 'a_offset': this.offsets, 'a_tex_coord': this.texcoords };
304
365
  const uniforms = {
305
366
  'u_map_width': map_width, 'u_map_height': map_height, 'u_map_zoom': map_zoom, 'u_font_size': this.opts.font_size,
306
- 'u_text_color': this.opts.text_color.toRGBATuple(), 'u_halo_color': this.opts.halo_color.toRGBATuple(), 'u_offset': 0,
367
+ 'u_halo_color': this.opts.halo_color.toRGBATuple(), 'u_offset': 0,
307
368
  ...this.shader_manager.getShaderUniforms(render_data)
308
369
  };
370
+ if (this.data !== null) {
371
+ attributes['a_value'] = this.data;
372
+ }
373
+ else {
374
+ uniforms['u_text_color'] = this.opts.text_color.toRGBATuple();
375
+ }
309
376
  uniforms['u_is_halo'] = this.opts.halo ? 1 : 0;
310
- program.use({ 'a_pos': this.anchors, 'a_offset': this.offsets, 'a_tex_coord': this.texcoords }, uniforms, { 'u_sdf_sampler': this.texture });
377
+ program.use(attributes, uniforms, { 'u_sdf_sampler': this.texture });
378
+ if (this.cmap_gpu !== null) {
379
+ this.cmap_gpu.bindShaderVariables(program);
380
+ }
311
381
  gl.enable(gl.BLEND);
312
382
  gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
313
383
  program.draw();
@@ -0,0 +1,7 @@
1
+ import { MarchingSquaresModule } from './cpp/marchingsquares';
2
+ import './cpp/marchingsquares.wasm';
3
+ interface InitMSModuleOpts {
4
+ document_script?: string;
5
+ }
6
+ declare function initMSModule(opts: InitMSModuleOpts): Promise<MarchingSquaresModule>;
7
+ export { initMSModule };
@@ -0,0 +1,11 @@
1
+ // Should rename this eventually
2
+ import Module from './cpp/marchingsquares';
3
+ import './cpp/marchingsquares.wasm';
4
+ let msm_promise = null;
5
+ function initMSModule(opts) {
6
+ if (msm_promise === null) {
7
+ msm_promise = Module({ 'locateFile': (fname, dir) => (opts.document_script === undefined ? dir : opts.document_script) + fname });
8
+ }
9
+ return msm_promise;
10
+ }
11
+ export { initMSModule };
@@ -0,0 +1,8 @@
1
+ import * as Comlink from 'comlink';
2
+ type Promisify<T> = (T extends (...args: infer TArguments) => infer TReturn ? (...args: TArguments) => Promise<TReturn> : unknown);
3
+ type WorkerPool<T> = {
4
+ [K in keyof T]: Promisify<T[K]>;
5
+ };
6
+ declare function createWorkerPool<T>(workers: Worker[], init?: (wkr: Comlink.Remote<T>) => void): WorkerPool<T>;
7
+ export { createWorkerPool };
8
+ export type { WorkerPool };
@@ -0,0 +1,77 @@
1
+ import * as Comlink from 'comlink';
2
+ class WorkerPool_ {
3
+ constructor(workers, init) {
4
+ this.workers = workers.map(wkr => ({ worker: Comlink.wrap(wkr), is_busy: false }));
5
+ if (init) {
6
+ this.workers.forEach(wkr => init(wkr.worker));
7
+ }
8
+ this.queue = new Map();
9
+ }
10
+ call(path, args, callback) {
11
+ const worker_idx = this.workers.map(((w, iw) => [w, iw])).filter(([w, iw]) => !w.is_busy)[0];
12
+ if (worker_idx === undefined) {
13
+ this.enqueue(path, args, callback);
14
+ }
15
+ else {
16
+ const [worker, iw] = worker_idx;
17
+ const dequeueAndStart = () => {
18
+ if (this.queueSize(path) > 0) {
19
+ const queue_data = this.dequeue(path);
20
+ if (queue_data === undefined)
21
+ return;
22
+ this.startRun(worker, path, queue_data.args).then(queue_data.callback).then(dequeueAndStart);
23
+ }
24
+ };
25
+ this.startRun(worker, path, args).then(callback).then(dequeueAndStart);
26
+ }
27
+ }
28
+ enqueue(path, args, callback) {
29
+ const path_str = path.join(".");
30
+ const old_queue = this.queue.get(path_str);
31
+ const new_queue = old_queue ? old_queue : [];
32
+ new_queue.push({ args: args, callback: callback });
33
+ this.queue.set(path_str, new_queue);
34
+ }
35
+ dequeue(path) {
36
+ const path_str = path.join(".");
37
+ const queue = this.queue.get(path_str);
38
+ if (!queue) {
39
+ return undefined;
40
+ }
41
+ const elem = queue.shift();
42
+ this.queue.set(path_str, queue);
43
+ return elem;
44
+ }
45
+ queueSize(path) {
46
+ const path_str = path.join(".");
47
+ const queue = this.queue.get(path_str);
48
+ if (!queue) {
49
+ return 0;
50
+ }
51
+ return queue.length;
52
+ }
53
+ async startRun(worker, path, args) {
54
+ let rem = worker.worker;
55
+ path.forEach(p => rem = rem[p]);
56
+ worker.is_busy = true;
57
+ const ret = await rem(...args);
58
+ worker.is_busy = false;
59
+ return ret;
60
+ }
61
+ }
62
+ function createProxy(pool, path, target) {
63
+ const proxy = new Proxy(target, {
64
+ get(tgt, prop) {
65
+ return createProxy(pool, [...path, prop], () => { });
66
+ },
67
+ apply(tgt, this_arg, func_args) {
68
+ return new Promise((resolve, reject) => pool.call(path, func_args, resolve));
69
+ }
70
+ });
71
+ return proxy;
72
+ }
73
+ function createWorkerPool(workers, init) {
74
+ const pool = new WorkerPool_(workers, init);
75
+ return createProxy(pool, [], () => { });
76
+ }
77
+ export { createWorkerPool };