autumnplot-gl 4.0.0-beta → 4.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 +11 -207
- package/dist/983.autumnplot-gl.js +2 -0
- package/dist/983.autumnplot-gl.js.map +1 -0
- package/dist/autumnplot-gl.js +1 -1
- package/dist/autumnplot-gl.js.map +1 -1
- package/dist/marchingsquares.wasm +0 -0
- package/lib/AutumnTypes.d.ts +34 -3
- package/lib/AutumnTypes.js +4 -1
- package/lib/Barbs.d.ts +1 -0
- package/lib/Color.d.ts +1 -0
- package/lib/Color.js +1 -0
- package/lib/ColorBar.d.ts +9 -0
- package/lib/ColorBar.js +5 -4
- package/lib/Colormap.d.ts +1 -0
- package/lib/Contour.d.ts +10 -0
- package/lib/Contour.js +10 -0
- package/lib/ContourCreator.d.ts +5 -1
- package/lib/ContourCreator.js +3 -3
- package/lib/Fill.d.ts +2 -0
- package/lib/Grid.d.ts +10 -3
- package/lib/Grid.js +61 -8
- package/lib/Hodographs.d.ts +6 -0
- package/lib/Hodographs.js +34 -19
- package/lib/Map.d.ts +14 -1
- package/lib/Map.js +59 -3
- package/lib/Paintball.d.ts +1 -0
- package/lib/Paintball.js +1 -1
- package/lib/PlotComponent.d.ts +1 -0
- package/lib/PlotComponent.js +1 -0
- package/lib/PlotLayer.d.ts +2 -2
- package/lib/PlotLayer.js +2 -2
- package/lib/PlotLayer.worker.js +8 -2
- package/lib/RawField.d.ts +2 -0
- package/lib/RawField.js +9 -2
- package/lib/StationPlot.d.ts +59 -8
- package/lib/StationPlot.js +28 -11
- package/lib/TextCollection.js +3 -0
- package/lib/index.d.ts +9 -3
- package/lib/index.js +4 -2
- package/package.json +2 -2
- package/dist/110.autumnplot-gl.js +0 -2
- package/dist/110.autumnplot-gl.js.map +0 -1
|
Binary file
|
package/lib/AutumnTypes.d.ts
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
import { Float16Array } from "@petamoriken/float16";
|
|
2
|
-
|
|
2
|
+
/** A wind profile with a storm-motion for plotting storm-relative hodographs */
|
|
3
|
+
interface StormRelativeWindProfile {
|
|
4
|
+
/** The grid index in the j direction (ignored for unstructured grids) */
|
|
3
5
|
jlat: number;
|
|
6
|
+
/** The grid index in the i direction */
|
|
4
7
|
ilon: number;
|
|
8
|
+
/** u component of storm motion in kts */
|
|
5
9
|
smu: number;
|
|
10
|
+
/** v component of storm motion in kts */
|
|
6
11
|
smv: number;
|
|
12
|
+
/** Ground-relative u winds in kts (will be converted to storm-relative during plotting) */
|
|
7
13
|
u: Float32Array;
|
|
14
|
+
/** Ground-relative v winds in kts (will be converted to storm-relative during plotting) */
|
|
8
15
|
v: Float32Array;
|
|
16
|
+
/** Height of each data point in km */
|
|
9
17
|
z: Float32Array;
|
|
10
18
|
}
|
|
19
|
+
/** A wind profile without a storm motion for plotting ground-relative hodographs */
|
|
20
|
+
interface GroundRelativeWindProfile {
|
|
21
|
+
/** The grid index in the j direction (ignored for unstructured grids) */
|
|
22
|
+
jlat: number;
|
|
23
|
+
/** The grid index in the i direction */
|
|
24
|
+
ilon: number;
|
|
25
|
+
/** Ground-relative u winds in kts */
|
|
26
|
+
u: Float32Array;
|
|
27
|
+
/** Ground-relative v winds in kts */
|
|
28
|
+
v: Float32Array;
|
|
29
|
+
/** Height of each data point in km */
|
|
30
|
+
z: Float32Array;
|
|
31
|
+
}
|
|
32
|
+
/** Different types of wind profiles for {@link Hodographs} components */
|
|
33
|
+
type WindProfile = StormRelativeWindProfile | GroundRelativeWindProfile;
|
|
34
|
+
declare function isStormRelativeWindProfile(obj: any): obj is StormRelativeWindProfile;
|
|
11
35
|
interface BillboardSpec {
|
|
12
36
|
BB_WIDTH: number;
|
|
13
37
|
BB_HEIGHT: number;
|
|
@@ -30,10 +54,17 @@ type Polyline = {
|
|
|
30
54
|
data?: Float32Array;
|
|
31
55
|
zoom?: Float32Array;
|
|
32
56
|
};
|
|
57
|
+
/** WebGL rendering contexts (either WebGL1 or WebGL2) */
|
|
33
58
|
type WebGLAnyRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;
|
|
34
59
|
declare function isWebGL2Ctx(gl: WebGLAnyRenderingContext): gl is WebGL2RenderingContext;
|
|
60
|
+
/** Javascript typed arrays for use in raw fields */
|
|
35
61
|
type TypedArray = Float16Array | Float32Array | Uint8Array;
|
|
36
62
|
type TypedArrayStr = 'float16' | 'float32' | 'uint8';
|
|
63
|
+
/**
|
|
64
|
+
* The result of contouring a field
|
|
65
|
+
*
|
|
66
|
+
* Each property is a different contour level giving an array of contours, and each contour is an array of [longitude, latitude].
|
|
67
|
+
*/
|
|
37
68
|
type ContourData = Record<number, [number, number][][]>;
|
|
38
69
|
type mat4 = number[] | Float32Array | Float64Array;
|
|
39
70
|
type RenderShaderData = {
|
|
@@ -84,5 +115,5 @@ type RendererDataAutumn = {
|
|
|
84
115
|
};
|
|
85
116
|
type RendererData = RendererDataMapLibre | RendererDataAutumn;
|
|
86
117
|
declare function getRendererData(arg: RenderMethodArg): RendererData;
|
|
87
|
-
export { isWebGL2Ctx, getRendererData };
|
|
88
|
-
export type { WindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourData, RenderMethodArg, RendererData, RenderShaderData };
|
|
118
|
+
export { isWebGL2Ctx, getRendererData, isStormRelativeWindProfile };
|
|
119
|
+
export type { WindProfile, StormRelativeWindProfile, GroundRelativeWindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourData, RenderMethodArg, RendererData, RenderShaderData };
|
package/lib/AutumnTypes.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
function isStormRelativeWindProfile(obj) {
|
|
2
|
+
return 'smu' in obj && 'smv' in obj;
|
|
3
|
+
}
|
|
1
4
|
function isWebGL2Ctx(gl) {
|
|
2
5
|
return gl.getParameter(gl.VERSION).includes('WebGL 2.0');
|
|
3
6
|
}
|
|
@@ -25,4 +28,4 @@ function getRendererData(arg) {
|
|
|
25
28
|
}
|
|
26
29
|
return { type: 'autumn', mainMatrix: [...arg], shaderData: null };
|
|
27
30
|
}
|
|
28
|
-
export { isWebGL2Ctx, getRendererData };
|
|
31
|
+
export { isWebGL2Ctx, getRendererData, isStormRelativeWindProfile };
|
package/lib/Barbs.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { MapLikeType } from "./Map";
|
|
|
4
4
|
import { RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
5
5
|
import { ColorMap } from "./Colormap";
|
|
6
6
|
import { Grid } from "./Grid";
|
|
7
|
+
/** Options for {@link Barbs} components */
|
|
7
8
|
interface BarbsOptions {
|
|
8
9
|
/**
|
|
9
10
|
* The color to use for the barbs as a hex color string;.
|
package/lib/Color.d.ts
CHANGED
package/lib/Color.js
CHANGED
package/lib/ColorBar.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ColorMap } from "./Colormap";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
|
+
/** The orientation for color bars (horizontal or vertical) */
|
|
3
4
|
type ColorbarOrientation = 'horizontal' | 'vertical';
|
|
5
|
+
/** Which side of a color bar the ticks are on */
|
|
4
6
|
type ColorbarTickDirection = 'top' | 'bottom' | 'left' | 'right';
|
|
7
|
+
/** Options for {@link ColorBar}s */
|
|
5
8
|
interface ColorBarOptions {
|
|
6
9
|
/** The label to place along the color bar */
|
|
7
10
|
label?: string;
|
|
@@ -41,6 +44,11 @@ interface ColorBarOptions {
|
|
|
41
44
|
* @default 12
|
|
42
45
|
*/
|
|
43
46
|
ticklabelsize?: number;
|
|
47
|
+
/**
|
|
48
|
+
* The color for the color bar outline and the text
|
|
49
|
+
* @default '#000000'
|
|
50
|
+
*/
|
|
51
|
+
outline_and_text_color?: string;
|
|
44
52
|
}
|
|
45
53
|
/**
|
|
46
54
|
* Make an SVG containing a color bar. The color bar can either be oriented horizontal or vertical, and a label can be provided.
|
|
@@ -56,6 +64,7 @@ interface ColorBarOptions {
|
|
|
56
64
|
* document.getElementById('colorbar-container').appendChild(svg);
|
|
57
65
|
*/
|
|
58
66
|
declare function makeColorBar(colormap: ColorMap, opts: ColorBarOptions): SVGElement;
|
|
67
|
+
/** Options for {@link makePaintballKey | makePaintballKey()} */
|
|
59
68
|
interface PaintballKeyOptions {
|
|
60
69
|
/**
|
|
61
70
|
* The number of columns of entries in the key
|
package/lib/ColorBar.js
CHANGED
|
@@ -32,6 +32,7 @@ function makeColorBar(colormap, opts) {
|
|
|
32
32
|
const tickfontsize = opts.ticklabelsize || 12;
|
|
33
33
|
const size_long = opts.size_long || 600;
|
|
34
34
|
const size_short = opts.size_short || size_long / 9;
|
|
35
|
+
const outline_and_text_color = opts.outline_and_text_color || '#000000';
|
|
35
36
|
const tick_dir = opts.tick_direction || (orientation == 'vertical' ? 'left' : 'bottom');
|
|
36
37
|
if (orientation == 'vertical' && (tick_dir == 'top' || tick_dir == 'bottom') ||
|
|
37
38
|
orientation == 'horizontal' && (tick_dir == 'left' || tick_dir == 'right')) {
|
|
@@ -143,7 +144,7 @@ function makeColorBar(colormap, opts) {
|
|
|
143
144
|
else {
|
|
144
145
|
lineattrs = tick_dir == 'bottom' ? { y2: 6 } : { y2: -6 };
|
|
145
146
|
}
|
|
146
|
-
createElement('line', { ...lineattrs, stroke:
|
|
147
|
+
createElement('line', { ...lineattrs, stroke: outline_and_text_color, 'stroke-width': 1.5 }, gtick);
|
|
147
148
|
let textattrs;
|
|
148
149
|
if (orientation == 'vertical') {
|
|
149
150
|
textattrs = tick_dir == 'left' ? { x: -9, dy: '0.32em' } : { x: 9, dy: '0.32em' };
|
|
@@ -151,7 +152,7 @@ function makeColorBar(colormap, opts) {
|
|
|
151
152
|
else {
|
|
152
153
|
textattrs = tick_dir == 'bottom' ? { y: 9, dy: '0.8em' } : { y: -9, dy: '0em' };
|
|
153
154
|
}
|
|
154
|
-
const text = createElement('text', { ...textattrs, fill:
|
|
155
|
+
const text = createElement('text', { ...textattrs, fill: outline_and_text_color, style: `font-family: ${fontface}; font-size: ${tickfontsize}pt` }, gtick);
|
|
155
156
|
text.textContent = level.toString();
|
|
156
157
|
});
|
|
157
158
|
// Draw the outline
|
|
@@ -166,7 +167,7 @@ function makeColorBar(colormap, opts) {
|
|
|
166
167
|
}
|
|
167
168
|
const outline_attrs = {
|
|
168
169
|
points: point_list,
|
|
169
|
-
stroke:
|
|
170
|
+
stroke: outline_and_text_color,
|
|
170
171
|
'stroke-width': 1.5,
|
|
171
172
|
fill: 'none'
|
|
172
173
|
};
|
|
@@ -179,7 +180,7 @@ function makeColorBar(colormap, opts) {
|
|
|
179
180
|
else {
|
|
180
181
|
labelattrs = tick_dir == 'bottom' ? { transform: `translate(${width / 2}, ${height - 5})` } : { transform: `translate(${width / 2}, 15)` };
|
|
181
182
|
}
|
|
182
|
-
const label_elem = createElement('text', { ...labelattrs, fill:
|
|
183
|
+
const label_elem = createElement('text', { ...labelattrs, fill: outline_and_text_color, 'text-anchor': 'middle', style: `font-family: ${fontface};` }, root);
|
|
183
184
|
label_elem.textContent = label;
|
|
184
185
|
return root;
|
|
185
186
|
}
|
package/lib/Colormap.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WGLProgram, WGLTexture } from "autumn-wgl";
|
|
2
2
|
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
3
3
|
import { Color } from "./Color";
|
|
4
|
+
/** Options for {@link ColorMap}s */
|
|
4
5
|
interface ColorMapOptions {
|
|
5
6
|
/** The color to use for areas where the value is above the highest value in the color map */
|
|
6
7
|
overflow_color?: Color | string;
|
package/lib/Contour.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { RawScalarField } from './RawField';
|
|
|
5
5
|
import { LineStyle } from './PolylineCollection';
|
|
6
6
|
import { ColorMap } from './Colormap';
|
|
7
7
|
import { StructuredGrid } from './Grid';
|
|
8
|
+
/** Options for {@link Contour} components */
|
|
8
9
|
interface ContourOptions {
|
|
9
10
|
/**
|
|
10
11
|
* The color of the contours as a hex color string
|
|
@@ -80,6 +81,7 @@ declare class Contour<ArrayType extends TypedArray, GridType extends StructuredG
|
|
|
80
81
|
*/
|
|
81
82
|
render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg): void;
|
|
82
83
|
}
|
|
84
|
+
/** Options for {@link ContourLabels} */
|
|
83
85
|
interface ContourLabelOptions {
|
|
84
86
|
/**
|
|
85
87
|
* Number of decimal places to use in the contour labels
|
|
@@ -121,6 +123,14 @@ interface ContourLabelOptions {
|
|
|
121
123
|
*/
|
|
122
124
|
density?: number;
|
|
123
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Label the contours on a plot
|
|
128
|
+
* @example
|
|
129
|
+
* // Contour some data
|
|
130
|
+
* const contours = new Contour(height_field, {color: '#000000', interval: 30});
|
|
131
|
+
* // Label the contours
|
|
132
|
+
* const labels = new ContourLabels(contours, {text_color: '#ffffff', halo: true});
|
|
133
|
+
*/
|
|
124
134
|
declare class ContourLabels<ArrayType extends TypedArray, GridType extends StructuredGrid, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
125
135
|
private readonly contours;
|
|
126
136
|
private gl_elems;
|
package/lib/Contour.js
CHANGED
|
@@ -126,6 +126,14 @@ const contour_label_opt_defaults = {
|
|
|
126
126
|
halo: false,
|
|
127
127
|
density: 1
|
|
128
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* Label the contours on a plot
|
|
131
|
+
* @example
|
|
132
|
+
* // Contour some data
|
|
133
|
+
* const contours = new Contour(height_field, {color: '#000000', interval: 30});
|
|
134
|
+
* // Label the contours
|
|
135
|
+
* const labels = new ContourLabels(contours, {text_color: '#ffffff', halo: true});
|
|
136
|
+
*/
|
|
129
137
|
class ContourLabels extends PlotComponent {
|
|
130
138
|
constructor(contours, opts) {
|
|
131
139
|
super();
|
|
@@ -175,6 +183,8 @@ class ContourLabels extends PlotComponent {
|
|
|
175
183
|
let n_labels_placed = 0;
|
|
176
184
|
for (let idist = 1; idist < dist.length; idist++) {
|
|
177
185
|
const target_dist = contour_label_spacing * (n_labels_placed + (icntr / 2) % 1);
|
|
186
|
+
// This works fine when contour_label_spacing > the spacing between points along a contour, but when you allow the map to zoom in
|
|
187
|
+
// (and therefore contour_label_spacing gets small), dist[idist] outruns target_dist, so it doesn't put any more labels after the first.
|
|
178
188
|
if (dist[idist - 1] <= target_dist && target_dist < dist[idist]) {
|
|
179
189
|
const pt1 = contour[idist - 1];
|
|
180
190
|
const pt2 = contour[idist];
|
package/lib/ContourCreator.d.ts
CHANGED
|
@@ -2,7 +2,11 @@ import { MarchingSquaresModule } from './cpp/marchingsquares';
|
|
|
2
2
|
import './cpp/marchingsquares.wasm';
|
|
3
3
|
import { Grid } from "./Grid";
|
|
4
4
|
import { ContourData, TypedArray } from "./AutumnTypes";
|
|
5
|
-
|
|
5
|
+
interface InitMSModuleOpts {
|
|
6
|
+
document_script?: string;
|
|
7
|
+
}
|
|
8
|
+
declare function initMSModule(opts: InitMSModuleOpts): Promise<MarchingSquaresModule>;
|
|
9
|
+
/** Options for contouring data via {@link RawScalarField.getContours | RawScalarField.getContours()} */
|
|
6
10
|
interface FieldContourOpts {
|
|
7
11
|
/**
|
|
8
12
|
* The interval at which to create contours. The field will be contoured at this interval from its minimum to its maximum.
|
package/lib/ContourCreator.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import Module from './cpp/marchingsquares';
|
|
2
2
|
import './cpp/marchingsquares.wasm';
|
|
3
3
|
let msm_promise = null;
|
|
4
|
-
function initMSModule() {
|
|
4
|
+
function initMSModule(opts) {
|
|
5
5
|
if (msm_promise === null) {
|
|
6
|
-
msm_promise = Module();
|
|
6
|
+
msm_promise = Module({ 'locateFile': (fname, dir) => (opts.document_script === undefined ? dir : opts.document_script) + fname });
|
|
7
7
|
}
|
|
8
8
|
return msm_promise;
|
|
9
9
|
}
|
|
@@ -13,7 +13,7 @@ async function contourCreator(data, grid, opts) {
|
|
|
13
13
|
}
|
|
14
14
|
const interval = opts.interval === undefined ? 0 : opts.interval;
|
|
15
15
|
const quad_as_tri = opts.quad_as_tri === undefined ? false : opts.quad_as_tri;
|
|
16
|
-
const msm = await initMSModule();
|
|
16
|
+
const msm = await initMSModule({});
|
|
17
17
|
const grid_coords = grid.getGridCoords();
|
|
18
18
|
const getContourLevels = data instanceof Float32Array ? msm.getContourLevelsFloat32 : msm.getContourLevelsFloat16;
|
|
19
19
|
const makeContours = data instanceof Float32Array ? msm.makeContoursFloat32 : msm.makeContoursFloat16;
|
package/lib/Fill.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { RawScalarField } from './RawField';
|
|
|
4
4
|
import { MapLikeType } from './Map';
|
|
5
5
|
import { RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
|
|
6
6
|
import { StructuredGrid } from './Grid';
|
|
7
|
+
/** Options for {@link ContourFill} components */
|
|
7
8
|
interface ContourFillOptions {
|
|
8
9
|
/** The color maps to use when creating the fills */
|
|
9
10
|
cmap: ColorMap | ColorMap[];
|
|
@@ -18,6 +19,7 @@ interface ContourFillOptions {
|
|
|
18
19
|
*/
|
|
19
20
|
opacity?: number;
|
|
20
21
|
}
|
|
22
|
+
/** Options for {@link Raster} components */
|
|
21
23
|
interface RasterOptions {
|
|
22
24
|
/** The color map to use when creating the raster plot */
|
|
23
25
|
cmap: ColorMap | ColorMap[];
|
package/lib/Grid.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface GridCoords {
|
|
|
9
9
|
y: Float32Array;
|
|
10
10
|
}
|
|
11
11
|
type GridType = 'latlon' | 'latlonrot' | 'lcc' | 'unstructured';
|
|
12
|
+
/** The base class for grid types */
|
|
12
13
|
declare abstract class Grid {
|
|
13
14
|
readonly type: GridType;
|
|
14
15
|
readonly ni: number;
|
|
@@ -165,6 +166,8 @@ declare class LambertGrid extends StructuredGrid {
|
|
|
165
166
|
readonly ll_y: number;
|
|
166
167
|
readonly ur_x: number;
|
|
167
168
|
readonly ur_y: number;
|
|
169
|
+
readonly a: number;
|
|
170
|
+
readonly b: number;
|
|
168
171
|
private readonly lcc;
|
|
169
172
|
private readonly ll_cache;
|
|
170
173
|
private readonly gc_cache;
|
|
@@ -179,8 +182,10 @@ declare class LambertGrid extends StructuredGrid {
|
|
|
179
182
|
* @param ll_y - The y coordinate in projection space of the lower-left corner of the grid
|
|
180
183
|
* @param ur_x - The x coordinate in projection space of the upper-right corner of the grid
|
|
181
184
|
* @param ur_y - The y coordinate in projection space of the upper-right corner of the grid
|
|
185
|
+
* @param a - The semimajor axis of the assumed shape of Earth in meters
|
|
186
|
+
* @param b - The semiminor axis of the assumed shape of Earth in meters
|
|
182
187
|
*/
|
|
183
|
-
constructor(ni: number, nj: number, lon_0: number, lat_0: number, lat_std: [number, number], ll_x: number, ll_y: number, ur_x: number, ur_y: number, thin_x?: number, thin_y?: number);
|
|
188
|
+
constructor(ni: number, nj: number, lon_0: number, lat_0: number, lat_std: [number, number], ll_x: number, ll_y: number, ur_x: number, ur_y: number, a?: number, b?: number, thin_x?: number, thin_y?: number);
|
|
184
189
|
/**
|
|
185
190
|
* Create a Lambert conformal conic grid from the lower-left grid point coordinate and a dx and dy.
|
|
186
191
|
* @param ni - The number of grid points in the i (longitude) direction
|
|
@@ -192,9 +197,11 @@ declare class LambertGrid extends StructuredGrid {
|
|
|
192
197
|
* @param ll_lat - The latitude of the lower-left corner of the grid
|
|
193
198
|
* @param dx - The grid dx in meters
|
|
194
199
|
* @param dy - The grid dy in meters
|
|
200
|
+
* @param a - The semimajor axis of the assumed shape of Earth in meters
|
|
201
|
+
* @param b - The semiminor axis of the assumed shape of Earth in meters
|
|
195
202
|
* @returns
|
|
196
203
|
*/
|
|
197
|
-
static fromLLCornerLonLat(ni: number, nj: number, lon_0: number, lat_0: number, lat_std: [number, number], ll_lon: number, ll_lat: number, dx: number, dy: number): LambertGrid;
|
|
204
|
+
static fromLLCornerLonLat(ni: number, nj: number, lon_0: number, lat_0: number, lat_std: [number, number], ll_lon: number, ll_lat: number, dx: number, dy: number, a?: number, b?: number): LambertGrid;
|
|
198
205
|
/** @internal */
|
|
199
206
|
copy(opts?: {
|
|
200
207
|
ni?: number;
|
|
@@ -218,7 +225,7 @@ declare class LambertGrid extends StructuredGrid {
|
|
|
218
225
|
/** @internal */
|
|
219
226
|
getThinnedGrid(thin_fac: number, map_max_zoom: number): LambertGrid;
|
|
220
227
|
}
|
|
221
|
-
/** An unstructured grid */
|
|
228
|
+
/** An unstructured grid defined by a list of latitudes and longitudes */
|
|
222
229
|
declare class UnstructuredGrid extends Grid {
|
|
223
230
|
readonly coords: {
|
|
224
231
|
lon: number;
|
package/lib/Grid.js
CHANGED
|
@@ -4,6 +4,8 @@ import { LngLat, lambertConformalConic, rotateSphere } from "./Map";
|
|
|
4
4
|
import { getGLFormatTypeAlignment, layer_worker } from "./PlotComponent";
|
|
5
5
|
import { Cache, getArrayConstructor, getMinZoom } from "./utils";
|
|
6
6
|
import { kdTree } from "kd-tree-javascript";
|
|
7
|
+
const WGS84_SEMIMAJOR = 6378137.0;
|
|
8
|
+
const WGS84_SEMIMINOR = 6356752.314245;
|
|
7
9
|
function argMin(ary) {
|
|
8
10
|
if (ary.length === 0) {
|
|
9
11
|
return -1;
|
|
@@ -60,6 +62,7 @@ function makeVectorRotationTexture(gl, grid, data_are_earth_relative) {
|
|
|
60
62
|
const rot_tex = new WGLTexture(gl, rot_img);
|
|
61
63
|
return { 'rotation': rot_tex };
|
|
62
64
|
}
|
|
65
|
+
/** The base class for grid types */
|
|
63
66
|
class Grid {
|
|
64
67
|
constructor(type, is_conformal, ni, nj) {
|
|
65
68
|
this.type = type;
|
|
@@ -354,8 +357,10 @@ class LambertGrid extends StructuredGrid {
|
|
|
354
357
|
* @param ll_y - The y coordinate in projection space of the lower-left corner of the grid
|
|
355
358
|
* @param ur_x - The x coordinate in projection space of the upper-right corner of the grid
|
|
356
359
|
* @param ur_y - The y coordinate in projection space of the upper-right corner of the grid
|
|
360
|
+
* @param a - The semimajor axis of the assumed shape of Earth in meters
|
|
361
|
+
* @param b - The semiminor axis of the assumed shape of Earth in meters
|
|
357
362
|
*/
|
|
358
|
-
constructor(ni, nj, lon_0, lat_0, lat_std, ll_x, ll_y, ur_x, ur_y, thin_x, thin_y) {
|
|
363
|
+
constructor(ni, nj, lon_0, lat_0, lat_std, ll_x, ll_y, ur_x, ur_y, a, b, thin_x, thin_y) {
|
|
359
364
|
super('lcc', true, ni, nj, thin_x, thin_y);
|
|
360
365
|
this.lon_0 = lon_0;
|
|
361
366
|
this.lat_0 = lat_0;
|
|
@@ -364,7 +369,9 @@ class LambertGrid extends StructuredGrid {
|
|
|
364
369
|
this.ll_y = ll_y;
|
|
365
370
|
this.ur_x = ur_x;
|
|
366
371
|
this.ur_y = ur_y;
|
|
367
|
-
this.
|
|
372
|
+
this.a = a === undefined ? WGS84_SEMIMAJOR : a;
|
|
373
|
+
this.b = b === undefined ? WGS84_SEMIMINOR : b;
|
|
374
|
+
this.lcc = lambertConformalConic({ lon_0: lon_0, lat_0: lat_0, lat_std: lat_std, a: this.a, b: this.b });
|
|
368
375
|
const dx = (this.ur_x - this.ll_x) / this.ni;
|
|
369
376
|
const dy = (this.ur_y - this.ll_y) / this.nj;
|
|
370
377
|
this.ll_cache = new Cache((ni, nj) => {
|
|
@@ -407,12 +414,16 @@ class LambertGrid extends StructuredGrid {
|
|
|
407
414
|
* @param ll_lat - The latitude of the lower-left corner of the grid
|
|
408
415
|
* @param dx - The grid dx in meters
|
|
409
416
|
* @param dy - The grid dy in meters
|
|
417
|
+
* @param a - The semimajor axis of the assumed shape of Earth in meters
|
|
418
|
+
* @param b - The semiminor axis of the assumed shape of Earth in meters
|
|
410
419
|
* @returns
|
|
411
420
|
*/
|
|
412
|
-
static fromLLCornerLonLat(ni, nj, lon_0, lat_0, lat_std, ll_lon, ll_lat, dx, dy) {
|
|
413
|
-
|
|
421
|
+
static fromLLCornerLonLat(ni, nj, lon_0, lat_0, lat_std, ll_lon, ll_lat, dx, dy, a, b) {
|
|
422
|
+
a = a === undefined ? WGS84_SEMIMAJOR : a;
|
|
423
|
+
b = b === undefined ? WGS84_SEMIMINOR : b;
|
|
424
|
+
const lcc = lambertConformalConic({ lon_0: lon_0, lat_0: lat_0, lat_std: lat_std, a: a, b: b });
|
|
414
425
|
const [ll_x, ll_y] = lcc(ll_lon, ll_lat);
|
|
415
|
-
return new LambertGrid(ni, nj, lon_0, lat_0, lat_std, ll_x, ll_y, ll_x + ni * dx, ll_y + nj * dy);
|
|
426
|
+
return new LambertGrid(ni, nj, lon_0, lat_0, lat_std, ll_x, ll_y, ll_x + ni * dx, ll_y + nj * dy, a, b);
|
|
416
427
|
}
|
|
417
428
|
/** @internal */
|
|
418
429
|
copy(opts) {
|
|
@@ -423,7 +434,7 @@ class LambertGrid extends StructuredGrid {
|
|
|
423
434
|
const ll_y = opts.ll_y !== undefined ? opts.ll_y : this.ll_y;
|
|
424
435
|
const ur_x = opts.ur_x !== undefined ? opts.ur_x : this.ur_x;
|
|
425
436
|
const ur_y = opts.ur_y !== undefined ? opts.ur_y : this.ur_y;
|
|
426
|
-
return new LambertGrid(ni, nj, this.lon_0, this.lat_0, this.lat_std, ll_x, ll_y, ur_x, ur_y);
|
|
437
|
+
return new LambertGrid(ni, nj, this.lon_0, this.lat_0, this.lat_std, ll_x, ll_y, ur_x, ur_y, this.a, this.b);
|
|
427
438
|
}
|
|
428
439
|
/**
|
|
429
440
|
* @internal
|
|
@@ -457,10 +468,10 @@ class LambertGrid extends StructuredGrid {
|
|
|
457
468
|
const ll_y = this.ll_y;
|
|
458
469
|
const ur_x = this.ur_x - ni_remove * dx;
|
|
459
470
|
const ur_y = this.ur_y - nj_remove * dy;
|
|
460
|
-
return new LambertGrid(ni, nj, this.lon_0, this.lat_0, this.lat_std, ll_x, ll_y, ur_x, ur_y, this.thin_x * thin_x, this.thin_y * thin_y);
|
|
471
|
+
return new LambertGrid(ni, nj, this.lon_0, this.lat_0, this.lat_std, ll_x, ll_y, ur_x, ur_y, this.a, this.b, this.thin_x * thin_x, this.thin_y * thin_y);
|
|
461
472
|
}
|
|
462
473
|
}
|
|
463
|
-
/** An unstructured grid */
|
|
474
|
+
/** An unstructured grid defined by a list of latitudes and longitudes */
|
|
464
475
|
class UnstructuredGrid extends Grid {
|
|
465
476
|
/**
|
|
466
477
|
* Create an unstructured grid
|
|
@@ -544,4 +555,46 @@ class UnstructuredGrid extends Grid {
|
|
|
544
555
|
return { sample: ary[idx], sample_lon: this.coords[idx].lon, sample_lat: this.coords[idx].lat };
|
|
545
556
|
}
|
|
546
557
|
}
|
|
558
|
+
// class GeostationaryImage extends Grid {
|
|
559
|
+
// public readonly satellite_lon: number;
|
|
560
|
+
// public readonly satellite_lat: number;
|
|
561
|
+
// private readonly vpp: (a: number, b: number, opts?: {inverse: boolean}) => [number, number];
|
|
562
|
+
// constructor(ni: number, nj: number, satellite_lon: number, satellite_lat: number) {
|
|
563
|
+
// super('geostationary', false, ni, nj);
|
|
564
|
+
// this.satellite_lon = satellite_lon;
|
|
565
|
+
// this.satellite_lat = satellite_lat;
|
|
566
|
+
// this.vpp = verticalPerspective({lon_0: satellite_lon, lat_0: satellite_lat, alt: 35786000.});
|
|
567
|
+
// }
|
|
568
|
+
// public getEarthCoords(): EarthCoords {}
|
|
569
|
+
// public getGridCoords(): GridCoords {}
|
|
570
|
+
// public transform(x: number, y: number, opts?: {inverse?: boolean}): [number, number] {
|
|
571
|
+
// opts = opts === undefined ? {}: opts;
|
|
572
|
+
// const inverse = opts.inverse === undefined ? false : opts.inverse;
|
|
573
|
+
// return this.vpp(x, y, {inverse: inverse});
|
|
574
|
+
// }
|
|
575
|
+
// public sampleNearestGridPoint(lon: number, lat: number, ary: TypedArray): {sample: number, sample_lon: number, sample_lat: number} {
|
|
576
|
+
// const [x, y] = this.transform(lon, lat);
|
|
577
|
+
// const {x: xs, y: ys} = this.getGridCoords();
|
|
578
|
+
// const ll_x = xs[0];
|
|
579
|
+
// const ur_x = xs[xs.length - 1];
|
|
580
|
+
// const dx = xs[1] - xs[0];
|
|
581
|
+
// const ll_y = ys[0];
|
|
582
|
+
// const ur_y = ys[ys.length - 1];
|
|
583
|
+
// const dy = ys[1] - ys[0];
|
|
584
|
+
// if (x < ll_x - 0.5 * dx || x > ur_x + 0.5 * dx || y < ll_y - 0.5 * dy || y > ur_y + 0.5 * dy) {
|
|
585
|
+
// return {sample: NaN, sample_lon: NaN, sample_lat: NaN};
|
|
586
|
+
// }
|
|
587
|
+
// const i_min = argMin(xs.map(xv => Math.abs(xv - x)));
|
|
588
|
+
// const j_min = argMin(ys.map(yv => Math.abs(yv - y)));
|
|
589
|
+
// const idx = i_min + j_min * this.ni;
|
|
590
|
+
// const [lon_min, lat_min] = this.transform(xs[i_min], ys[j_min], {inverse: true});
|
|
591
|
+
// return {sample: ary[idx], sample_lon: lon_min, sample_lat: lat_min};
|
|
592
|
+
// }
|
|
593
|
+
// public getThinnedGrid(thin_fac: number, map_max_zoom: number): Grid {}
|
|
594
|
+
// public thinDataArray<ArrayType extends TypedArray>(original_grid: Grid, ary: ArrayType): ArrayType {}
|
|
595
|
+
// public getMinVisibleZoom(thin_fac: number): Uint8Array {}
|
|
596
|
+
// public copy() {
|
|
597
|
+
// return new GeostationaryImage(this.ni, this.nj, this.satellite_lon, this.satellite_lat);
|
|
598
|
+
// }
|
|
599
|
+
// }
|
|
547
600
|
export { Grid, StructuredGrid, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid, UnstructuredGrid };
|
package/lib/Hodographs.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { RawProfileField } from "./RawField";
|
|
|
4
4
|
import { RenderMethodArg, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
5
5
|
import { ColorMap } from "./Colormap";
|
|
6
6
|
import { Grid } from "./Grid";
|
|
7
|
+
/** Options for {@link Hodographs} components */
|
|
7
8
|
interface HodographOptions {
|
|
8
9
|
/**
|
|
9
10
|
* The color of the hodograph plot background as a hex string
|
|
@@ -30,6 +31,11 @@ interface HodographOptions {
|
|
|
30
31
|
* The colormap to use for the heights on the hodograph. Default is a yellow-blue colormap.
|
|
31
32
|
*/
|
|
32
33
|
height_cmap?: ColorMap;
|
|
34
|
+
/**
|
|
35
|
+
* The wind speed (in kts) of the largest ring on the hodograph background
|
|
36
|
+
* @default 80
|
|
37
|
+
*/
|
|
38
|
+
max_wind_speed_ring?: number;
|
|
33
39
|
}
|
|
34
40
|
/** A class representing a field of hodograph plots */
|
|
35
41
|
declare class Hodographs<GridType extends Grid, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
package/lib/Hodographs.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import { PolylineCollection } from "./PolylineCollection";
|
|
3
3
|
import { BillboardCollection } from "./BillboardCollection";
|
|
4
|
-
import {
|
|
4
|
+
import { normalizeOptions } from './utils';
|
|
5
|
+
import { isStormRelativeWindProfile } from "./AutumnTypes";
|
|
5
6
|
import { ColorMap } from "./Colormap";
|
|
6
7
|
import { Color } from "./Color";
|
|
7
8
|
const LINE_WIDTH_MULTIPLIER = 2.5;
|
|
8
|
-
const BG_MAX_RING_MAG = 40;
|
|
9
9
|
const HODO_BG_DIMS = {
|
|
10
10
|
BB_WIDTH: 256,
|
|
11
11
|
BB_HEIGHT: 256,
|
|
@@ -15,7 +15,7 @@ const HODO_BG_DIMS = {
|
|
|
15
15
|
BB_MAG_WRAP: 1000,
|
|
16
16
|
BB_MAG_BIN_SIZE: 1000,
|
|
17
17
|
};
|
|
18
|
-
function _createHodoBackgroundTexture(line_width) {
|
|
18
|
+
function _createHodoBackgroundTexture(line_width, arrow_head) {
|
|
19
19
|
let canvas = document.createElement('canvas');
|
|
20
20
|
canvas.width = HODO_BG_DIMS.BB_TEX_WIDTH;
|
|
21
21
|
canvas.height = HODO_BG_DIMS.BB_TEX_HEIGHT;
|
|
@@ -29,14 +29,21 @@ function _createHodoBackgroundTexture(line_width) {
|
|
|
29
29
|
ctx.arc(HODO_BG_DIMS.BB_TEX_WIDTH / 2, HODO_BG_DIMS.BB_TEX_WIDTH / 2, irng - line_width / 2, 0, 2 * Math.PI);
|
|
30
30
|
ctx.stroke();
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
if (arrow_head) {
|
|
33
|
+
const ctr_x = HODO_BG_DIMS.BB_TEX_WIDTH / 2, ctr_y = HODO_BG_DIMS.BB_TEX_WIDTH / 2;
|
|
34
|
+
const arrow_size = 20;
|
|
35
|
+
ctx.beginPath();
|
|
36
|
+
ctx.moveTo(ctr_x, ctr_y);
|
|
37
|
+
ctx.lineTo(ctr_x + arrow_size / 2, ctr_y + arrow_size);
|
|
38
|
+
ctx.lineTo(ctr_x - arrow_size / 2, ctr_y + arrow_size);
|
|
39
|
+
ctx.lineTo(ctr_x, ctr_y);
|
|
40
|
+
ctx.fill();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
ctx.beginPath();
|
|
44
|
+
ctx.arc(HODO_BG_DIMS.BB_TEX_WIDTH / 2, HODO_BG_DIMS.BB_TEX_WIDTH / 2, line_width, 0, 2 * Math.PI);
|
|
45
|
+
ctx.fill();
|
|
46
|
+
}
|
|
40
47
|
return canvas;
|
|
41
48
|
}
|
|
42
49
|
;
|
|
@@ -46,7 +53,8 @@ const hodograph_opt_defaults = {
|
|
|
46
53
|
thin_fac: 1,
|
|
47
54
|
hodo_line_width: 2.5,
|
|
48
55
|
background_line_width: 1.5,
|
|
49
|
-
height_cmap: HODO_CMAP
|
|
56
|
+
height_cmap: HODO_CMAP,
|
|
57
|
+
max_wind_speed_ring: 80
|
|
50
58
|
};
|
|
51
59
|
/** A class representing a field of hodograph plots */
|
|
52
60
|
class Hodographs extends PlotComponent {
|
|
@@ -59,8 +67,8 @@ class Hodographs extends PlotComponent {
|
|
|
59
67
|
super();
|
|
60
68
|
this.profile_field = profile_field;
|
|
61
69
|
this.opts = normalizeOptions(opts, hodograph_opt_defaults);
|
|
62
|
-
this.hodo_bg_texture = _createHodoBackgroundTexture(this.opts.background_line_width * LINE_WIDTH_MULTIPLIER);
|
|
63
|
-
this.hodo_scale = (HODO_BG_DIMS.BB_TEX_WIDTH - this.opts.background_line_width / 2) / (HODO_BG_DIMS.BB_TEX_WIDTH *
|
|
70
|
+
this.hodo_bg_texture = _createHodoBackgroundTexture(this.opts.background_line_width * LINE_WIDTH_MULTIPLIER, isStormRelativeWindProfile(profile_field.profiles[0]));
|
|
71
|
+
this.hodo_scale = (HODO_BG_DIMS.BB_TEX_WIDTH - this.opts.background_line_width / 2) / (HODO_BG_DIMS.BB_TEX_WIDTH * this.opts.max_wind_speed_ring);
|
|
64
72
|
this.bg_size = 140;
|
|
65
73
|
this.gl_elems = null;
|
|
66
74
|
this.line_elems = null;
|
|
@@ -78,19 +86,26 @@ class Hodographs extends PlotComponent {
|
|
|
78
86
|
this.gl_elems.bg_billboard.updateField(field.getStormMotionGrid());
|
|
79
87
|
const profiles = this.profile_field.profiles;
|
|
80
88
|
const { lats, lons } = this.profile_field.getProfileCoords();
|
|
89
|
+
const min_visible_zoom = this.profile_field.grid.getMinVisibleZoom(this.opts.thin_fac);
|
|
81
90
|
const hodo_polyline = profiles.map((prof, iprof) => {
|
|
82
|
-
const zoom = getMinZoom(prof['jlat'], prof['ilon'], this.opts.thin_fac);
|
|
83
91
|
return {
|
|
84
|
-
'offsets': [...prof['u']].map((u, ipt) =>
|
|
92
|
+
'offsets': [...prof['u']].map((u, ipt) => {
|
|
93
|
+
if (isStormRelativeWindProfile(prof)) {
|
|
94
|
+
return [u - prof['smu'], prof['v'][ipt] - prof['smv']];
|
|
95
|
+
}
|
|
96
|
+
return [u, prof['v'][ipt]];
|
|
97
|
+
}),
|
|
85
98
|
'vertices': [...prof['u']].map(u => [lons[iprof], lats[iprof]]),
|
|
86
|
-
'zoom':
|
|
99
|
+
'zoom': min_visible_zoom[iprof],
|
|
87
100
|
'data': [...prof['z']],
|
|
88
101
|
};
|
|
89
102
|
});
|
|
90
103
|
const hodo_line = await PolylineCollection.make(gl, hodo_polyline, { line_width: this.opts.hodo_line_width, cmap: this.opts.height_cmap,
|
|
91
104
|
offset_scale: this.hodo_scale * this.bg_size, offset_rotates_with_map: false });
|
|
92
105
|
const sm_polyline = profiles.map((prof, iprof) => {
|
|
93
|
-
|
|
106
|
+
if (!isStormRelativeWindProfile(prof)) {
|
|
107
|
+
return { vertices: [] };
|
|
108
|
+
}
|
|
94
109
|
const sm_mag = Math.hypot(prof['smu'], prof['smv']);
|
|
95
110
|
const sm_ang = Math.PI / 2 - Math.atan2(-prof['smv'], -prof['smu']);
|
|
96
111
|
const buffer = 2;
|
|
@@ -98,7 +113,7 @@ class Hodographs extends PlotComponent {
|
|
|
98
113
|
'offsets': [[buffer * Math.sin(sm_ang), buffer * Math.cos(sm_ang)],
|
|
99
114
|
[sm_mag * Math.sin(sm_ang), sm_mag * Math.cos(sm_ang)]],
|
|
100
115
|
'vertices': [[lons[iprof], lats[iprof]], [lons[iprof], lats[iprof]]],
|
|
101
|
-
'zoom':
|
|
116
|
+
'zoom': min_visible_zoom[iprof]
|
|
102
117
|
};
|
|
103
118
|
});
|
|
104
119
|
const sm_line = await PolylineCollection.make(gl, sm_polyline, { line_width: this.opts.background_line_width, color: this.opts.bgcolor,
|
package/lib/Map.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
type StyleSpecification = {
|
|
2
2
|
glyphs?: string;
|
|
3
3
|
};
|
|
4
|
+
/** Type with the required methods for mapping libraries */
|
|
4
5
|
type MapLikeType = {
|
|
5
6
|
triggerRepaint: () => void;
|
|
6
7
|
getCanvas: () => HTMLCanvasElement;
|
|
@@ -14,6 +15,8 @@ interface LambertConformalConicParameters {
|
|
|
14
15
|
lon_0: number;
|
|
15
16
|
lat_0: number;
|
|
16
17
|
lat_std: [number, number] | number;
|
|
18
|
+
a: number;
|
|
19
|
+
b: number;
|
|
17
20
|
}
|
|
18
21
|
declare function lambertConformalConic(params: LambertConformalConicParameters): (a: number, b: number, opts?: {
|
|
19
22
|
inverse: boolean;
|
|
@@ -26,6 +29,16 @@ interface RotateSphereParams {
|
|
|
26
29
|
declare function rotateSphere(params: RotateSphereParams): (a: number, b: number, opts?: {
|
|
27
30
|
inverse: boolean;
|
|
28
31
|
}) => [number, number];
|
|
32
|
+
interface VerticalPerspectiveParams {
|
|
33
|
+
lat_0: number;
|
|
34
|
+
lon_0: number;
|
|
35
|
+
alt: number;
|
|
36
|
+
a: number;
|
|
37
|
+
b: number;
|
|
38
|
+
}
|
|
39
|
+
declare function verticalPerspective(params: VerticalPerspectiveParams): (a: number, b: number, opts?: {
|
|
40
|
+
inverse: boolean;
|
|
41
|
+
}) => [number, number];
|
|
29
42
|
/**
|
|
30
43
|
* A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.
|
|
31
44
|
* These coordinates are based on the [WGS84 (EPSG:4326) standard](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84).
|
|
@@ -49,5 +62,5 @@ declare class LngLat {
|
|
|
49
62
|
};
|
|
50
63
|
static fromMercatorCoord(x: number, y: number): LngLat;
|
|
51
64
|
}
|
|
52
|
-
export { LngLat, lambertConformalConic, rotateSphere };
|
|
65
|
+
export { LngLat, lambertConformalConic, rotateSphere, verticalPerspective };
|
|
53
66
|
export type { MapLikeType };
|