autumnplot-gl 3.2.0 → 4.0.0-beta
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/lib/AutumnTypes.d.ts +53 -5
- package/lib/AutumnTypes.js +25 -1
- package/lib/Barbs.d.ts +6 -5
- package/lib/BillboardCollection.d.ts +8 -7
- package/lib/BillboardCollection.js +69 -58
- package/lib/Color.d.ts +1 -0
- package/lib/Color.js +3 -0
- package/lib/ColorBar.d.ts +10 -0
- package/lib/ColorBar.js +4 -2
- package/lib/Colormap.js +8 -8
- package/lib/Contour.d.ts +18 -8
- package/lib/Contour.js +17 -54
- package/lib/ContourCreator.d.ts +4 -0
- package/lib/ContourCreator.js +2 -1
- package/lib/Fill.d.ts +26 -14
- package/lib/Fill.js +97 -50
- package/lib/Grid.d.ts +124 -29
- package/lib/Grid.js +297 -94
- package/lib/Hodographs.d.ts +9 -8
- package/lib/Hodographs.js +14 -11
- package/lib/Map.js +1 -1
- package/lib/Paintball.d.ts +6 -5
- package/lib/Paintball.js +35 -30
- package/lib/ParticleTracer.d.ts +19 -0
- package/lib/ParticleTracer.js +37 -0
- package/lib/PlotComponent.d.ts +6 -7
- package/lib/PlotComponent.js +8 -3
- package/lib/PlotLayer.d.ts +3 -3
- package/lib/PlotLayer.worker.d.ts +1 -2
- package/lib/PlotLayer.worker.js +15 -50
- package/lib/PolylineCollection.d.ts +5 -3
- package/lib/PolylineCollection.js +60 -37
- package/lib/RawField.d.ts +76 -23
- package/lib/RawField.js +138 -29
- package/lib/ShaderManager.d.ts +12 -0
- package/lib/ShaderManager.js +58 -0
- package/lib/StationPlot.d.ts +136 -25
- package/lib/StationPlot.js +192 -60
- package/lib/TextCollection.d.ts +9 -6
- package/lib/TextCollection.js +94 -62
- package/lib/cpp/marchingsquares.js +483 -585
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +23 -3
- package/lib/index.d.ts +4 -3
- package/lib/index.js +4 -3
- package/lib/utils.d.ts +4 -1
- package/lib/utils.js +12 -1
- package/package.json +2 -2
package/lib/TextCollection.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import { isWebGL2Ctx } from "./AutumnTypes";
|
|
1
|
+
import { getRendererData, isWebGL2Ctx } from "./AutumnTypes";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
3
|
import { LngLat } from "./Map";
|
|
4
|
+
import { ShaderProgramManager } from "./ShaderManager";
|
|
4
5
|
import { Cache, normalizeOptions } from "./utils";
|
|
5
|
-
import { WGLBuffer,
|
|
6
|
+
import { WGLBuffer, WGLTexture } from "autumn-wgl";
|
|
6
7
|
import Protobuf from 'pbf';
|
|
7
8
|
import potpack from "potpack";
|
|
8
|
-
const text_vertex_shader_src =
|
|
9
|
-
|
|
9
|
+
const text_vertex_shader_src = `#version 300 es
|
|
10
|
+
|
|
10
11
|
uniform int u_offset;
|
|
11
12
|
uniform highp float u_map_width;
|
|
12
13
|
uniform highp float u_map_height;
|
|
13
14
|
uniform highp float u_map_zoom;
|
|
14
15
|
uniform highp float u_font_size;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
in vec3 a_pos;
|
|
18
|
+
in vec2 a_offset;
|
|
19
|
+
in vec2 a_tex_coord;
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
out highp vec2 v_tex_coord;
|
|
21
22
|
|
|
22
23
|
mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
|
|
23
24
|
return mat4(x_scale, 0.0, 0.0, 0.0,
|
|
@@ -38,11 +39,12 @@ void main() {
|
|
|
38
39
|
|
|
39
40
|
mat4 map_stretch_matrix = scalingMatrix(u_map_height / u_map_width, 1., 1.);
|
|
40
41
|
|
|
41
|
-
gl_Position =
|
|
42
|
+
gl_Position = projectTile(a_pos.xy + globe_offset) + u_font_size / 12. * 1.5 * map_stretch_matrix * vec4(offset, 0., 0.);
|
|
42
43
|
v_tex_coord = a_tex_coord;
|
|
43
44
|
}`
|
|
44
|
-
const text_fragment_shader_src =
|
|
45
|
-
|
|
45
|
+
const text_fragment_shader_src = `#version 300 es
|
|
46
|
+
|
|
47
|
+
in highp vec2 v_tex_coord;
|
|
46
48
|
uniform sampler2D u_sdf_sampler;
|
|
47
49
|
uniform int u_is_halo;
|
|
48
50
|
|
|
@@ -52,8 +54,10 @@ uniform lowp vec4 u_halo_color;
|
|
|
52
54
|
#define SDF_FILL 0.75
|
|
53
55
|
#define SDF_HALO 0.45
|
|
54
56
|
|
|
57
|
+
out highp vec4 fragColor;
|
|
58
|
+
|
|
55
59
|
void main() {
|
|
56
|
-
highp float sdf_val =
|
|
60
|
+
highp float sdf_val = texture(u_sdf_sampler, v_tex_coord).r;
|
|
57
61
|
|
|
58
62
|
lowp float step_width = 0.08;
|
|
59
63
|
lowp float alpha = smoothstep(SDF_FILL - step_width, SDF_FILL + step_width, sdf_val);
|
|
@@ -65,9 +69,8 @@ void main() {
|
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
color.a *= alpha;
|
|
68
|
-
|
|
72
|
+
fragColor = color;
|
|
69
73
|
}`
|
|
70
|
-
const program_cache = new Cache((gl) => new WGLProgram(gl, text_vertex_shader_src, text_fragment_shader_src));
|
|
71
74
|
const PADDING = 3;
|
|
72
75
|
function parseFontPBF(data) {
|
|
73
76
|
const readGlyph = (tag, glyph, pbf) => {
|
|
@@ -125,6 +128,7 @@ function createAtlas(pbf_glyphs) {
|
|
|
125
128
|
const { w: img_width, h: img_height } = potpack(bins);
|
|
126
129
|
const atlas_data = new Uint8Array(img_width * img_height);
|
|
127
130
|
const glyphs = {};
|
|
131
|
+
let max_glyph_height = 0;
|
|
128
132
|
glyph_bins.forEach(glyph_bin => {
|
|
129
133
|
const { bin, glyph } = glyph_bin;
|
|
130
134
|
if (bin.x === undefined || bin.y === undefined)
|
|
@@ -133,6 +137,7 @@ function createAtlas(pbf_glyphs) {
|
|
|
133
137
|
id: glyph.id, width: glyph.width, height: glyph.height, left: glyph.left, top: glyph.top,
|
|
134
138
|
atlas_i: bin.x, atlas_j: bin.y, advance: glyph.advance
|
|
135
139
|
};
|
|
140
|
+
max_glyph_height = Math.max(max_glyph_height, glyph.height);
|
|
136
141
|
for (let i = 0; i < glyph.width; i++) {
|
|
137
142
|
for (let j = 0; j < glyph.height; j++) {
|
|
138
143
|
const glyph_idx = i + glyph.width * j;
|
|
@@ -142,38 +147,46 @@ function createAtlas(pbf_glyphs) {
|
|
|
142
147
|
}
|
|
143
148
|
});
|
|
144
149
|
const glyph_M = glyphs['M'.charCodeAt(0)];
|
|
145
|
-
const baseline = glyph_M.height - glyph_M.top;
|
|
146
|
-
const top = -glyph_M.top;
|
|
150
|
+
const baseline = glyph_M === undefined ? max_glyph_height : glyph_M.height - glyph_M.top;
|
|
151
|
+
const top = glyph_M === undefined ? 0 : -glyph_M.top;
|
|
147
152
|
return { atlas: atlas_data, atlas_width: img_width, atlas_height: img_height, baseline: baseline, top: top, glyph_info: glyphs };
|
|
148
153
|
}
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
const FONT_ATLAS_CACHE = new Cache(async (urls) => {
|
|
155
|
+
const promises = urls.map(async (url) => {
|
|
156
|
+
const resp = await fetch(url);
|
|
157
|
+
const blob = await resp.blob();
|
|
158
|
+
const data_buffer = await blob.arrayBuffer();
|
|
159
|
+
// Parse the PBF and get the glyph data
|
|
160
|
+
return parseFontPBF(new Uint8Array(data_buffer));
|
|
161
|
+
});
|
|
162
|
+
const glyphs = (await Promise.all(promises)).flat();
|
|
155
163
|
// Create an atlas for the glyphs
|
|
156
164
|
return createAtlas(glyphs);
|
|
157
|
-
}
|
|
165
|
+
});
|
|
158
166
|
const text_collection_opt_defaults = {
|
|
159
167
|
horizontal_align: 'left',
|
|
160
168
|
vertical_align: 'baseline',
|
|
161
169
|
font_size: 12,
|
|
162
170
|
text_color: new Color([0, 0, 0, 1]),
|
|
163
171
|
halo_color: new Color([0, 0, 0, 1]),
|
|
164
|
-
halo: false
|
|
172
|
+
halo: false,
|
|
173
|
+
offset_x: 0,
|
|
174
|
+
offset_y: 0
|
|
165
175
|
};
|
|
166
176
|
class TextCollection {
|
|
167
177
|
constructor(gl, text_locs, font_atlas, opts) {
|
|
168
|
-
this.program = program_cache.getValue(gl);
|
|
169
178
|
this.opts = normalizeOptions(opts, text_collection_opt_defaults);
|
|
170
179
|
const is_webgl2 = isWebGL2Ctx(gl);
|
|
171
180
|
const format = is_webgl2 ? gl.R8 : gl.LUMINANCE;
|
|
172
181
|
const type = gl.UNSIGNED_BYTE;
|
|
173
182
|
const row_alignment = 1;
|
|
183
|
+
const empty_atlas = font_atlas.atlas_width == 0 || font_atlas.atlas_height == 0 || font_atlas.atlas.length == 0;
|
|
184
|
+
const atlas_width = empty_atlas ? 1 : font_atlas.atlas_width;
|
|
185
|
+
const atlas_height = empty_atlas ? 1 : font_atlas.atlas_height;
|
|
186
|
+
const atlas_data = empty_atlas ? new Uint8Array([0, 0, 0, 0]) : font_atlas.atlas;
|
|
174
187
|
const image = {
|
|
175
|
-
'format': format, 'type': type, 'width':
|
|
176
|
-
'image':
|
|
188
|
+
'format': format, 'type': type, 'width': atlas_width, 'height': atlas_height,
|
|
189
|
+
'image': atlas_data, 'row_alignment': row_alignment, 'mag_filter': gl.LINEAR
|
|
177
190
|
};
|
|
178
191
|
this.texture = new WGLTexture(gl, image);
|
|
179
192
|
const n_verts = text_locs.map(tl => tl.text.length).reduce((a, b) => a + b, 0) * 6;
|
|
@@ -185,7 +198,8 @@ class TextCollection {
|
|
|
185
198
|
const { lat, lon, text } = loc;
|
|
186
199
|
const min_zoom = loc.min_zoom === undefined ? 0 : loc.min_zoom;
|
|
187
200
|
const { x: anchor_x, y: anchor_y } = new LngLat(lon, lat).toMercatorCoord();
|
|
188
|
-
let x_offset =
|
|
201
|
+
let x_offset = this.opts.offset_x;
|
|
202
|
+
let y_offset = this.opts.offset_y;
|
|
189
203
|
const init_i_off = i_off;
|
|
190
204
|
for (let i = 0; i < text.length; i++) {
|
|
191
205
|
const glyph_code = text.charCodeAt(i);
|
|
@@ -214,17 +228,17 @@ class TextCollection {
|
|
|
214
228
|
anchor_data[i_anch++] = anchor_y;
|
|
215
229
|
anchor_data[i_anch++] = min_zoom;
|
|
216
230
|
offset_data[i_off++] = x_offset;
|
|
217
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
231
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
218
232
|
offset_data[i_off++] = x_offset;
|
|
219
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
233
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
220
234
|
offset_data[i_off++] = x_offset + glyph_info.width;
|
|
221
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
235
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top - glyph_info.height;
|
|
222
236
|
offset_data[i_off++] = x_offset;
|
|
223
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
|
|
237
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top;
|
|
224
238
|
offset_data[i_off++] = x_offset + glyph_info.width;
|
|
225
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
|
|
239
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top;
|
|
226
240
|
offset_data[i_off++] = x_offset + glyph_info.width;
|
|
227
|
-
offset_data[i_off++] = font_atlas.baseline + glyph_info.top;
|
|
241
|
+
offset_data[i_off++] = y_offset + font_atlas.baseline + glyph_info.top;
|
|
228
242
|
tc_data[i_tc++] = glyph_info.atlas_i / font_atlas.atlas_width;
|
|
229
243
|
tc_data[i_tc++] = (glyph_info.atlas_j + glyph_info.height) / font_atlas.atlas_height;
|
|
230
244
|
tc_data[i_tc++] = glyph_info.atlas_i / font_atlas.atlas_width;
|
|
@@ -241,12 +255,12 @@ class TextCollection {
|
|
|
241
255
|
}
|
|
242
256
|
if (this.opts.horizontal_align == 'center') {
|
|
243
257
|
for (let i = init_i_off; i < init_i_off + text.length * 12; i += 2) {
|
|
244
|
-
offset_data[i] -= x_offset / 2;
|
|
258
|
+
offset_data[i] -= (x_offset - this.opts.offset_x) / 2;
|
|
245
259
|
}
|
|
246
260
|
}
|
|
247
261
|
else if (this.opts.horizontal_align == 'right') {
|
|
248
262
|
for (let i = init_i_off; i < init_i_off + text.length * 12; i += 2) {
|
|
249
|
-
offset_data[i] -= x_offset;
|
|
263
|
+
offset_data[i] -= (x_offset - this.opts.offset_x);
|
|
250
264
|
}
|
|
251
265
|
}
|
|
252
266
|
if (this.opts.vertical_align == 'top') {
|
|
@@ -260,45 +274,63 @@ class TextCollection {
|
|
|
260
274
|
}
|
|
261
275
|
}
|
|
262
276
|
});
|
|
277
|
+
this.shader_manager = new ShaderProgramManager(text_vertex_shader_src, text_fragment_shader_src, []);
|
|
263
278
|
this.anchors = new WGLBuffer(gl, anchor_data, 3, gl.TRIANGLE_STRIP);
|
|
264
279
|
this.offsets = new WGLBuffer(gl, offset_data, 2, gl.TRIANGLE_STRIP);
|
|
265
280
|
this.texcoords = new WGLBuffer(gl, tc_data, 2, gl.TRIANGLE_STRIP);
|
|
266
281
|
}
|
|
267
|
-
static async make(gl, text_locs,
|
|
268
|
-
const
|
|
282
|
+
static async make(gl, text_locs, fontstack_url_template, opts) {
|
|
283
|
+
const FONT_GROUP_SIZE = 256;
|
|
284
|
+
const characters = text_locs.map(tl => [...tl.text]).flat().map(c => c.charCodeAt(0)).filter((c, i, ary) => ary.indexOf(c) == i);
|
|
285
|
+
const char_code_min = Math.min(...characters);
|
|
286
|
+
const char_code_max = Math.max(...characters);
|
|
287
|
+
const stack_start = Math.floor(char_code_min / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
|
|
288
|
+
const stack_end = Math.floor(char_code_max / FONT_GROUP_SIZE) * FONT_GROUP_SIZE;
|
|
289
|
+
const fontstack_urls = [];
|
|
290
|
+
for (let istack = stack_start; istack <= stack_end; istack += FONT_GROUP_SIZE) {
|
|
291
|
+
fontstack_urls.push(fontstack_url_template.replace('{range}', `${istack}-${istack + FONT_GROUP_SIZE - 1}`));
|
|
292
|
+
}
|
|
293
|
+
const atlas = await FONT_ATLAS_CACHE.getValue(fontstack_urls);
|
|
294
|
+
if (atlas.atlas_height == 0 || atlas.atlas_width == 0 || atlas.atlas.length == 0)
|
|
295
|
+
console.warn(`No font data from '${fontstack_url_template}'`);
|
|
269
296
|
return new TextCollection(gl, text_locs, atlas, opts);
|
|
270
297
|
}
|
|
271
|
-
render(gl,
|
|
298
|
+
render(gl, arg, [map_width, map_height], map_zoom) {
|
|
299
|
+
const render_data = getRendererData(arg);
|
|
300
|
+
const program = this.shader_manager.getShaderProgram(gl, render_data.shaderData);
|
|
272
301
|
const uniforms = {
|
|
273
|
-
'
|
|
274
|
-
'u_text_color': this.opts.text_color.toRGBATuple(), 'u_halo_color': this.opts.halo_color.toRGBATuple(), 'u_offset': 0
|
|
302
|
+
'u_map_width': map_width, 'u_map_height': map_height, 'u_map_zoom': map_zoom, 'u_font_size': this.opts.font_size,
|
|
303
|
+
'u_text_color': this.opts.text_color.toRGBATuple(), 'u_halo_color': this.opts.halo_color.toRGBATuple(), 'u_offset': 0,
|
|
304
|
+
...this.shader_manager.getShaderUniforms(render_data)
|
|
275
305
|
};
|
|
276
306
|
uniforms['u_is_halo'] = this.opts.halo ? 1 : 0;
|
|
277
|
-
|
|
307
|
+
program.use({ 'a_pos': this.anchors, 'a_offset': this.offsets, 'a_tex_coord': this.texcoords }, uniforms, { 'u_sdf_sampler': this.texture });
|
|
278
308
|
gl.enable(gl.BLEND);
|
|
279
309
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
280
|
-
|
|
281
|
-
if (this.opts.halo) {
|
|
282
|
-
this.program.setUniforms({ 'u_is_halo': 0 });
|
|
283
|
-
this.program.draw();
|
|
284
|
-
}
|
|
285
|
-
this.program.setUniforms({ 'u_offset': -2, 'u_is_halo': this.opts.halo ? 1 : 0 });
|
|
286
|
-
this.program.draw();
|
|
287
|
-
if (this.opts.halo) {
|
|
288
|
-
this.program.setUniforms({ 'u_is_halo': 0 });
|
|
289
|
-
this.program.draw();
|
|
290
|
-
}
|
|
291
|
-
this.program.setUniforms({ 'u_offset': -1, 'u_is_halo': this.opts.halo ? 1 : 0 });
|
|
292
|
-
this.program.draw();
|
|
310
|
+
program.draw();
|
|
293
311
|
if (this.opts.halo) {
|
|
294
|
-
|
|
295
|
-
|
|
312
|
+
program.setUniforms({ 'u_is_halo': 0 });
|
|
313
|
+
program.draw();
|
|
296
314
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.
|
|
301
|
-
|
|
315
|
+
if (render_data.type != 'maplibre' || !render_data.shaderData.define.includes('GLOBE')) {
|
|
316
|
+
program.setUniforms({ 'u_offset': -2, 'u_is_halo': this.opts.halo ? 1 : 0 });
|
|
317
|
+
program.draw();
|
|
318
|
+
if (this.opts.halo) {
|
|
319
|
+
program.setUniforms({ 'u_is_halo': 0 });
|
|
320
|
+
program.draw();
|
|
321
|
+
}
|
|
322
|
+
program.setUniforms({ 'u_offset': -1, 'u_is_halo': this.opts.halo ? 1 : 0 });
|
|
323
|
+
program.draw();
|
|
324
|
+
if (this.opts.halo) {
|
|
325
|
+
program.setUniforms({ 'u_is_halo': 0 });
|
|
326
|
+
program.draw();
|
|
327
|
+
}
|
|
328
|
+
program.setUniforms({ 'u_offset': 1, 'u_is_halo': this.opts.halo ? 1 : 0 });
|
|
329
|
+
program.draw();
|
|
330
|
+
if (this.opts.halo) {
|
|
331
|
+
program.setUniforms({ 'u_is_halo': 0 });
|
|
332
|
+
program.draw();
|
|
333
|
+
}
|
|
302
334
|
}
|
|
303
335
|
}
|
|
304
336
|
}
|