autumnplot-gl 2.2.3 → 3.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 +65 -8
- package/dist/110.autumnplot-gl.js +2 -0
- package/dist/110.autumnplot-gl.js.map +1 -0
- package/dist/autumnplot-gl.js +3 -0
- package/dist/autumnplot-gl.js.LICENSE.txt +12 -0
- package/dist/autumnplot-gl.js.map +1 -0
- package/dist/marchingsquares.wasm +0 -0
- package/lib/AutumnTypes.d.ts +14 -13
- package/lib/Barbs.d.ts +8 -3
- package/lib/Barbs.js +14 -1
- package/lib/BillboardCollection.d.ts +11 -7
- package/lib/BillboardCollection.js +52 -30
- package/lib/ColorBar.js +51 -7
- package/lib/Colormap.d.ts +14 -3
- package/lib/Colormap.js +63 -12
- package/lib/Contour.d.ts +73 -16
- package/lib/Contour.js +175 -146
- package/lib/ContourCreator.d.ts +18 -0
- package/lib/ContourCreator.js +59 -0
- package/lib/Fill.d.ts +17 -5
- package/lib/Fill.js +60 -37
- package/lib/Grid.d.ts +167 -0
- package/lib/Grid.js +339 -0
- package/lib/Hodographs.d.ts +13 -5
- package/lib/Hodographs.js +52 -67
- package/lib/Map.d.ts +14 -3
- package/lib/Map.js +9 -0
- package/lib/Paintball.d.ts +9 -3
- package/lib/Paintball.js +28 -10
- package/lib/PlotComponent.d.ts +5 -5
- package/lib/PlotLayer.d.ts +12 -12
- package/lib/PlotLayer.js +16 -14
- package/lib/PlotLayer.worker.d.ts +2 -2
- package/lib/PlotLayer.worker.js +102 -66
- package/lib/PolylineCollection.d.ts +20 -9
- package/lib/PolylineCollection.js +158 -32
- package/lib/RawField.d.ts +11 -167
- package/lib/RawField.js +37 -383
- package/lib/TextCollection.d.ts +31 -0
- package/lib/TextCollection.js +295 -0
- package/lib/cpp/marchingsquares.d.ts +6 -0
- package/lib/cpp/marchingsquares.js +4152 -0
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +47 -0
- package/lib/index.d.ts +13 -6
- package/lib/index.js +12 -3
- package/lib/utils.d.ts +5 -3
- package/lib/utils.js +17 -6
- package/package.json +14 -9
package/lib/Hodographs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/// <reference types="mapbox-gl" />
|
|
2
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
|
+
import { MapLikeType } from "./Map";
|
|
3
3
|
import { RawProfileField } from "./RawField";
|
|
4
4
|
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
5
5
|
interface HodographOptions {
|
|
@@ -15,22 +15,30 @@ interface HodographOptions {
|
|
|
15
15
|
thin_fac?: number;
|
|
16
16
|
}
|
|
17
17
|
/** A class representing a a field of hodograph plots */
|
|
18
|
-
declare class Hodographs extends PlotComponent {
|
|
19
|
-
private
|
|
20
|
-
readonly bgcolor:
|
|
18
|
+
declare class Hodographs<MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
19
|
+
private profile_field;
|
|
20
|
+
readonly bgcolor: string;
|
|
21
21
|
readonly thin_fac: number;
|
|
22
22
|
private gl_elems;
|
|
23
|
+
private line_elems;
|
|
24
|
+
private readonly hodo_scale;
|
|
25
|
+
private readonly bg_size;
|
|
23
26
|
/**
|
|
24
27
|
* Create a field of hodographs
|
|
25
28
|
* @param profile_field - The grid of profiles to plot
|
|
26
29
|
* @param opts - Various options to use when creating the hodographs
|
|
27
30
|
*/
|
|
28
31
|
constructor(profile_field: RawProfileField, opts?: HodographOptions);
|
|
32
|
+
/**
|
|
33
|
+
* Update the profiles displayed
|
|
34
|
+
* @param field - The new profiles to display as hodographs
|
|
35
|
+
*/
|
|
36
|
+
updateField(field: RawProfileField): Promise<void>;
|
|
29
37
|
/**
|
|
30
38
|
* @internal
|
|
31
39
|
* Add the hodographs to a map
|
|
32
40
|
*/
|
|
33
|
-
onAdd(map:
|
|
41
|
+
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
34
42
|
/**
|
|
35
43
|
* @internal
|
|
36
44
|
* Render the hodographs
|
package/lib/Hodographs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PlotComponent
|
|
1
|
+
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import { PolylineCollection } from "./PolylineCollection";
|
|
3
3
|
import { BillboardCollection } from "./BillboardCollection";
|
|
4
|
-
import { getMinZoom,
|
|
5
|
-
import {
|
|
4
|
+
import { getMinZoom, hex2rgb } from './utils';
|
|
5
|
+
import { ColorMap } from "./Colormap";
|
|
6
6
|
const LINE_WIDTH = 4;
|
|
7
7
|
const BG_MAX_RING_MAG = 40;
|
|
8
8
|
const HODO_BG_DIMS = {
|
|
@@ -40,28 +40,7 @@ function _createHodoBackgroundTexture() {
|
|
|
40
40
|
}
|
|
41
41
|
;
|
|
42
42
|
let HODO_BG_TEXTURE = null;
|
|
43
|
-
const
|
|
44
|
-
{ 'bounds': [0, 1], 'color': '#ffffcc' },
|
|
45
|
-
{ 'bounds': [1, 3], 'color': '#a1dab4' },
|
|
46
|
-
{ 'bounds': [3, 6], 'color': '#41b6c4' },
|
|
47
|
-
{ 'bounds': [6, 9], 'color': '#225ea8' }
|
|
48
|
-
];
|
|
49
|
-
function _createHodoHeightTexture() {
|
|
50
|
-
let canvas = document.createElement('canvas');
|
|
51
|
-
canvas.width = Math.max(...HODO_COLORS.map(s => Math.max(...s['bounds'])));
|
|
52
|
-
canvas.height = 1;
|
|
53
|
-
let ctx = canvas.getContext('2d');
|
|
54
|
-
HODO_COLORS.forEach(stop => {
|
|
55
|
-
if (ctx === null) {
|
|
56
|
-
throw "Could not get rendering context for the hodograph height texture canvas";
|
|
57
|
-
}
|
|
58
|
-
const [clb, cub] = stop['bounds'];
|
|
59
|
-
ctx.fillStyle = stop['color'];
|
|
60
|
-
ctx.fillRect(clb, 0, cub - clb, 1);
|
|
61
|
-
});
|
|
62
|
-
return canvas;
|
|
63
|
-
}
|
|
64
|
-
let HODO_HEIGHT_TEXTURE = null;
|
|
43
|
+
const HODO_CMAP = new ColorMap([0, 1, 3, 6, 9], ['#ffffcc', '#a1dab4', '#41b6c4', '#225ea8']);
|
|
65
44
|
/** A class representing a a field of hodograph plots */
|
|
66
45
|
class Hodographs extends PlotComponent {
|
|
67
46
|
/**
|
|
@@ -73,79 +52,85 @@ class Hodographs extends PlotComponent {
|
|
|
73
52
|
super();
|
|
74
53
|
opts = opts || {};
|
|
75
54
|
this.profile_field = profile_field;
|
|
76
|
-
|
|
77
|
-
this.bgcolor = [color[0], color[1], color[2]];
|
|
55
|
+
this.bgcolor = opts.bgcolor || '#000000';
|
|
78
56
|
this.thin_fac = opts.thin_fac || 1;
|
|
57
|
+
this.hodo_scale = (HODO_BG_DIMS.BB_TEX_WIDTH - LINE_WIDTH / 2) / (HODO_BG_DIMS.BB_TEX_WIDTH * BG_MAX_RING_MAG);
|
|
58
|
+
this.bg_size = 140;
|
|
79
59
|
this.gl_elems = null;
|
|
60
|
+
this.line_elems = null;
|
|
80
61
|
}
|
|
81
62
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
63
|
+
* Update the profiles displayed
|
|
64
|
+
* @param field - The new profiles to display as hodographs
|
|
84
65
|
*/
|
|
85
|
-
async
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const hodo_polyline = await layer_worker.makePolyLines(this.profile_field.profiles.map(prof => {
|
|
95
|
-
const pt_ll = new LngLat(prof['lon'], prof['lat']).toMercatorCoord();
|
|
66
|
+
async updateField(field) {
|
|
67
|
+
this.profile_field = field;
|
|
68
|
+
if (this.gl_elems === null)
|
|
69
|
+
return;
|
|
70
|
+
// XXX: This might leak VRAM
|
|
71
|
+
const gl = this.gl_elems.gl;
|
|
72
|
+
this.gl_elems.bg_billboard.updateField(field.getStormMotionGrid());
|
|
73
|
+
const profiles = this.profile_field.profiles;
|
|
74
|
+
const hodo_polyline = profiles.map(prof => {
|
|
96
75
|
const zoom = getMinZoom(prof['jlat'], prof['ilon'], this.thin_fac);
|
|
97
|
-
const max_tex_z = Math.max(...HODO_COLORS.map(s => Math.max(...s['bounds'])));
|
|
98
76
|
return {
|
|
99
|
-
'
|
|
100
|
-
'
|
|
77
|
+
'offsets': [...prof['u']].map((u, ipt) => [u - prof['smu'], prof['v'][ipt] - prof['smv']]),
|
|
78
|
+
'vertices': [...prof['u']].map(u => [prof['lon'], prof['lat']]),
|
|
101
79
|
'zoom': zoom,
|
|
102
|
-
'
|
|
80
|
+
'data': [...prof['z']],
|
|
103
81
|
};
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
const height_image = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': HODO_HEIGHT_TEXTURE, 'mag_filter': gl.NEAREST };
|
|
109
|
-
const hodo_line = new PolylineCollection(gl, hodo_polyline, height_image, 1.5, hodo_scale * bg_size);
|
|
110
|
-
const sm_polyline = await layer_worker.makePolyLines(this.profile_field.profiles.map(prof => {
|
|
111
|
-
const pt_ll = new LngLat(prof['lon'], prof['lat']).toMercatorCoord();
|
|
112
|
-
let ret = {};
|
|
82
|
+
});
|
|
83
|
+
const hodo_line = await PolylineCollection.make(gl, hodo_polyline, { line_width: 2.5, cmap: HODO_CMAP, offset_scale: this.hodo_scale * this.bg_size });
|
|
84
|
+
const sm_polyline = profiles.map(prof => {
|
|
113
85
|
const zoom = getMinZoom(prof['jlat'], prof['ilon'], this.thin_fac);
|
|
114
86
|
const sm_mag = Math.hypot(prof['smu'], prof['smv']);
|
|
115
87
|
const sm_ang = Math.PI / 2 - Math.atan2(-prof['smv'], -prof['smu']);
|
|
116
88
|
const buffer = 2;
|
|
117
89
|
return {
|
|
118
|
-
'
|
|
90
|
+
'offsets': [[buffer * Math.sin(sm_ang), buffer * Math.cos(sm_ang)],
|
|
119
91
|
[sm_mag * Math.sin(sm_ang), sm_mag * Math.cos(sm_ang)]],
|
|
120
|
-
'
|
|
121
|
-
'zoom': zoom
|
|
122
|
-
'texcoords': [[0.5, 0.5], [0.5, 0.5]]
|
|
92
|
+
'vertices': [[prof['lon'], prof['lat']], [prof['lon'], prof['lat']]],
|
|
93
|
+
'zoom': zoom
|
|
123
94
|
};
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
95
|
+
});
|
|
96
|
+
const sm_line = await PolylineCollection.make(gl, sm_polyline, { line_width: 1.5, color: this.bgcolor, offset_scale: this.hodo_scale * this.bg_size });
|
|
97
|
+
this.line_elems = {
|
|
98
|
+
hodo_line: hodo_line, sm_line: sm_line
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* @internal
|
|
103
|
+
* Add the hodographs to a map
|
|
104
|
+
*/
|
|
105
|
+
async onAdd(map, gl) {
|
|
106
|
+
if (HODO_BG_TEXTURE === null) {
|
|
107
|
+
HODO_BG_TEXTURE = _createHodoBackgroundTexture();
|
|
108
|
+
}
|
|
109
|
+
const bg_image = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': HODO_BG_TEXTURE, 'mag_filter': gl.NEAREST };
|
|
110
|
+
const max_zoom = map.getMaxZoom();
|
|
111
|
+
const bg_billboard = new BillboardCollection(this.profile_field.getStormMotionGrid(), this.thin_fac, max_zoom, bg_image, HODO_BG_DIMS, hex2rgb(this.bgcolor), this.bg_size * 0.004);
|
|
112
|
+
await bg_billboard.setup(gl);
|
|
130
113
|
this.gl_elems = {
|
|
131
|
-
map: map, bg_billboard: bg_billboard
|
|
114
|
+
gl: gl, map: map, bg_billboard: bg_billboard
|
|
132
115
|
};
|
|
116
|
+
this.updateField(this.profile_field);
|
|
133
117
|
}
|
|
134
118
|
/**
|
|
135
119
|
* @internal
|
|
136
120
|
* Render the hodographs
|
|
137
121
|
*/
|
|
138
122
|
render(gl, matrix) {
|
|
139
|
-
if (this.gl_elems === null)
|
|
123
|
+
if (this.gl_elems === null || this.line_elems === null)
|
|
140
124
|
return;
|
|
141
125
|
const gl_elems = this.gl_elems;
|
|
126
|
+
const line_elems = this.line_elems;
|
|
142
127
|
const zoom = gl_elems.map.getZoom();
|
|
143
128
|
const map_width = gl_elems.map.getCanvas().width;
|
|
144
129
|
const map_height = gl_elems.map.getCanvas().height;
|
|
145
130
|
const bearing = gl_elems.map.getBearing();
|
|
146
131
|
const pitch = gl_elems.map.getPitch();
|
|
147
|
-
|
|
148
|
-
|
|
132
|
+
line_elems.hodo_line.render(gl, matrix, [map_width, map_height], zoom, bearing, pitch);
|
|
133
|
+
line_elems.sm_line.render(gl, matrix, [map_width, map_height], zoom, bearing, bearing);
|
|
149
134
|
gl_elems.bg_billboard.render(gl, matrix, [map_width, map_height], zoom, bearing, pitch);
|
|
150
135
|
}
|
|
151
136
|
}
|
package/lib/Map.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type StyleSpecification = {
|
|
2
|
+
glyphs?: string;
|
|
3
|
+
};
|
|
4
|
+
type MapLikeType = {
|
|
5
|
+
triggerRepaint: () => void;
|
|
6
|
+
getCanvas: () => HTMLCanvasElement;
|
|
7
|
+
getStyle: () => StyleSpecification;
|
|
8
|
+
getZoom: () => number;
|
|
9
|
+
getMaxZoom: () => number;
|
|
10
|
+
getBearing: () => number;
|
|
11
|
+
getPitch: () => number;
|
|
12
|
+
};
|
|
3
13
|
interface LambertConformalConicParameters {
|
|
4
14
|
lon_0: number;
|
|
5
15
|
lat_0: number;
|
|
@@ -37,6 +47,7 @@ declare class LngLat {
|
|
|
37
47
|
x: number;
|
|
38
48
|
y: number;
|
|
39
49
|
};
|
|
50
|
+
static fromMercatorCoord(x: number, y: number): LngLat;
|
|
40
51
|
}
|
|
41
52
|
export { LngLat, lambertConformalConic, rotateSphere };
|
|
42
|
-
export type {
|
|
53
|
+
export type { MapLikeType };
|
package/lib/Map.js
CHANGED
|
@@ -124,11 +124,17 @@ function rotateSphere(params) {
|
|
|
124
124
|
function mercatorXfromLng(lng) {
|
|
125
125
|
return (180 + lng) / 360;
|
|
126
126
|
}
|
|
127
|
+
function lngFromMercatorX(x) {
|
|
128
|
+
return 360 * x - 180;
|
|
129
|
+
}
|
|
127
130
|
function mercatorYfromLat(lat) {
|
|
128
131
|
const sin_lat = Math.sin(lat * Math.PI / 180);
|
|
129
132
|
const y = (180 - (90 / Math.PI * Math.log((1 + sin_lat) / (1 - sin_lat)))) / 360;
|
|
130
133
|
return Math.min(2, Math.max(-2, y));
|
|
131
134
|
}
|
|
135
|
+
function latFromMercatorY(y) {
|
|
136
|
+
return Math.atan(Math.sinh((180 - y * 360) * Math.PI / 180)) * 180 / Math.PI;
|
|
137
|
+
}
|
|
132
138
|
/**
|
|
133
139
|
* A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.
|
|
134
140
|
* These coordinates are based on the [WGS84 (EPSG:4326) standard](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84).
|
|
@@ -156,5 +162,8 @@ class LngLat {
|
|
|
156
162
|
toMercatorCoord() {
|
|
157
163
|
return { x: mercatorXfromLng(this.lng), y: mercatorYfromLat(this.lat) };
|
|
158
164
|
}
|
|
165
|
+
static fromMercatorCoord(x, y) {
|
|
166
|
+
return new LngLat(lngFromMercatorX(x), latFromMercatorY(y));
|
|
167
|
+
}
|
|
159
168
|
}
|
|
160
169
|
export { LngLat, lambertConformalConic, rotateSphere };
|
package/lib/Paintball.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
|
-
import {
|
|
2
|
+
import { MapLikeType } from "./Map";
|
|
3
3
|
import { PlotComponent } from "./PlotComponent";
|
|
4
4
|
import { RawScalarField } from "./RawField";
|
|
5
5
|
interface PaintballOptions {
|
|
@@ -20,11 +20,12 @@ interface PaintballOptions {
|
|
|
20
20
|
* of single-precision floats, this works for up to 24 members. (Technically speaking, I don't need the quotes around "bits", as they're bits of the
|
|
21
21
|
* significand of an IEEE 754 float.)
|
|
22
22
|
*/
|
|
23
|
-
declare class Paintball<ArrayType extends TypedArray> extends PlotComponent {
|
|
24
|
-
private
|
|
23
|
+
declare class Paintball<ArrayType extends TypedArray, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
24
|
+
private field;
|
|
25
25
|
readonly colors: number[];
|
|
26
26
|
readonly opacity: number;
|
|
27
27
|
private gl_elems;
|
|
28
|
+
private fill_texture;
|
|
28
29
|
/**
|
|
29
30
|
* Create a paintball plot
|
|
30
31
|
* @param field - A scalar field containing the member objects encoded as "bits." The numerical value of each grid point can be constructed like
|
|
@@ -33,6 +34,11 @@ declare class Paintball<ArrayType extends TypedArray> extends PlotComponent {
|
|
|
33
34
|
* @param opts - Options for creating the paintball plot
|
|
34
35
|
*/
|
|
35
36
|
constructor(field: RawScalarField<ArrayType>, opts?: PaintballOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Update the field displayed as a paintball plot
|
|
39
|
+
* @param field - The new field to display as a paintball plot
|
|
40
|
+
*/
|
|
41
|
+
updateField(field: RawScalarField<ArrayType>): Promise<void>;
|
|
36
42
|
/**
|
|
37
43
|
* @internal
|
|
38
44
|
* Add the paintball plot to a map.
|
package/lib/Paintball.js
CHANGED
|
@@ -68,6 +68,30 @@ class Paintball extends PlotComponent {
|
|
|
68
68
|
this.colors = colors.reverse().map(color => hex2rgba(color)).flat();
|
|
69
69
|
this.opacity = opts.opacity !== undefined ? opts.opacity : 1.;
|
|
70
70
|
this.gl_elems = null;
|
|
71
|
+
this.fill_texture = null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Update the field displayed as a paintball plot
|
|
75
|
+
* @param field - The new field to display as a paintball plot
|
|
76
|
+
*/
|
|
77
|
+
async updateField(field) {
|
|
78
|
+
this.field = field;
|
|
79
|
+
if (this.gl_elems === null)
|
|
80
|
+
return;
|
|
81
|
+
const gl = this.gl_elems.gl;
|
|
82
|
+
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);
|
|
83
|
+
const tex_data = this.field.getTextureData();
|
|
84
|
+
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, !(tex_data instanceof Float32Array));
|
|
85
|
+
const fill_image = { 'format': format, 'type': type,
|
|
86
|
+
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': tex_data,
|
|
87
|
+
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
88
|
+
};
|
|
89
|
+
if (this.fill_texture === null) {
|
|
90
|
+
this.fill_texture = new WGLTexture(gl, fill_image);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.fill_texture.setImageData(fill_image);
|
|
94
|
+
}
|
|
71
95
|
}
|
|
72
96
|
/**
|
|
73
97
|
* @internal
|
|
@@ -79,29 +103,23 @@ class Paintball extends PlotComponent {
|
|
|
79
103
|
const { vertices: verts_buf, texcoords: tex_coords_buf } = await this.field.grid.getWGLBuffers(gl);
|
|
80
104
|
const vertices = verts_buf;
|
|
81
105
|
const texcoords = tex_coords_buf;
|
|
82
|
-
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);
|
|
83
|
-
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, this.field.isFloat16());
|
|
84
|
-
const fill_image = { 'format': format, 'type': type,
|
|
85
|
-
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.getTextureData(),
|
|
86
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
87
|
-
};
|
|
88
|
-
const fill_texture = new WGLTexture(gl, fill_image);
|
|
89
106
|
this.gl_elems = {
|
|
90
|
-
program: program, vertices: vertices,
|
|
107
|
+
gl: gl, program: program, vertices: vertices, texcoords: texcoords,
|
|
91
108
|
};
|
|
109
|
+
this.updateField(this.field);
|
|
92
110
|
}
|
|
93
111
|
/**
|
|
94
112
|
* @internal
|
|
95
113
|
* Render the paintball plot
|
|
96
114
|
*/
|
|
97
115
|
render(gl, matrix) {
|
|
98
|
-
if (this.gl_elems === null)
|
|
116
|
+
if (this.gl_elems === null || this.fill_texture === null)
|
|
99
117
|
return;
|
|
100
118
|
const gl_elems = this.gl_elems;
|
|
101
119
|
if (matrix instanceof Float32Array)
|
|
102
120
|
matrix = [...matrix];
|
|
103
121
|
// Render to framebuffer
|
|
104
|
-
gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_matrix': matrix, 'u_opacity': this.opacity, 'u_colors': this.colors, 'u_num_colors': this.colors.length / 4, 'u_offset': 0 }, { 'u_fill_sampler':
|
|
122
|
+
gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_matrix': matrix, 'u_opacity': this.opacity, 'u_colors': this.colors, 'u_num_colors': this.colors.length / 4, 'u_offset': 0 }, { 'u_fill_sampler': this.fill_texture });
|
|
105
123
|
gl.enable(gl.BLEND);
|
|
106
124
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
107
125
|
gl_elems.program.draw();
|
package/lib/PlotComponent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
|
-
import {
|
|
2
|
+
import { MapLikeType } from './Map';
|
|
3
3
|
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
4
4
|
declare const layer_worker: Comlink.Remote<{
|
|
5
5
|
makeBBElements: (field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, thin_fac_base: number, max_zoom: number) => {
|
|
@@ -11,15 +11,15 @@ declare const layer_worker: Comlink.Remote<{
|
|
|
11
11
|
tex_coords: Float32Array;
|
|
12
12
|
grid_cell_size: Float32Array;
|
|
13
13
|
};
|
|
14
|
-
makePolyLines: (lines: import("./AutumnTypes").
|
|
14
|
+
makePolyLines: (lines: import("./AutumnTypes").LineData[]) => import("./AutumnTypes").Polyline;
|
|
15
15
|
}>;
|
|
16
|
-
declare abstract class PlotComponent {
|
|
16
|
+
declare abstract class PlotComponent<MapType extends MapLikeType> {
|
|
17
17
|
abstract onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
18
18
|
abstract render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
19
19
|
}
|
|
20
20
|
declare function getGLFormatTypeAlignment(gl: WebGLAnyRenderingContext, is_float16: boolean): {
|
|
21
|
-
format:
|
|
22
|
-
type:
|
|
21
|
+
format: 33325 | 33326 | 6409;
|
|
22
|
+
type: 36193 | 5131 | 5126;
|
|
23
23
|
row_alignment: number;
|
|
24
24
|
};
|
|
25
25
|
export { PlotComponent, layer_worker, getGLFormatTypeAlignment };
|
package/lib/PlotLayer.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
2
|
-
import {
|
|
2
|
+
import { MapLikeType } from './Map';
|
|
3
3
|
import { PlotComponent } from './PlotComponent';
|
|
4
|
-
declare abstract class PlotLayerBase {
|
|
4
|
+
declare abstract class PlotLayerBase<MapType extends MapLikeType> {
|
|
5
5
|
readonly type: 'custom';
|
|
6
6
|
readonly id: string;
|
|
7
|
+
protected map: MapType;
|
|
7
8
|
constructor(id: string);
|
|
8
9
|
abstract onAdd(map: MapType, gl: WebGLAnyRenderingContext): void;
|
|
9
10
|
abstract render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
11
|
+
protected repaint(): void;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast), an {@link MultiPlotLayer}
|
|
@@ -17,19 +19,19 @@ declare abstract class PlotLayerBase {
|
|
|
17
19
|
* const wind_speed_layer = new PlotLayer('wind-speed-fill', wind_speed_fill);
|
|
18
20
|
* const barb_layer = new PlotLayer('barbs', wind_barbs);
|
|
19
21
|
*/
|
|
20
|
-
declare class PlotLayer extends PlotLayerBase {
|
|
22
|
+
declare class PlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapType> {
|
|
21
23
|
private readonly field;
|
|
22
24
|
/**
|
|
23
25
|
* Create a map layer from a field
|
|
24
26
|
* @param id - A unique id for this layer
|
|
25
27
|
* @param field - The field to plot in this layer
|
|
26
28
|
*/
|
|
27
|
-
constructor(id: string, field: PlotComponent);
|
|
29
|
+
constructor(id: string, field: PlotComponent<MapType>);
|
|
28
30
|
/**
|
|
29
31
|
* @internal
|
|
30
32
|
* Add this layer to a map
|
|
31
33
|
*/
|
|
32
|
-
onAdd(map: MapType, gl: WebGLAnyRenderingContext): void
|
|
34
|
+
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
33
35
|
/**
|
|
34
36
|
* @internal
|
|
35
37
|
* Render this layer
|
|
@@ -50,10 +52,9 @@ declare class PlotLayer extends PlotLayerBase {
|
|
|
50
52
|
* // Set the date/time in the map layer
|
|
51
53
|
* height_layer.setActiveKey('20230112_1200');
|
|
52
54
|
*/
|
|
53
|
-
declare class MultiPlotLayer extends PlotLayerBase {
|
|
55
|
+
declare class MultiPlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapType> {
|
|
54
56
|
private fields;
|
|
55
57
|
private field_key;
|
|
56
|
-
private map;
|
|
57
58
|
private gl;
|
|
58
59
|
/**
|
|
59
60
|
* Create a time-varying map layer
|
|
@@ -72,7 +73,7 @@ declare class MultiPlotLayer extends PlotLayerBase {
|
|
|
72
73
|
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
73
74
|
/**
|
|
74
75
|
* Set the active key
|
|
75
|
-
* @param key - The new key
|
|
76
|
+
* @param key - The new key. The field with that key is plotted immediately.
|
|
76
77
|
*/
|
|
77
78
|
setActiveKey(key: string): void;
|
|
78
79
|
/**
|
|
@@ -81,11 +82,10 @@ declare class MultiPlotLayer extends PlotLayerBase {
|
|
|
81
82
|
*/
|
|
82
83
|
getKeys(): string[];
|
|
83
84
|
/**
|
|
84
|
-
* Add a field
|
|
85
|
+
* Add a field with a given key
|
|
85
86
|
* @param field - The field to add
|
|
86
|
-
* @param
|
|
87
|
+
* @param key - The key to associate with the field
|
|
87
88
|
*/
|
|
88
|
-
addField(field: PlotComponent
|
|
89
|
-
private repaintIfNecessary;
|
|
89
|
+
addField(field: PlotComponent<MapType>, key: string): void;
|
|
90
90
|
}
|
|
91
91
|
export { PlotLayer, MultiPlotLayer };
|
package/lib/PlotLayer.js
CHANGED
|
@@ -2,6 +2,12 @@ class PlotLayerBase {
|
|
|
2
2
|
constructor(id) {
|
|
3
3
|
this.type = 'custom';
|
|
4
4
|
this.id = id;
|
|
5
|
+
this.map = null;
|
|
6
|
+
}
|
|
7
|
+
repaint() {
|
|
8
|
+
if (this.map !== null) {
|
|
9
|
+
this.map.triggerRepaint();
|
|
10
|
+
}
|
|
5
11
|
}
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
@@ -27,8 +33,9 @@ class PlotLayer extends PlotLayerBase {
|
|
|
27
33
|
* @internal
|
|
28
34
|
* Add this layer to a map
|
|
29
35
|
*/
|
|
30
|
-
onAdd(map, gl) {
|
|
31
|
-
this.
|
|
36
|
+
async onAdd(map, gl) {
|
|
37
|
+
this.map = map;
|
|
38
|
+
await this.field.onAdd(map, gl);
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
41
|
* @internal
|
|
@@ -73,10 +80,10 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
73
80
|
this.gl = gl;
|
|
74
81
|
Object.values(this.fields).forEach(field => {
|
|
75
82
|
field.onAdd(map, gl).then(res => {
|
|
76
|
-
this.
|
|
83
|
+
this.repaint();
|
|
77
84
|
});
|
|
78
85
|
});
|
|
79
|
-
this.
|
|
86
|
+
this.repaint();
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
82
89
|
* @internal
|
|
@@ -90,12 +97,12 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
90
97
|
}
|
|
91
98
|
/**
|
|
92
99
|
* Set the active key
|
|
93
|
-
* @param key - The new key
|
|
100
|
+
* @param key - The new key. The field with that key is plotted immediately.
|
|
94
101
|
*/
|
|
95
102
|
setActiveKey(key) {
|
|
96
103
|
const old_field_key = this.field_key;
|
|
97
104
|
this.field_key = key;
|
|
98
|
-
this.
|
|
105
|
+
this.repaint();
|
|
99
106
|
}
|
|
100
107
|
/**
|
|
101
108
|
* Get a list of all dates/times that have been added to the layer
|
|
@@ -105,15 +112,15 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
105
112
|
return Object.keys(this.fields);
|
|
106
113
|
}
|
|
107
114
|
/**
|
|
108
|
-
* Add a field
|
|
115
|
+
* Add a field with a given key
|
|
109
116
|
* @param field - The field to add
|
|
110
|
-
* @param
|
|
117
|
+
* @param key - The key to associate with the field
|
|
111
118
|
*/
|
|
112
119
|
addField(field, key) {
|
|
113
120
|
const old_field_key = this.field_key;
|
|
114
121
|
if (this.map !== null && this.gl !== null && field !== null) {
|
|
115
122
|
field.onAdd(this.map, this.gl).then(res => {
|
|
116
|
-
this.
|
|
123
|
+
this.repaint();
|
|
117
124
|
});
|
|
118
125
|
}
|
|
119
126
|
this.fields[key] = field;
|
|
@@ -121,10 +128,5 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
121
128
|
this.field_key = key;
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
|
-
repaintIfNecessary(old_field_key) {
|
|
125
|
-
if (this.map !== null && old_field_key !== this.field_key) {
|
|
126
|
-
this.map.triggerRepaint();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
131
|
}
|
|
130
132
|
export { PlotLayer, MultiPlotLayer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LineData, Polyline } from "./AutumnTypes";
|
|
2
2
|
declare function makeBBElements(field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, thin_fac_base: number, max_zoom: number): {
|
|
3
3
|
pts: Float32Array;
|
|
4
4
|
tex_coords: Float32Array;
|
|
@@ -8,7 +8,7 @@ declare function makeDomainVerticesAndTexCoords(field_lats: Float32Array, field_
|
|
|
8
8
|
tex_coords: Float32Array;
|
|
9
9
|
grid_cell_size: Float32Array;
|
|
10
10
|
};
|
|
11
|
-
declare function makePolylines(lines:
|
|
11
|
+
declare function makePolylines(lines: LineData[]): Polyline;
|
|
12
12
|
declare const ep_interface: {
|
|
13
13
|
makeBBElements: typeof makeBBElements;
|
|
14
14
|
makeDomainVerticesAndTexCoords: typeof makeDomainVerticesAndTexCoords;
|