autumnplot-gl 2.1.0 → 2.2.1
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 +11 -5
- package/lib/AutumnTypes.d.ts +3 -1
- package/lib/Barbs.d.ts +6 -12
- package/lib/BillboardCollection.d.ts +11 -11
- package/lib/BillboardCollection.js +23 -11
- package/lib/Contour.d.ts +6 -16
- package/lib/Contour.js +38 -25
- package/lib/Fill.d.ts +16 -28
- package/lib/Fill.js +35 -24
- package/lib/Hodographs.d.ts +3 -13
- package/lib/Map.d.ts +9 -1
- package/lib/Map.js +42 -2
- package/lib/Paintball.d.ts +6 -14
- package/lib/Paintball.js +24 -12
- package/lib/PlotComponent.d.ts +7 -2
- package/lib/PlotComponent.js +34 -1
- package/lib/PlotLayer.d.ts +9 -14
- package/lib/PlotLayer.js +5 -6
- package/lib/PolylineCollection.d.ts +9 -9
- package/lib/PolylineCollection.js +14 -2
- package/lib/RawField.d.ts +83 -48
- package/lib/RawField.js +176 -40
- package/lib/index.d.ts +3 -3
- package/lib/index.js +2 -2
- package/lib/utils.d.ts +8 -1
- package/lib/utils.js +33 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ npm i autumnplot-gl
|
|
|
19
19
|
Additionally, 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(...)`).
|
|
20
20
|
|
|
21
21
|
### A basic contour plot
|
|
22
|
-
The first step in plotting data is to create a grid. Currently, the only supported grids are
|
|
22
|
+
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).
|
|
23
23
|
|
|
24
24
|
```javascript
|
|
25
25
|
// Create a grid object that covers the continental United States
|
|
@@ -27,7 +27,7 @@ const nx = 121, ny = 61;
|
|
|
27
27
|
const grid = new PlateCarreeGrid(nx, ny, -130, 20, -65, 55);
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
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 in row-major order with the first element being at the southwest corner of the grid.
|
|
30
|
+
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:
|
|
31
31
|
|
|
32
32
|
```javascript
|
|
33
33
|
// Create the raw data field
|
|
@@ -81,7 +81,7 @@ map.on('load', () => {
|
|
|
81
81
|
|
|
82
82
|
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.
|
|
83
83
|
|
|
84
|
-
### Filled contours
|
|
84
|
+
### Filled contours or raster plots
|
|
85
85
|
|
|
86
86
|
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.
|
|
87
87
|
|
|
@@ -96,7 +96,13 @@ map.on('load', () => {
|
|
|
96
96
|
});
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
Making a raster plot is very similar (the two classes support the same options):
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const raster = new Raster(height, {cmap: colormap});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Normally, when you have a color fill, you have a color bar on the plot. To create an SVG color bar:
|
|
100
106
|
|
|
101
107
|
```javascript
|
|
102
108
|
const colorbar_svg = makeColorBar(colormap, {label: "Height Perturbation (m)",
|
|
@@ -154,7 +160,7 @@ The above exmple uses map tiles from [Maptiler](https://www.maptiler.com/). Map
|
|
|
154
160
|
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.
|
|
155
161
|
|
|
156
162
|
## Conspicuous absences
|
|
157
|
-
A few capabilities are missing from this library as of v2.
|
|
163
|
+
A few capabilities are missing from this library as of v2.2.
|
|
158
164
|
* Helper functions for reading from specific data formats. For instance, I'd like to add support for reading from a zarr file.
|
|
159
165
|
* A whole bunch of little things that ought to be fairly straightforward like tweaking the size of the wind barbs and contour thicknesses.
|
|
160
166
|
* Support for contour labeling. I'd like to add it, but I'm not really sure how I'd do it with the contours as I've implemented them. Any WebGL gurus, get in touch.
|
package/lib/AutumnTypes.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Float16Array } from "@petamoriken/float16";
|
|
1
2
|
interface WindProfile {
|
|
2
3
|
lat: number;
|
|
3
4
|
lon: number;
|
|
@@ -33,5 +34,6 @@ interface LineSpec {
|
|
|
33
34
|
}
|
|
34
35
|
type WebGLAnyRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;
|
|
35
36
|
declare function isWebGL2Ctx(gl: WebGLAnyRenderingContext): gl is WebGL2RenderingContext;
|
|
37
|
+
type TypedArray = Float16Array | Float32Array;
|
|
36
38
|
export { isWebGL2Ctx };
|
|
37
|
-
export type { WindProfile, BillboardSpec, PolylineSpec, LineSpec, WebGLAnyRenderingContext };
|
|
39
|
+
export type { WindProfile, BillboardSpec, PolylineSpec, LineSpec, WebGLAnyRenderingContext, TypedArray };
|
package/lib/Barbs.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
|
-
import { BillboardCollection } from './BillboardCollection';
|
|
3
2
|
import { RawVectorField } from "./RawField";
|
|
4
3
|
import { MapType } from "./Map";
|
|
5
|
-
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
4
|
+
import { TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
6
5
|
interface BarbsOptions {
|
|
7
6
|
/**
|
|
8
7
|
* The color to use for the barbs as a hex color string;.
|
|
@@ -16,10 +15,6 @@ interface BarbsOptions {
|
|
|
16
15
|
*/
|
|
17
16
|
thin_fac?: number;
|
|
18
17
|
}
|
|
19
|
-
interface BarbsGLElems {
|
|
20
|
-
map: MapType | null;
|
|
21
|
-
barb_billboards: BillboardCollection | null;
|
|
22
|
-
}
|
|
23
18
|
/**
|
|
24
19
|
* A class representing a field of wind barbs. The barbs are automatically thinned based on the zoom level on the map; the user only has to provide a
|
|
25
20
|
* thinning factor at zoom level 1.
|
|
@@ -28,19 +23,18 @@ interface BarbsGLElems {
|
|
|
28
23
|
* const vector_field = new RawVectorField(grid, u_data, v_data);
|
|
29
24
|
* const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
|
|
30
25
|
*/
|
|
31
|
-
declare class Barbs extends PlotComponent {
|
|
26
|
+
declare class Barbs<ArrayType extends TypedArray> extends PlotComponent {
|
|
32
27
|
/** The vector field */
|
|
33
|
-
readonly fields
|
|
28
|
+
private readonly fields;
|
|
34
29
|
readonly color: [number, number, number];
|
|
35
30
|
readonly thin_fac: number;
|
|
36
|
-
|
|
37
|
-
gl_elems: BarbsGLElems | null;
|
|
31
|
+
private gl_elems;
|
|
38
32
|
/**
|
|
39
33
|
* Create a field of wind barbs
|
|
40
34
|
* @param fields - The vector field to plot as barbs
|
|
41
35
|
* @param opts - Options for creating the wind barbs
|
|
42
36
|
*/
|
|
43
|
-
constructor(fields: RawVectorField
|
|
37
|
+
constructor(fields: RawVectorField<ArrayType>, opts: BarbsOptions);
|
|
44
38
|
/**
|
|
45
39
|
* @internal
|
|
46
40
|
* Add the barb field to a map
|
|
@@ -50,7 +44,7 @@ declare class Barbs extends PlotComponent {
|
|
|
50
44
|
* @internal
|
|
51
45
|
* Render the barb field
|
|
52
46
|
*/
|
|
53
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
47
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
54
48
|
}
|
|
55
49
|
export default Barbs;
|
|
56
50
|
export type { BarbsOptions };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { BillboardSpec, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { BillboardSpec, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
2
|
import { RawVectorField } from "./RawField";
|
|
3
|
-
import {
|
|
4
|
-
declare class BillboardCollection {
|
|
3
|
+
import { WGLTextureSpec } from "autumn-wgl";
|
|
4
|
+
declare class BillboardCollection<ArrayType extends TypedArray> {
|
|
5
5
|
readonly spec: BillboardSpec;
|
|
6
6
|
readonly color: [number, number, number];
|
|
7
7
|
readonly size_multiplier: number;
|
|
8
|
-
readonly program
|
|
9
|
-
vertices
|
|
10
|
-
texcoords
|
|
11
|
-
readonly texture
|
|
12
|
-
readonly u_texture
|
|
13
|
-
readonly v_texture
|
|
14
|
-
constructor(gl: WebGLAnyRenderingContext, field: RawVectorField
|
|
15
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[], [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
|
|
8
|
+
private readonly program;
|
|
9
|
+
private vertices;
|
|
10
|
+
private texcoords;
|
|
11
|
+
private readonly texture;
|
|
12
|
+
private readonly u_texture;
|
|
13
|
+
private readonly v_texture;
|
|
14
|
+
constructor(gl: WebGLAnyRenderingContext, field: RawVectorField<ArrayType>, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_color: [number, number, number], billboard_size_mult: number);
|
|
15
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array, [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
|
|
16
16
|
}
|
|
17
17
|
export { BillboardCollection };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getGLFormatTypeAlignment } from "./PlotComponent";
|
|
2
2
|
import { WGLProgram, WGLTexture } from "autumn-wgl";
|
|
3
3
|
const billboard_vertex_shader_src = `uniform mat4 u_matrix;
|
|
4
|
+
uniform int u_offset;
|
|
4
5
|
|
|
5
6
|
attribute vec3 a_pos;
|
|
6
7
|
attribute vec2 a_tex_coord;
|
|
@@ -47,7 +48,10 @@ mat4 rotationXMatrix(float angle) {
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
void main() {
|
|
50
|
-
|
|
51
|
+
float globe_width = 1.;
|
|
52
|
+
vec2 globe_offset = vec2(globe_width * float(u_offset), 0.);
|
|
53
|
+
|
|
54
|
+
vec4 pivot_pos = u_matrix * vec4(a_pos.xy + globe_offset, 0.0, 1.0);
|
|
51
55
|
highp float zoom_corner = a_pos.z;
|
|
52
56
|
lowp float min_zoom = floor(zoom_corner / 4.0);
|
|
53
57
|
lowp float corner = mod(zoom_corner, 4.0);
|
|
@@ -56,7 +60,7 @@ void main() {
|
|
|
56
60
|
highp float v = texture2D(u_v_sampler, a_tex_coord).r;
|
|
57
61
|
|
|
58
62
|
lowp float bb_aspect = u_bb_width / u_bb_height;
|
|
59
|
-
lowp float ang = atan(v, u) - 3.141592654 / 2.0;
|
|
63
|
+
lowp float ang = (abs(u) < 1e-6 && abs(v) < 1e-6) ? 0. : atan(v, u) - 3.141592654 / 2.0;
|
|
60
64
|
highp float mag = length(vec2(u, v));
|
|
61
65
|
mag = floor(mag / u_bb_mag_bin_size + 0.5) * u_bb_mag_bin_size;
|
|
62
66
|
|
|
@@ -119,14 +123,14 @@ class BillboardCollection {
|
|
|
119
123
|
this.vertices = vertices;
|
|
120
124
|
this.texcoords = texcoords;
|
|
121
125
|
})();
|
|
122
|
-
const format =
|
|
123
|
-
const u_image = { 'format': format, 'type':
|
|
124
|
-
'width': u_thin.grid.ni, 'height': u_thin.grid.nj, 'image': u_thin.
|
|
125
|
-
'mag_filter': gl.NEAREST,
|
|
126
|
+
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, u_thin.isFloat16());
|
|
127
|
+
const u_image = { 'format': format, 'type': type,
|
|
128
|
+
'width': u_thin.grid.ni, 'height': u_thin.grid.nj, 'image': u_thin.getTextureData(),
|
|
129
|
+
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
126
130
|
};
|
|
127
|
-
const v_image = { 'format': format, 'type':
|
|
128
|
-
'width': v_thin.grid.ni, 'height': v_thin.grid.nj, 'image': v_thin.
|
|
129
|
-
'mag_filter': gl.NEAREST,
|
|
131
|
+
const v_image = { 'format': format, 'type': type,
|
|
132
|
+
'width': v_thin.grid.ni, 'height': v_thin.grid.nj, 'image': v_thin.getTextureData(),
|
|
133
|
+
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
130
134
|
};
|
|
131
135
|
this.texture = new WGLTexture(gl, billboard_image);
|
|
132
136
|
this.u_texture = new WGLTexture(gl, u_image);
|
|
@@ -135,15 +139,23 @@ class BillboardCollection {
|
|
|
135
139
|
render(gl, matrix, [map_width, map_height], map_zoom, map_bearing, map_pitch) {
|
|
136
140
|
if (this.vertices === null || this.texcoords === null)
|
|
137
141
|
return;
|
|
142
|
+
if (matrix instanceof Float32Array)
|
|
143
|
+
matrix = [...matrix];
|
|
138
144
|
const bb_size = this.spec.BB_HEIGHT * (map_height / map_width) * this.size_multiplier;
|
|
139
145
|
const bb_width = this.spec.BB_WIDTH / this.spec.BB_TEX_WIDTH;
|
|
140
146
|
const bb_height = this.spec.BB_HEIGHT / this.spec.BB_TEX_HEIGHT;
|
|
141
147
|
this.program.use({ 'a_pos': this.vertices, 'a_tex_coord': this.texcoords }, { 'u_bb_size': bb_size, 'u_bb_width': bb_width, 'u_bb_height': bb_height,
|
|
142
|
-
'u_bb_mag_bin_size': this.spec.BB_MAG_BIN_SIZE, 'u_bb_mag_wrap': this.spec.BB_MAG_WRAP,
|
|
148
|
+
'u_bb_mag_bin_size': this.spec.BB_MAG_BIN_SIZE, 'u_bb_mag_wrap': this.spec.BB_MAG_WRAP, 'u_offset': 0,
|
|
143
149
|
'u_bb_color': this.color, 'u_matrix': matrix, 'u_map_aspect': map_height / map_width, 'u_zoom': map_zoom, 'u_map_bearing': map_bearing }, { 'u_sampler': this.texture, 'u_u_sampler': this.u_texture, 'u_v_sampler': this.v_texture });
|
|
144
150
|
gl.enable(gl.BLEND);
|
|
145
151
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
146
152
|
this.program.draw();
|
|
153
|
+
this.program.setUniforms({ 'u_offset': -2 });
|
|
154
|
+
this.program.draw();
|
|
155
|
+
this.program.setUniforms({ 'u_offset': -1 });
|
|
156
|
+
this.program.draw();
|
|
157
|
+
this.program.setUniforms({ 'u_offset': 1 });
|
|
158
|
+
this.program.draw();
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
export { BillboardCollection };
|
package/lib/Contour.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
1
|
+
import { TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
|
|
2
2
|
import { MapType } from './Map';
|
|
3
3
|
import { PlotComponent } from './PlotComponent';
|
|
4
4
|
import { RawScalarField } from './RawField';
|
|
5
|
-
import { WGLBuffer, WGLProgram, WGLTexture } from 'autumn-wgl';
|
|
6
5
|
interface ContourOptions {
|
|
7
6
|
/**
|
|
8
7
|
* The color of the contours as a hex color string
|
|
@@ -26,14 +25,6 @@ interface ContourOptions {
|
|
|
26
25
|
*/
|
|
27
26
|
thinner?: (zoom: number) => number;
|
|
28
27
|
}
|
|
29
|
-
interface ContourGLElems {
|
|
30
|
-
map: MapType;
|
|
31
|
-
program: WGLProgram;
|
|
32
|
-
vertices: WGLBuffer;
|
|
33
|
-
grid_cell_size: WGLBuffer;
|
|
34
|
-
fill_texture: WGLTexture;
|
|
35
|
-
texcoords: WGLBuffer;
|
|
36
|
-
}
|
|
37
28
|
/**
|
|
38
29
|
* A field of contoured data. The contours can optionally be thinned based on map zoom level.
|
|
39
30
|
* @example
|
|
@@ -42,20 +33,19 @@ interface ContourGLElems {
|
|
|
42
33
|
* const contours = new Contour(height_field, {color: '#000000', interval: 30,
|
|
43
34
|
* thinner: zoom => zoom < 5 ? 2 : 1});
|
|
44
35
|
*/
|
|
45
|
-
declare class Contour extends PlotComponent {
|
|
46
|
-
readonly field
|
|
36
|
+
declare class Contour<ArrayType extends TypedArray> extends PlotComponent {
|
|
37
|
+
private readonly field;
|
|
47
38
|
readonly color: [number, number, number];
|
|
48
39
|
readonly interval: number;
|
|
49
40
|
readonly levels: number[];
|
|
50
41
|
readonly thinner: (zoom: number) => number;
|
|
51
|
-
|
|
52
|
-
gl_elems: ContourGLElems | null;
|
|
42
|
+
private gl_elems;
|
|
53
43
|
/**
|
|
54
44
|
* Create a contoured field
|
|
55
45
|
* @param field - The field to contour
|
|
56
46
|
* @param opts - Options for creating the contours
|
|
57
47
|
*/
|
|
58
|
-
constructor(field: RawScalarField
|
|
48
|
+
constructor(field: RawScalarField<ArrayType>, opts: ContourOptions);
|
|
59
49
|
/**
|
|
60
50
|
* @internal
|
|
61
51
|
* Add the contours to a map
|
|
@@ -65,7 +55,7 @@ declare class Contour extends PlotComponent {
|
|
|
65
55
|
* @internal
|
|
66
56
|
* Render the contours
|
|
67
57
|
*/
|
|
68
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
58
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
69
59
|
}
|
|
70
60
|
export default Contour;
|
|
71
61
|
export type { ContourOptions };
|
package/lib/Contour.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PlotComponent } from './PlotComponent';
|
|
1
|
+
import { PlotComponent, getGLFormatTypeAlignment } from './PlotComponent';
|
|
3
2
|
import { hex2rgba } from './utils';
|
|
4
3
|
import { WGLProgram, WGLTexture } from 'autumn-wgl';
|
|
5
4
|
const contour_vertex_shader_src = `uniform mat4 u_matrix;
|
|
5
|
+
uniform int u_offset;
|
|
6
6
|
|
|
7
7
|
attribute vec2 a_pos;
|
|
8
8
|
attribute float a_grid_cell_size;
|
|
@@ -13,7 +13,10 @@ varying highp float v_grid_cell_size;
|
|
|
13
13
|
varying highp float v_map_scale_fac;
|
|
14
14
|
|
|
15
15
|
void main() {
|
|
16
|
-
|
|
16
|
+
float globe_width = 1.;
|
|
17
|
+
vec2 globe_offset = vec2(globe_width * float(u_offset), 0.);
|
|
18
|
+
|
|
19
|
+
gl_Position = u_matrix * vec4(a_pos + globe_offset, 0.0, 1.0);
|
|
17
20
|
v_tex_coord = a_tex_coord;
|
|
18
21
|
v_grid_cell_size = a_grid_cell_size;
|
|
19
22
|
|
|
@@ -40,16 +43,20 @@ uniform lowp float u_zoom_fac;
|
|
|
40
43
|
void main() {
|
|
41
44
|
highp float field_val = texture2D(u_fill_sampler, v_tex_coord).r;
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
lowp vec2 grid_point = fract(v_tex_coord / u_step_size + vec2(0.5, 0.5));
|
|
47
|
+
highp vec2 grid_sw = v_tex_coord - grid_point * u_step_size;
|
|
48
|
+
|
|
44
49
|
lowp vec2 ihat = vec2(u_step_size.x, 0.0);
|
|
45
50
|
lowp vec2 jhat = vec2(0.0, u_step_size.y);
|
|
46
|
-
highp float
|
|
47
|
-
highp float
|
|
48
|
-
highp float
|
|
49
|
-
highp float
|
|
50
|
-
|
|
51
|
+
highp float fv_sw = texture2D(u_fill_sampler, grid_sw).r;
|
|
52
|
+
highp float fv_se = texture2D(u_fill_sampler, grid_sw + ihat).r;
|
|
53
|
+
highp float fv_nw = texture2D(u_fill_sampler, grid_sw + jhat).r;
|
|
54
|
+
highp float fv_ne = texture2D(u_fill_sampler, grid_sw + ihat + jhat).r;
|
|
55
|
+
|
|
56
|
+
highp float dfdx = mix(fv_se, fv_ne, grid_point.y) - mix(fv_sw, fv_nw, grid_point.y);
|
|
57
|
+
highp float dfdy = mix(fv_nw, fv_ne, grid_point.x) - mix(fv_sw, fv_se, grid_point.x);
|
|
58
|
+
highp float fwidth_field = sqrt((dfdx * dfdx + dfdy * dfdy) / (5e5 * v_grid_cell_size));
|
|
51
59
|
|
|
52
|
-
|
|
53
60
|
lowp float plot_val;
|
|
54
61
|
|
|
55
62
|
if (u_num_contours > 0) {
|
|
@@ -99,7 +106,7 @@ void main() {
|
|
|
99
106
|
}`
|
|
100
107
|
/**
|
|
101
108
|
* A field of contoured data. The contours can optionally be thinned based on map zoom level.
|
|
102
|
-
*
|
|
109
|
+
* @example
|
|
103
110
|
* // Create a contoured height field, with black contours every 30 m (assuming the height field is in
|
|
104
111
|
* // meters) and only using every other contour when the map zoom level is less than 5.
|
|
105
112
|
* const contours = new Contour(height_field, {color: '#000000', interval: 30,
|
|
@@ -108,8 +115,8 @@ void main() {
|
|
|
108
115
|
class Contour extends PlotComponent {
|
|
109
116
|
/**
|
|
110
117
|
* Create a contoured field
|
|
111
|
-
*
|
|
112
|
-
*
|
|
118
|
+
* @param field - The field to contour
|
|
119
|
+
* @param opts - Options for creating the contours
|
|
113
120
|
*/
|
|
114
121
|
constructor(field, opts) {
|
|
115
122
|
super();
|
|
@@ -122,23 +129,21 @@ class Contour extends PlotComponent {
|
|
|
122
129
|
this.gl_elems = null;
|
|
123
130
|
}
|
|
124
131
|
/**
|
|
125
|
-
*
|
|
132
|
+
* @internal
|
|
126
133
|
* Add the contours to a map
|
|
127
134
|
*/
|
|
128
135
|
async onAdd(map, gl) {
|
|
129
136
|
// Basic procedure for these contours from https://www.shadertoy.com/view/lltBWM
|
|
130
|
-
gl.getExtension(
|
|
131
|
-
gl.getExtension('OES_texture_float_linear');
|
|
132
|
-
gl.getExtension('OES_standard_derivatives');
|
|
137
|
+
gl.getExtension("OES_standard_derivatives");
|
|
133
138
|
const program = new WGLProgram(gl, contour_vertex_shader_src, contour_fragment_shader_src);
|
|
134
139
|
const { vertices: verts_buf, texcoords: tex_coords_buf, cellsize: cellsize_buf } = await this.field.grid.getWGLBuffers(gl);
|
|
135
140
|
const vertices = verts_buf;
|
|
136
141
|
const texcoords = tex_coords_buf;
|
|
137
142
|
const grid_cell_size = cellsize_buf;
|
|
138
|
-
const format =
|
|
139
|
-
const fill_image = { 'format': format, 'type':
|
|
140
|
-
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.
|
|
141
|
-
'mag_filter': gl.LINEAR,
|
|
143
|
+
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, this.field.isFloat16());
|
|
144
|
+
const fill_image = { 'format': format, 'type': type,
|
|
145
|
+
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.getTextureData(),
|
|
146
|
+
'mag_filter': gl.LINEAR, 'row_alignment': row_alignment,
|
|
142
147
|
};
|
|
143
148
|
const fill_texture = new WGLTexture(gl, fill_image);
|
|
144
149
|
this.gl_elems = {
|
|
@@ -146,20 +151,22 @@ class Contour extends PlotComponent {
|
|
|
146
151
|
};
|
|
147
152
|
}
|
|
148
153
|
/**
|
|
149
|
-
*
|
|
154
|
+
* @internal
|
|
150
155
|
* Render the contours
|
|
151
156
|
*/
|
|
152
157
|
render(gl, matrix) {
|
|
153
158
|
if (this.gl_elems === null)
|
|
154
159
|
return;
|
|
155
160
|
const gl_elems = this.gl_elems;
|
|
161
|
+
if (matrix instanceof Float32Array)
|
|
162
|
+
matrix = [...matrix];
|
|
156
163
|
const zoom = gl_elems.map.getZoom();
|
|
157
164
|
const intv = this.thinner(zoom) * this.interval;
|
|
158
|
-
const cutoff = 0.
|
|
159
|
-
const step_size = [
|
|
165
|
+
const cutoff = 0.3 / intv;
|
|
166
|
+
const step_size = [1 / this.field.grid.ni, 1 / this.field.grid.nj];
|
|
160
167
|
const zoom_fac = Math.pow(2, zoom);
|
|
161
168
|
let uniforms = { 'u_contour_interval': intv, 'u_line_cutoff': cutoff, 'u_color': this.color, 'u_step_size': step_size, 'u_zoom_fac': zoom_fac,
|
|
162
|
-
'u_matrix': matrix, 'u_num_contours': 0, 'u_contour_levels': [0] };
|
|
169
|
+
'u_matrix': matrix, 'u_num_contours': 0, 'u_contour_levels': [0], 'u_offset': 0 };
|
|
163
170
|
if (this.levels.length > 0) {
|
|
164
171
|
uniforms = { ...uniforms, 'u_num_contours': this.levels.length, 'u_contour_levels': this.levels };
|
|
165
172
|
}
|
|
@@ -167,6 +174,12 @@ class Contour extends PlotComponent {
|
|
|
167
174
|
gl.enable(gl.BLEND);
|
|
168
175
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
169
176
|
gl_elems.program.draw();
|
|
177
|
+
gl_elems.program.setUniforms({ 'u_offset': -2 });
|
|
178
|
+
gl_elems.program.draw();
|
|
179
|
+
gl_elems.program.setUniforms({ 'u_offset': -1 });
|
|
180
|
+
gl_elems.program.draw();
|
|
181
|
+
gl_elems.program.setUniforms({ 'u_offset': 1 });
|
|
182
|
+
gl_elems.program.draw();
|
|
170
183
|
}
|
|
171
184
|
}
|
|
172
185
|
export default Contour;
|
package/lib/Fill.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { PlotComponent } from './PlotComponent';
|
|
2
2
|
import { ColorMap } from './Colormap';
|
|
3
|
-
import { WGLBuffer, WGLProgram, WGLTexture } from 'autumn-wgl';
|
|
4
3
|
import { RawScalarField } from './RawField';
|
|
5
4
|
import { MapType } from './Map';
|
|
6
|
-
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
5
|
+
import { TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
|
|
7
6
|
interface ContourFillOptions {
|
|
8
7
|
/** The color map to use when creating the fills */
|
|
9
8
|
cmap: ColorMap;
|
|
@@ -22,29 +21,18 @@ interface RasterOptions {
|
|
|
22
21
|
*/
|
|
23
22
|
opacity?: number;
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
vertices: WGLBuffer;
|
|
28
|
-
fill_texture: WGLTexture;
|
|
29
|
-
texcoords: WGLBuffer;
|
|
30
|
-
cmap_texture: WGLTexture;
|
|
31
|
-
cmap_nonlin_texture: WGLTexture;
|
|
32
|
-
}
|
|
33
|
-
declare class PlotComponentFill extends PlotComponent {
|
|
34
|
-
readonly field: RawScalarField;
|
|
24
|
+
declare class PlotComponentFill<ArrayType extends TypedArray> extends PlotComponent {
|
|
25
|
+
private readonly field;
|
|
35
26
|
readonly cmap: ColorMap;
|
|
36
27
|
readonly opacity: number;
|
|
37
|
-
|
|
38
|
-
readonly
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
image_mag_filter: number | null;
|
|
44
|
-
cmap_mag_filter: number | null;
|
|
45
|
-
constructor(field: RawScalarField, opts: ContourFillOptions);
|
|
28
|
+
private readonly cmap_image;
|
|
29
|
+
private readonly index_map;
|
|
30
|
+
private gl_elems;
|
|
31
|
+
protected image_mag_filter: number | null;
|
|
32
|
+
protected cmap_mag_filter: number | null;
|
|
33
|
+
constructor(field: RawScalarField<ArrayType>, opts: ContourFillOptions);
|
|
46
34
|
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
47
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
35
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
48
36
|
}
|
|
49
37
|
/**
|
|
50
38
|
* A raster (i.e. pixel) plot
|
|
@@ -52,13 +40,13 @@ declare class PlotComponentFill extends PlotComponent {
|
|
|
52
40
|
* // Create a raster plot with the provided color map
|
|
53
41
|
* const raster = new Raster(wind_speed_field, {cmap: color_map});
|
|
54
42
|
*/
|
|
55
|
-
declare class Raster extends PlotComponentFill {
|
|
43
|
+
declare class Raster<ArrayType extends TypedArray> extends PlotComponentFill<ArrayType> {
|
|
56
44
|
/**
|
|
57
45
|
* Create a raster plot
|
|
58
46
|
* @param field - The field to create the raster plot from
|
|
59
47
|
* @param opts - Options for creating the raster plot
|
|
60
48
|
*/
|
|
61
|
-
constructor(field: RawScalarField
|
|
49
|
+
constructor(field: RawScalarField<ArrayType>, opts: RasterOptions);
|
|
62
50
|
/**
|
|
63
51
|
* @internal
|
|
64
52
|
* Add the raster plot to a map
|
|
@@ -68,7 +56,7 @@ declare class Raster extends PlotComponentFill {
|
|
|
68
56
|
* @internal
|
|
69
57
|
* Render the raster plot
|
|
70
58
|
*/
|
|
71
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
59
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
72
60
|
}
|
|
73
61
|
/**
|
|
74
62
|
* A filled contoured field
|
|
@@ -76,13 +64,13 @@ declare class Raster extends PlotComponentFill {
|
|
|
76
64
|
* // Create a field of filled contours with the provided color map
|
|
77
65
|
* const fill = new ContourFill(wind_speed_field, {cmap: color_map});
|
|
78
66
|
*/
|
|
79
|
-
declare class ContourFill extends PlotComponentFill {
|
|
67
|
+
declare class ContourFill<ArrayType extends TypedArray> extends PlotComponentFill<ArrayType> {
|
|
80
68
|
/**
|
|
81
69
|
* Create a filled contoured field
|
|
82
70
|
* @param field - The field to create filled contours from
|
|
83
71
|
* @param opts - Options for creating the filled contours
|
|
84
72
|
*/
|
|
85
|
-
constructor(field: RawScalarField
|
|
73
|
+
constructor(field: RawScalarField<ArrayType>, opts: ContourFillOptions);
|
|
86
74
|
/**
|
|
87
75
|
* @internal
|
|
88
76
|
* Add the filled contours to a map
|
|
@@ -92,7 +80,7 @@ declare class ContourFill extends PlotComponentFill {
|
|
|
92
80
|
* @internal
|
|
93
81
|
* Render the filled contours
|
|
94
82
|
*/
|
|
95
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
83
|
+
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
96
84
|
}
|
|
97
85
|
export { ContourFill, Raster };
|
|
98
86
|
export type { ContourFillOptions, RasterOptions };
|