autumnplot-gl 2.2.3 → 3.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 (49) hide show
  1. package/README.md +65 -8
  2. package/dist/110.autumnplot-gl.js +2 -0
  3. package/dist/110.autumnplot-gl.js.map +1 -0
  4. package/dist/autumnplot-gl.js +3 -0
  5. package/dist/autumnplot-gl.js.LICENSE.txt +12 -0
  6. package/dist/autumnplot-gl.js.map +1 -0
  7. package/dist/marchingsquares.wasm +0 -0
  8. package/lib/AutumnTypes.d.ts +14 -13
  9. package/lib/Barbs.d.ts +10 -5
  10. package/lib/Barbs.js +22 -5
  11. package/lib/BillboardCollection.d.ts +11 -7
  12. package/lib/BillboardCollection.js +52 -30
  13. package/lib/ColorBar.js +51 -7
  14. package/lib/Colormap.d.ts +14 -3
  15. package/lib/Colormap.js +63 -12
  16. package/lib/Contour.d.ts +73 -18
  17. package/lib/Contour.js +180 -148
  18. package/lib/ContourCreator.d.ts +18 -0
  19. package/lib/ContourCreator.js +23 -0
  20. package/lib/Fill.d.ts +18 -7
  21. package/lib/Fill.js +73 -41
  22. package/lib/Grid.d.ts +167 -0
  23. package/lib/Grid.js +339 -0
  24. package/lib/Hodographs.d.ts +13 -6
  25. package/lib/Hodographs.js +58 -71
  26. package/lib/Map.d.ts +14 -3
  27. package/lib/Map.js +9 -0
  28. package/lib/Paintball.d.ts +11 -5
  29. package/lib/Paintball.js +35 -15
  30. package/lib/PlotComponent.d.ts +5 -5
  31. package/lib/PlotLayer.d.ts +12 -12
  32. package/lib/PlotLayer.js +16 -14
  33. package/lib/PlotLayer.worker.d.ts +2 -2
  34. package/lib/PlotLayer.worker.js +105 -66
  35. package/lib/PolylineCollection.d.ts +20 -9
  36. package/lib/PolylineCollection.js +158 -32
  37. package/lib/RawField.d.ts +11 -167
  38. package/lib/RawField.js +37 -383
  39. package/lib/TextCollection.d.ts +31 -0
  40. package/lib/TextCollection.js +295 -0
  41. package/lib/cpp/marchingsquares.d.ts +6 -0
  42. package/lib/cpp/marchingsquares.js +3449 -0
  43. package/lib/cpp/marchingsquares.wasm +0 -0
  44. package/lib/cpp/marchingsquares_embind.d.ts +6 -0
  45. package/lib/index.d.ts +13 -6
  46. package/lib/index.js +12 -3
  47. package/lib/utils.d.ts +5 -3
  48. package/lib/utils.js +17 -6
  49. package/package.json +14 -9
@@ -0,0 +1,295 @@
1
+ import { isWebGL2Ctx } from "./AutumnTypes";
2
+ import { LngLat } from "./Map";
3
+ import { Cache, normalizeOptions } from "./utils";
4
+ import { WGLBuffer, WGLProgram, WGLTexture } from "autumn-wgl";
5
+ import Protobuf from 'pbf';
6
+ import potpack from "potpack";
7
+ const text_vertex_shader_src = `
8
+ uniform mat4 u_matrix;
9
+ uniform int u_offset;
10
+ uniform highp float u_map_width;
11
+ uniform highp float u_map_height;
12
+ uniform highp float u_map_zoom;
13
+ uniform highp float u_font_size;
14
+
15
+ attribute vec3 a_pos;
16
+ attribute vec2 a_offset;
17
+ attribute vec2 a_tex_coord;
18
+
19
+ varying highp vec2 v_tex_coord;
20
+
21
+ mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
22
+ return mat4(x_scale, 0.0, 0.0, 0.0,
23
+ 0.0, y_scale, 0.0, 0.0,
24
+ 0.0, 0.0, z_scale, 0.0,
25
+ 0.0, 0.0, 0.0, 1.0);
26
+ }
27
+
28
+ void main() {
29
+ float min_zoom = a_pos.z;
30
+
31
+ vec2 offset = a_offset;
32
+ if (u_map_zoom < min_zoom)
33
+ offset = vec2(0., 0.);
34
+
35
+ float globe_width = 1.;
36
+ vec2 globe_offset = vec2(globe_width * float(u_offset), 0.);
37
+
38
+ mat4 map_stretch_matrix = scalingMatrix(u_map_height / u_map_width, 1., 1.);
39
+
40
+ gl_Position = u_matrix * vec4(a_pos.xy + globe_offset, 0.0, 1.0) + u_font_size / 12. * 1.5 * map_stretch_matrix * vec4(offset, 0., 0.);
41
+ v_tex_coord = a_tex_coord;
42
+ }`
43
+ const text_fragment_shader_src = `
44
+ varying highp vec2 v_tex_coord;
45
+ uniform sampler2D u_sdf_sampler;
46
+ uniform int u_is_halo;
47
+
48
+ uniform lowp vec3 u_text_color;
49
+ uniform lowp vec3 u_halo_color;
50
+
51
+ #define SDF_FILL 0.75
52
+ #define SDF_HALO 0.45
53
+
54
+ void main() {
55
+ highp float sdf_val = texture2D(u_sdf_sampler, v_tex_coord).r;
56
+
57
+ lowp float step_width = 0.08;
58
+ lowp float alpha = smoothstep(SDF_FILL - step_width, SDF_FILL + step_width, sdf_val);
59
+
60
+ lowp vec3 color = u_is_halo == 1 ? u_halo_color : u_text_color;
61
+
62
+ if (u_is_halo == 1) {
63
+ alpha = min(smoothstep(SDF_HALO - step_width, SDF_HALO + step_width, sdf_val), 1.0 - alpha);
64
+ }
65
+
66
+ gl_FragColor = vec4(color, alpha);
67
+ }`
68
+ const program_cache = new Cache((gl) => new WGLProgram(gl, text_vertex_shader_src, text_fragment_shader_src));
69
+ const PADDING = 3;
70
+ function parseFontPBF(data) {
71
+ const readGlyph = (tag, glyph, pbf) => {
72
+ switch (tag) {
73
+ case 1:
74
+ glyph.id = pbf.readVarint();
75
+ break;
76
+ case 2:
77
+ glyph.data = pbf.readBytes();
78
+ break;
79
+ case 3:
80
+ glyph.width = pbf.readVarint() + 2 * PADDING;
81
+ break;
82
+ case 4:
83
+ glyph.height = pbf.readVarint() + 2 * PADDING;
84
+ break;
85
+ case 5:
86
+ glyph.left = pbf.readSVarint();
87
+ break;
88
+ case 6:
89
+ glyph.top = pbf.readSVarint();
90
+ break;
91
+ case 7:
92
+ glyph.advance = pbf.readVarint();
93
+ break;
94
+ }
95
+ };
96
+ const readFontStack = (tag, glyphs, pbf) => {
97
+ if (tag == 3) {
98
+ const glyph = pbf.readMessage(readGlyph, {});
99
+ glyphs.push(glyph);
100
+ }
101
+ };
102
+ const readFontStacks = (tag, glyphs, pbf) => {
103
+ if (tag == 1) {
104
+ pbf.readMessage(readFontStack, glyphs);
105
+ }
106
+ };
107
+ return new Protobuf(data).readFields(readFontStacks, []);
108
+ }
109
+ function createAtlas(pbf_glyphs) {
110
+ const pbf_glyphs_filtered = pbf_glyphs.filter(glyph => glyph.data !== undefined);
111
+ const glyph_bins = [];
112
+ const bins = pbf_glyphs_filtered.map(glyph => {
113
+ const bin = { x: 0, y: 0, w: glyph.width, h: glyph.height };
114
+ glyph_bins.push({ glyph: glyph, bin: bin });
115
+ return bin;
116
+ });
117
+ const { w: img_width, h: img_height } = potpack(bins);
118
+ const atlas_data = new Uint8Array(img_width * img_height);
119
+ const glyphs = {};
120
+ glyph_bins.forEach(glyph_bin => {
121
+ const { bin, glyph } = glyph_bin;
122
+ glyphs[glyph.id] = {
123
+ id: glyph.id, width: glyph.width, height: glyph.height, left: glyph.left, top: glyph.top,
124
+ atlas_i: bin.x, atlas_j: bin.y, advance: glyph.advance
125
+ };
126
+ for (let i = 0; i < glyph.width; i++) {
127
+ for (let j = 0; j < glyph.height; j++) {
128
+ const glyph_idx = i + glyph.width * j;
129
+ const atlas_idx = (i + bin.x) + img_width * (j + bin.y);
130
+ atlas_data[atlas_idx] = glyph.data[glyph_idx];
131
+ }
132
+ }
133
+ });
134
+ const glyph_M = glyphs['M'.charCodeAt(0)];
135
+ const baseline = glyph_M.height - glyph_M.top;
136
+ const top = -glyph_M.top;
137
+ return { atlas: atlas_data, atlas_width: img_width, atlas_height: img_height, baseline: baseline, top: top, glyph_info: glyphs };
138
+ }
139
+ async function getFontAtlas(url) {
140
+ const resp = await fetch(url);
141
+ const blob = await resp.blob();
142
+ const data_buffer = await blob.arrayBuffer();
143
+ // Parse the PBF and get the glyph data
144
+ const glyphs = parseFontPBF(new Uint8Array(data_buffer));
145
+ // Create an atlas for the glyphs
146
+ return createAtlas(glyphs);
147
+ }
148
+ const text_collection_opt_defaults = {
149
+ horizontal_align: 'left',
150
+ vertical_align: 'baseline',
151
+ font_size: 12,
152
+ text_color: [0, 0, 0],
153
+ halo_color: [0, 0, 0],
154
+ halo: false
155
+ };
156
+ class TextCollection {
157
+ constructor(gl, text_locs, font_atlas, opts) {
158
+ this.program = program_cache.getValue(gl);
159
+ this.opts = normalizeOptions(opts, text_collection_opt_defaults);
160
+ const is_webgl2 = isWebGL2Ctx(gl);
161
+ const format = is_webgl2 ? gl.R8 : gl.LUMINANCE;
162
+ const type = gl.UNSIGNED_BYTE;
163
+ const row_alignment = 1;
164
+ const image = {
165
+ 'format': format, 'type': type, 'width': font_atlas.atlas_width, 'height': font_atlas.atlas_height,
166
+ 'image': font_atlas.atlas, 'row_alignment': row_alignment, 'mag_filter': gl.LINEAR
167
+ };
168
+ this.texture = new WGLTexture(gl, image);
169
+ const n_verts = text_locs.map(tl => tl.text.length).reduce((a, b) => a + b, 0) * 6;
170
+ const anchor_data = new Float32Array(n_verts * 3);
171
+ const offset_data = new Float32Array(n_verts * 2);
172
+ const tc_data = new Float32Array(n_verts * 2);
173
+ let i_anch = 0, i_off = 0, i_tc = 0;
174
+ text_locs.forEach(loc => {
175
+ const { lat, lon, text } = loc;
176
+ const min_zoom = loc.min_zoom === undefined ? 0 : loc.min_zoom;
177
+ const { x: anchor_x, y: anchor_y } = new LngLat(lon, lat).toMercatorCoord();
178
+ let x_offset = 0;
179
+ const init_i_off = i_off;
180
+ for (let i = 0; i < text.length; i++) {
181
+ const glyph_code = text.charCodeAt(i);
182
+ const glyph_info = font_atlas.glyph_info[glyph_code];
183
+ if (glyph_info === undefined) {
184
+ x_offset += 7;
185
+ continue;
186
+ }
187
+ x_offset += glyph_info.left;
188
+ anchor_data[i_anch++] = anchor_x;
189
+ anchor_data[i_anch++] = anchor_y;
190
+ anchor_data[i_anch++] = min_zoom;
191
+ anchor_data[i_anch++] = anchor_x;
192
+ anchor_data[i_anch++] = anchor_y;
193
+ anchor_data[i_anch++] = min_zoom;
194
+ anchor_data[i_anch++] = anchor_x;
195
+ anchor_data[i_anch++] = anchor_y;
196
+ anchor_data[i_anch++] = min_zoom;
197
+ anchor_data[i_anch++] = anchor_x;
198
+ anchor_data[i_anch++] = anchor_y;
199
+ anchor_data[i_anch++] = min_zoom;
200
+ anchor_data[i_anch++] = anchor_x;
201
+ anchor_data[i_anch++] = anchor_y;
202
+ anchor_data[i_anch++] = min_zoom;
203
+ anchor_data[i_anch++] = anchor_x;
204
+ anchor_data[i_anch++] = anchor_y;
205
+ anchor_data[i_anch++] = min_zoom;
206
+ offset_data[i_off++] = x_offset;
207
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
208
+ offset_data[i_off++] = x_offset;
209
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
210
+ offset_data[i_off++] = x_offset + glyph_info.width;
211
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
212
+ offset_data[i_off++] = x_offset;
213
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
214
+ offset_data[i_off++] = x_offset + glyph_info.width;
215
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
216
+ offset_data[i_off++] = x_offset + glyph_info.width;
217
+ offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
218
+ tc_data[i_tc++] = glyph_info.atlas_i / font_atlas.atlas_width;
219
+ tc_data[i_tc++] = (glyph_info.atlas_j + glyph_info.height) / font_atlas.atlas_height;
220
+ tc_data[i_tc++] = glyph_info.atlas_i / font_atlas.atlas_width;
221
+ tc_data[i_tc++] = (glyph_info.atlas_j + glyph_info.height) / font_atlas.atlas_height;
222
+ tc_data[i_tc++] = (glyph_info.atlas_i + glyph_info.width) / font_atlas.atlas_width;
223
+ tc_data[i_tc++] = (glyph_info.atlas_j + glyph_info.height) / font_atlas.atlas_height;
224
+ tc_data[i_tc++] = glyph_info.atlas_i / font_atlas.atlas_width;
225
+ tc_data[i_tc++] = glyph_info.atlas_j / font_atlas.atlas_height;
226
+ tc_data[i_tc++] = (glyph_info.atlas_i + glyph_info.width) / font_atlas.atlas_width;
227
+ tc_data[i_tc++] = glyph_info.atlas_j / font_atlas.atlas_height;
228
+ tc_data[i_tc++] = (glyph_info.atlas_i + glyph_info.width) / font_atlas.atlas_width;
229
+ tc_data[i_tc++] = glyph_info.atlas_j / font_atlas.atlas_height;
230
+ x_offset += glyph_info.advance - glyph_info.left;
231
+ }
232
+ if (opts.horizontal_align == 'center') {
233
+ for (let i = init_i_off; i < init_i_off + text.length * 12; i += 2) {
234
+ offset_data[i] -= x_offset / 2;
235
+ }
236
+ }
237
+ else if (opts.horizontal_align == 'right') {
238
+ for (let i = init_i_off; i < init_i_off + text.length * 12; i += 2) {
239
+ offset_data[i] -= x_offset;
240
+ }
241
+ }
242
+ if (opts.vertical_align == 'top') {
243
+ for (let i = init_i_off + 1; i < init_i_off + text.length * 12; i += 2) {
244
+ offset_data[i] -= (font_atlas.baseline - font_atlas.top);
245
+ }
246
+ }
247
+ else if (opts.vertical_align == 'middle') {
248
+ for (let i = init_i_off + 1; i < init_i_off + text.length * 12; i += 2) {
249
+ offset_data[i] -= (font_atlas.baseline - font_atlas.top) / 2;
250
+ }
251
+ }
252
+ });
253
+ this.anchors = new WGLBuffer(gl, anchor_data, 3, gl.TRIANGLE_STRIP);
254
+ this.offsets = new WGLBuffer(gl, offset_data, 2, gl.TRIANGLE_STRIP);
255
+ this.texcoords = new WGLBuffer(gl, tc_data, 2, gl.TRIANGLE_STRIP);
256
+ }
257
+ static async make(gl, text_locs, fontstack_url, opts) {
258
+ const atlas = await getFontAtlas(fontstack_url);
259
+ return new TextCollection(gl, text_locs, atlas, opts);
260
+ }
261
+ render(gl, matrix, [map_width, map_height], map_zoom) {
262
+ const uniforms = {
263
+ 'u_matrix': matrix, 'u_map_width': map_width, 'u_map_height': map_height, 'u_map_zoom': map_zoom, 'u_font_size': this.opts.font_size,
264
+ 'u_text_color': this.opts.text_color, 'u_halo_color': this.opts.halo_color, 'u_offset': 0
265
+ };
266
+ uniforms['u_is_halo'] = this.opts.halo ? 1 : 0;
267
+ this.program.use({ 'a_pos': this.anchors, 'a_offset': this.offsets, 'a_tex_coord': this.texcoords }, uniforms, { 'u_sdf_sampler': this.texture });
268
+ gl.enable(gl.BLEND);
269
+ gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
270
+ this.program.draw();
271
+ if (this.opts.halo) {
272
+ this.program.setUniforms({ 'u_is_halo': 0 });
273
+ this.program.draw();
274
+ }
275
+ this.program.setUniforms({ 'u_offset': -2, 'u_is_halo': this.opts.halo ? 1 : 0 });
276
+ this.program.draw();
277
+ if (this.opts.halo) {
278
+ this.program.setUniforms({ 'u_is_halo': 0 });
279
+ this.program.draw();
280
+ }
281
+ this.program.setUniforms({ 'u_offset': -1, 'u_is_halo': this.opts.halo ? 1 : 0 });
282
+ this.program.draw();
283
+ if (this.opts.halo) {
284
+ this.program.setUniforms({ 'u_is_halo': 0 });
285
+ this.program.draw();
286
+ }
287
+ this.program.setUniforms({ 'u_offset': 1, 'u_is_halo': this.opts.halo ? 1 : 0 });
288
+ this.program.draw();
289
+ if (this.opts.halo) {
290
+ this.program.setUniforms({ 'u_is_halo': 0 });
291
+ this.program.draw();
292
+ }
293
+ }
294
+ }
295
+ export { TextCollection };
@@ -0,0 +1,6 @@
1
+ import { type MainModule } from "./marchingsquares_embind";
2
+
3
+ export type MarchingSquaresModule = MainModule & EmscriptenModule;
4
+
5
+ declare const Module: EmscriptenModuleFactory<MarchingSquaresModule>;
6
+ export default Module;