autumnplot-gl 4.0.0-beta → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +13 -207
  2. package/dist/812.autumnplot-gl.js +2 -0
  3. package/dist/812.autumnplot-gl.js.map +1 -0
  4. package/dist/983.autumnplot-gl.js +2 -0
  5. package/dist/983.autumnplot-gl.js.map +1 -0
  6. package/dist/autumnplot-gl.js +1 -1
  7. package/dist/autumnplot-gl.js.map +1 -1
  8. package/dist/marchingsquares.wasm +0 -0
  9. package/lib/AutumnTypes.d.ts +38 -5
  10. package/lib/AutumnTypes.js +7 -1
  11. package/lib/Barbs.d.ts +12 -2
  12. package/lib/Barbs.js +9 -0
  13. package/lib/BillboardCollection.d.ts +2 -2
  14. package/lib/BillboardCollection.js +14 -14
  15. package/lib/Color.d.ts +1 -0
  16. package/lib/Color.js +1 -0
  17. package/lib/ColorBar.d.ts +14 -0
  18. package/lib/ColorBar.js +15 -8
  19. package/lib/Colormap.d.ts +9 -1
  20. package/lib/Colormap.js +24 -1
  21. package/lib/Contour.d.ts +26 -1
  22. package/lib/Contour.js +24 -2
  23. package/lib/ContourCreator.worker.d.ts +25 -0
  24. package/lib/{ContourCreator.js → ContourCreator.worker.js} +15 -14
  25. package/lib/Fill.d.ts +31 -11
  26. package/lib/Fill.js +38 -18
  27. package/lib/Hodographs.d.ts +19 -3
  28. package/lib/Hodographs.js +45 -20
  29. package/lib/Map.d.ts +13 -1
  30. package/lib/Map.js +62 -8
  31. package/lib/Paintball.d.ts +14 -5
  32. package/lib/Paintball.js +96 -46
  33. package/lib/PlotComponent.d.ts +9 -3
  34. package/lib/PlotComponent.js +36 -1
  35. package/lib/PlotLayer.d.ts +2 -2
  36. package/lib/PlotLayer.js +2 -2
  37. package/lib/PlotLayer.worker.js +9 -3
  38. package/lib/RawField.d.ts +223 -27
  39. package/lib/RawField.js +413 -59
  40. package/lib/StationPlot.d.ts +78 -11
  41. package/lib/StationPlot.js +113 -30
  42. package/lib/TextCollection.d.ts +5 -0
  43. package/lib/TextCollection.js +82 -9
  44. package/lib/WasmInterface.d.ts +7 -0
  45. package/lib/WasmInterface.js +11 -0
  46. package/lib/WorkerPool.d.ts +8 -0
  47. package/lib/WorkerPool.js +77 -0
  48. package/lib/cpp/marchingsquares.js +127 -13
  49. package/lib/cpp/marchingsquares.wasm +0 -0
  50. package/lib/cpp/marchingsquares_embind.d.ts +16 -3
  51. package/lib/grids/AutoZoom.d.ts +21 -0
  52. package/lib/grids/AutoZoom.js +63 -0
  53. package/lib/grids/DomainBuffer.d.ts +14 -0
  54. package/lib/grids/DomainBuffer.js +16 -0
  55. package/lib/grids/Geostationary.d.ts +35 -0
  56. package/lib/grids/Geostationary.js +47 -0
  57. package/lib/grids/Grid.d.ts +36 -0
  58. package/lib/grids/Grid.js +12 -0
  59. package/lib/grids/GridCoordinates.d.ts +10 -0
  60. package/lib/grids/GridCoordinates.js +64 -0
  61. package/lib/grids/LambertGrid.d.ts +73 -0
  62. package/lib/grids/LambertGrid.js +92 -0
  63. package/lib/grids/PlateCarreeGrid.d.ts +46 -0
  64. package/lib/grids/PlateCarreeGrid.js +55 -0
  65. package/lib/grids/PlateCarreeRotatedGrid.d.ts +53 -0
  66. package/lib/grids/PlateCarreeRotatedGrid.js +65 -0
  67. package/lib/grids/RadarSweepGrid.d.ts +46 -0
  68. package/lib/grids/RadarSweepGrid.js +74 -0
  69. package/lib/grids/StructuredGrid.d.ts +49 -0
  70. package/lib/grids/StructuredGrid.js +103 -0
  71. package/lib/grids/UnstructuredGrid.d.ts +56 -0
  72. package/lib/grids/UnstructuredGrid.js +102 -0
  73. package/lib/index.d.ts +23 -6
  74. package/lib/index.js +18 -8
  75. package/lib/utils.d.ts +11 -2
  76. package/lib/utils.js +63 -1
  77. package/package.json +4 -3
  78. package/dist/110.autumnplot-gl.js +0 -2
  79. package/dist/110.autumnplot-gl.js.map +0 -1
  80. package/lib/ContourCreator.d.ts +0 -22
  81. package/lib/Grid.d.ts +0 -263
  82. package/lib/Grid.js +0 -547
  83. package/lib/ParticleTracer.d.ts +0 -19
  84. package/lib/ParticleTracer.js +0 -37
Binary file
@@ -1,13 +1,37 @@
1
1
  import { Float16Array } from "@petamoriken/float16";
2
- interface WindProfile {
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,19 @@ 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;
35
- type TypedArray = Float16Array | Float32Array | Uint8Array;
36
- type TypedArrayStr = 'float16' | 'float32' | 'uint8';
60
+ /** Javascript typed arrays for use in raw fields */
61
+ type TypedArray = Float16Array | Float32Array | Uint8Array | Uint16Array | Uint32Array | Int16Array | Int32Array;
62
+ type TypedArrayStr = 'float16' | 'float32' | 'uint8' | 'uint16' | 'uint32' | 'int16' | 'int32';
63
+ type ContourableTypedArray = Float16Array | Float32Array;
64
+ declare function isContourable(ary: any): ary is ContourableTypedArray;
65
+ /**
66
+ * The result of contouring a field
67
+ *
68
+ * Each property is a different contour level giving an array of contours, and each contour is an array of [longitude, latitude].
69
+ */
37
70
  type ContourData = Record<number, [number, number][][]>;
38
71
  type mat4 = number[] | Float32Array | Float64Array;
39
72
  type RenderShaderData = {
@@ -84,5 +117,5 @@ type RendererDataAutumn = {
84
117
  };
85
118
  type RendererData = RendererDataMapLibre | RendererDataAutumn;
86
119
  declare function getRendererData(arg: RenderMethodArg): RendererData;
87
- export { isWebGL2Ctx, getRendererData };
88
- export type { WindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourData, RenderMethodArg, RendererData, RenderShaderData };
120
+ export { isWebGL2Ctx, isContourable, getRendererData, isStormRelativeWindProfile };
121
+ export type { WindProfile, StormRelativeWindProfile, GroundRelativeWindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourableTypedArray, ContourData, RenderMethodArg, RendererData, RenderShaderData };
@@ -1,6 +1,12 @@
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
  }
7
+ function isContourable(ary) {
8
+ return ary instanceof Uint16Array || ary instanceof Float32Array;
9
+ }
4
10
  function isMapLibreRenderArg(obj) {
5
11
  return 'modelViewProjectionMatrix' in obj && 'defaultProjectionData' in obj && 'mainMatrix' in obj.defaultProjectionData;
6
12
  }
@@ -25,4 +31,4 @@ function getRendererData(arg) {
25
31
  }
26
32
  return { type: 'autumn', mainMatrix: [...arg], shaderData: null };
27
33
  }
28
- export { isWebGL2Ctx, getRendererData };
34
+ export { isWebGL2Ctx, isContourable, getRendererData, isStormRelativeWindProfile };
package/lib/Barbs.d.ts CHANGED
@@ -3,7 +3,8 @@ import { RawVectorField } from "./RawField";
3
3
  import { MapLikeType } from "./Map";
4
4
  import { RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
5
5
  import { ColorMap } from "./Colormap";
6
- import { Grid } from "./Grid";
6
+ import { AutoZoomGrid } from "./grids/AutoZoom";
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;.
@@ -34,12 +35,21 @@ interface BarbsOptions {
34
35
  /**
35
36
  * 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
36
37
  * thinning factor at zoom level 1.
38
+ *
39
+ * ## Grid Compatibility
40
+ * - :white_check_mark: `PlateCarreeGrid`
41
+ * - :white_check_mark: `PlateCarreeRotatedGrid`
42
+ * - :white_check_mark: `LambertGrid`
43
+ * - :white_check_mark: `UnstructuredGrid`
44
+ * - :x: `RadarSweepGrid`
45
+ * - :x: `Geostationary`
46
+ *
37
47
  * @example
38
48
  * // Create a barb field with black barbs and plotting every 16th wind barb in both i and j at zoom level 1
39
49
  * const vector_field = new RawVectorField(grid, u_data, v_data);
40
50
  * const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
41
51
  */
42
- declare class Barbs<ArrayType extends TypedArray, GridType extends Grid, MapType extends MapLikeType> extends PlotComponent<MapType> {
52
+ declare class Barbs<ArrayType extends TypedArray, GridType extends AutoZoomGrid, MapType extends MapLikeType> extends PlotComponent<MapType> {
43
53
  /** The vector field */
44
54
  private fields;
45
55
  readonly opts: Required<BarbsOptions>;
package/lib/Barbs.js CHANGED
@@ -108,6 +108,15 @@ const barb_opt_defaults = {
108
108
  /**
109
109
  * 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
110
110
  * thinning factor at zoom level 1.
111
+ *
112
+ * ## Grid Compatibility
113
+ * - :white_check_mark: `PlateCarreeGrid`
114
+ * - :white_check_mark: `PlateCarreeRotatedGrid`
115
+ * - :white_check_mark: `LambertGrid`
116
+ * - :white_check_mark: `UnstructuredGrid`
117
+ * - :x: `RadarSweepGrid`
118
+ * - :x: `Geostationary`
119
+ *
111
120
  * @example
112
121
  * // Create a barb field with black barbs and plotting every 16th wind barb in both i and j at zoom level 1
113
122
  * const vector_field = new RawVectorField(grid, u_data, v_data);
@@ -1,7 +1,7 @@
1
1
  import { BillboardSpec, RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
2
2
  import { Color } from "./Color";
3
3
  import { ColorMap } from "./Colormap";
4
- import { Grid } from "./Grid";
4
+ import { AutoZoomGrid } from "./grids/AutoZoom";
5
5
  import { RawVectorField } from "./RawField";
6
6
  import { WGLTextureSpec } from "autumn-wgl";
7
7
  interface BillboardCollectionOpts {
@@ -9,7 +9,7 @@ interface BillboardCollectionOpts {
9
9
  cmap?: ColorMap;
10
10
  rotate_with_map?: boolean;
11
11
  }
12
- declare class BillboardCollection<ArrayType extends TypedArray, GridType extends Grid> {
12
+ declare class BillboardCollection<ArrayType extends TypedArray, GridType extends AutoZoomGrid> {
13
13
  private field;
14
14
  readonly spec: BillboardSpec;
15
15
  readonly color: Color;
@@ -3,6 +3,7 @@ import { Color } from "./Color";
3
3
  import { ColorMapGPUInterface } from "./Colormap";
4
4
  import { WGLBuffer, WGLTexture } from "autumn-wgl";
5
5
  import { ShaderProgramManager } from "./ShaderManager";
6
+ import { applySamplerCodeVector } from "./utils";
6
7
  const billboard_vertex_shader_src = `#version 300 es
7
8
 
8
9
  uniform int u_offset;
@@ -19,8 +20,6 @@ uniform highp float u_bb_mag_bin_size;
19
20
  uniform highp float u_bb_mag_wrap;
20
21
  uniform int u_rotate_with_map;
21
22
 
22
- uniform sampler2D u_u_sampler;
23
- uniform sampler2D u_v_sampler;
24
23
  uniform sampler2D u_rot_sampler;
25
24
 
26
25
  out highp vec2 v_tex_coord;
@@ -77,8 +76,8 @@ void main() {
77
76
  vec2 data_texcoord = a_tex_coord;
78
77
  data_texcoord.x = fract(data_texcoord.x);
79
78
 
80
- highp float u = texture(u_u_sampler, data_texcoord).r;
81
- highp float v = texture(u_v_sampler, data_texcoord).r;
79
+ highp float u = get_field_value_u(data_texcoord);
80
+ highp float v = get_field_value_v(data_texcoord);
82
81
  highp float rot = texture(u_rot_sampler, data_texcoord).r;
83
82
 
84
83
  lowp float bb_aspect = u_bb_width / u_bb_height;
@@ -168,14 +167,7 @@ class BillboardCollection {
168
167
  return;
169
168
  const gl = this.gl_elems.gl;
170
169
  const data = this.field.getThinnedField(this.thin_fac, this.max_zoom);
171
- const { u: u_image, v: v_image } = data.getWGLTextureSpecs(gl, gl.NEAREST);
172
- if (this.wind_textures === null) {
173
- this.wind_textures = { u: new WGLTexture(gl, u_image), v: new WGLTexture(gl, v_image) };
174
- }
175
- else {
176
- this.wind_textures.u.setImageData(u_image);
177
- this.wind_textures.v.setImageData(v_image);
178
- }
170
+ this.wind_textures = data.updateTexImageData(gl, gl.NEAREST, this.wind_textures);
179
171
  }
180
172
  async setup(gl) {
181
173
  const thinned_grid = this.field.grid.getThinnedGrid(this.thin_fac, this.max_zoom);
@@ -193,7 +185,10 @@ class BillboardCollection {
193
185
  cmap_gpu.setupShaderVariables(gl, gl.NEAREST);
194
186
  shader_defines.push('COLORMAP');
195
187
  }
196
- const shader_manager = new ShaderProgramManager(billboard_vertex_shader_src, fragment_src, shader_defines);
188
+ const sampler_keys = this.field.getSamplerIds();
189
+ const sampler_expressions = this.field.getExpressions();
190
+ const vertex_shader_src = applySamplerCodeVector(billboard_vertex_shader_src, sampler_keys, sampler_expressions);
191
+ const shader_manager = new ShaderProgramManager(vertex_shader_src, fragment_src, shader_defines);
197
192
  this.gl_elems = { gl: gl, shader_manager: shader_manager, geom_vertices: geom_buffer, vertices: vertices, texcoords: texcoords, texture: texture,
198
193
  proj_rot_texture: proj_rotation_tex, cmap_gpu: cmap_gpu };
199
194
  }
@@ -206,10 +201,15 @@ class BillboardCollection {
206
201
  const bb_size = this.spec.BB_HEIGHT * (map_height / map_width) * this.size_multiplier;
207
202
  const bb_width = this.spec.BB_WIDTH / this.spec.BB_TEX_WIDTH;
208
203
  const bb_height = this.spec.BB_HEIGHT / this.spec.BB_TEX_HEIGHT;
204
+ const samplers = {
205
+ 'u_sampler': gl_elems.texture, 'u_rot_sampler': gl_elems.proj_rot_texture,
206
+ ...Object.fromEntries([...this.wind_textures.u.entries()]),
207
+ ...Object.fromEntries([...this.wind_textures.v.entries()])
208
+ };
209
209
  program.use({ 'a_geom': gl_elems.geom_vertices, 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_bb_size': bb_size, 'u_bb_width': bb_width, 'u_bb_height': bb_height,
210
210
  'u_bb_mag_bin_size': this.spec.BB_MAG_BIN_SIZE, 'u_bb_mag_wrap': this.spec.BB_MAG_WRAP, 'u_offset': 0,
211
211
  'u_map_aspect': map_height / map_width, 'u_zoom': map_zoom, 'u_rotate_with_map': this.rotate_with_map ? 1 : 0,
212
- ...this.gl_elems.shader_manager.getShaderUniforms(render_data) }, { 'u_sampler': gl_elems.texture, 'u_u_sampler': this.wind_textures.u, 'u_v_sampler': this.wind_textures.v, 'u_rot_sampler': gl_elems.proj_rot_texture });
212
+ ...this.gl_elems.shader_manager.getShaderUniforms(render_data) }, samplers);
213
213
  if (gl_elems.cmap_gpu !== null) {
214
214
  gl_elems.cmap_gpu.bindShaderVariables(program);
215
215
  }
package/lib/Color.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /** A class for handling colors and translations between different color spaces */
1
2
  declare class Color {
2
3
  private rgba;
3
4
  /**
package/lib/Color.js CHANGED
@@ -78,6 +78,7 @@ const hsv2rgb = (hsv) => {
78
78
  }
79
79
  return [r_prime + m, g_prime + m, b_prime + m];
80
80
  };
81
+ /** A class for handling colors and translations between different color spaces */
81
82
  class Color {
82
83
  /**
83
84
  * Create a new color object
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 makeColorBar} */
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,12 +64,18 @@ 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
62
71
  * @default 1
63
72
  */
64
73
  n_cols?: number;
74
+ /**
75
+ * The space allocated for the text for each color swatch in pixels
76
+ * @default 100
77
+ */
78
+ swatch_text_space?: number;
65
79
  /**
66
80
  * A font face to use for the label and tick values.
67
81
  * @default 'sans-serif'
package/lib/ColorBar.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { normalizeOptions } from "./utils";
1
2
  ;
2
3
  const createElement = (tagname, attributes, parent) => {
3
4
  const elem = document.createElementNS('http://www.w3.org/2000/svg', tagname);
@@ -32,6 +33,7 @@ function makeColorBar(colormap, opts) {
32
33
  const tickfontsize = opts.ticklabelsize || 12;
33
34
  const size_long = opts.size_long || 600;
34
35
  const size_short = opts.size_short || size_long / 9;
36
+ const outline_and_text_color = opts.outline_and_text_color || '#000000';
35
37
  const tick_dir = opts.tick_direction || (orientation == 'vertical' ? 'left' : 'bottom');
36
38
  if (orientation == 'vertical' && (tick_dir == 'top' || tick_dir == 'bottom') ||
37
39
  orientation == 'horizontal' && (tick_dir == 'left' || tick_dir == 'right')) {
@@ -143,7 +145,7 @@ function makeColorBar(colormap, opts) {
143
145
  else {
144
146
  lineattrs = tick_dir == 'bottom' ? { y2: 6 } : { y2: -6 };
145
147
  }
146
- createElement('line', { ...lineattrs, stroke: '#000000', 'stroke-width': 1.5 }, gtick);
148
+ createElement('line', { ...lineattrs, stroke: outline_and_text_color, 'stroke-width': 1.5 }, gtick);
147
149
  let textattrs;
148
150
  if (orientation == 'vertical') {
149
151
  textattrs = tick_dir == 'left' ? { x: -9, dy: '0.32em' } : { x: 9, dy: '0.32em' };
@@ -151,7 +153,7 @@ function makeColorBar(colormap, opts) {
151
153
  else {
152
154
  textattrs = tick_dir == 'bottom' ? { y: 9, dy: '0.8em' } : { y: -9, dy: '0em' };
153
155
  }
154
- const text = createElement('text', { ...textattrs, fill: '#000000', style: `font-family: ${fontface}; font-size: ${tickfontsize}pt` }, gtick);
156
+ const text = createElement('text', { ...textattrs, fill: outline_and_text_color, style: `font-family: ${fontface}; font-size: ${tickfontsize}pt` }, gtick);
155
157
  text.textContent = level.toString();
156
158
  });
157
159
  // Draw the outline
@@ -166,7 +168,7 @@ function makeColorBar(colormap, opts) {
166
168
  }
167
169
  const outline_attrs = {
168
170
  points: point_list,
169
- stroke: '#000000',
171
+ stroke: outline_and_text_color,
170
172
  'stroke-width': 1.5,
171
173
  fill: 'none'
172
174
  };
@@ -179,10 +181,15 @@ function makeColorBar(colormap, opts) {
179
181
  else {
180
182
  labelattrs = tick_dir == 'bottom' ? { transform: `translate(${width / 2}, ${height - 5})` } : { transform: `translate(${width / 2}, 15)` };
181
183
  }
182
- const label_elem = createElement('text', { ...labelattrs, fill: '#000000', 'text-anchor': 'middle', style: `font-family: ${fontface};` }, root);
184
+ const label_elem = createElement('text', { ...labelattrs, fill: outline_and_text_color, 'text-anchor': 'middle', style: `font-family: ${fontface};` }, root);
183
185
  label_elem.textContent = label;
184
186
  return root;
185
187
  }
188
+ const paintball_key_opt_defaults = {
189
+ n_cols: 1,
190
+ swatch_text_space: 100,
191
+ fontface: 'sans-serif',
192
+ };
186
193
  /**
187
194
  * Make an SVG containing a color key for a paintball plot. The key can be split over any number of columns.
188
195
  * @param colors - A list of colors
@@ -200,16 +207,16 @@ function makePaintballKey(colors, labels, opts) {
200
207
  if (colors.length != labels.length) {
201
208
  throw `Mismatch between the number of colors (${colors.length}) and the number of labels (${labels.length})`;
202
209
  }
203
- opts = opts === undefined ? {} : opts;
204
- const n_cols = opts.n_cols === undefined ? 1 : opts.n_cols;
205
- const fontface = opts.fontface === undefined ? 'sans-serif' : opts.fontface;
210
+ const opts_ = normalizeOptions(opts, paintball_key_opt_defaults);
206
211
  let height, width;
207
212
  const swatch_width = 20;
208
213
  const swatch_height = 20;
209
214
  const swatch_text_pad = 3;
210
- const swatch_text_space = 100;
215
+ const swatch_text_space = opts_.swatch_text_space;
211
216
  const swatch_width_pad = 5;
212
217
  const swatch_height_pad = 5;
218
+ const n_cols = opts_.n_cols;
219
+ const fontface = opts_.fontface;
213
220
  const n_rows = Math.ceil(colors.length / n_cols);
214
221
  width = (swatch_width + swatch_text_pad + swatch_text_space) * n_cols + swatch_width_pad * (n_cols + 1);
215
222
  height = swatch_height * n_rows + swatch_height_pad * (n_rows + 1);
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;
@@ -28,6 +29,12 @@ declare class ColorMap {
28
29
  * @returns an array of opacities, one for each color in the color map
29
30
  */
30
31
  getOpacities(): number[];
32
+ /**
33
+ * Sample from the color map
34
+ * @param val - The value to sample from the color map
35
+ * @returns A color as an RGBA hex string
36
+ */
37
+ getColor(val: number): string;
31
38
  /**
32
39
  * Make a new color map with different opacities. The opacities are set by func.
33
40
  * @param func - A function which takes the two levels associated with a color (an upper and lower bound) and returns an opacity in the range from 0 to 1.
@@ -51,6 +58,7 @@ declare const pw_cape: ColorMap;
51
58
  declare const pw_t2m: ColorMap;
52
59
  declare const pw_td2m: ColorMap;
53
60
  declare const nws_storm_clear_refl: ColorMap;
61
+ declare const wv_cimss: ColorMap;
54
62
  /**
55
63
  * Create a diverging red/blue colormap, where red corresponds to the lowest value and blue corresponds to the highest value
56
64
  * @param level_min - The lowest value in the color map
@@ -79,5 +87,5 @@ declare class ColorMapGPUInterface {
79
87
  setupShaderVariables(gl: WebGLAnyRenderingContext, mag_filter: number): void;
80
88
  bindShaderVariables(program: WGLProgram): void;
81
89
  }
82
- export { ColorMap, ColorMapGPUInterface, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl };
90
+ export { ColorMap, ColorMapGPUInterface, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl, wv_cimss };
83
91
  export type { ColorMapOptions };
package/lib/Colormap.js CHANGED
@@ -4,6 +4,7 @@ const cape_colormap_data = { "levels": [0, 100, 200, 300, 400, 500, 600, 700
4
4
  const t2m_colormap_data = { "levels": [-60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120], "colors": [ "#235877", "#2a5f7c", "#316782", "#396e87", "#40768c", "#477d91", "#4e8497", "#558c9c", "#5d93a1", "#649ba6", "#6ba2ac", "#72a9b1", "#79b1b6", "#81b8bb", "#88c0c1", "#8fc7c6", "#96cecb", "#9dd6d0", "#a5ddd6", "#ace5db", "#b3ece0", "#b3ece0", "#b1e7df", "#b0e1dd", "#aedcdc", "#add7da", "#abd2d9", "#aaccd8", "#a8c7d6", "#a7c2d5", "#a5bcd4", "#a4b7d2", "#a2b2d1", "#9fa7ce", "#9ea2cd", "#9c9dcb", "#9c9dcb", "#9b97ca", "#9992c8", "#988dc7", "#9688c6", "#9582c4", "#9278c2", "#9073c0", "#8f6dbf", "#8d68bd", "#8c63bc", "#8a5dbb", "#8958b9", "#8753b8", "#864eb6", "#8448b5", "#8343b4", "#813eb2", "#8038b1", "#7e33b0", "#7d33ae", "#7b29ad", "#7a23ab", "#781eaa", "#a037af", "#a443b3", "#a74fb7", "#ab5cbb", "#af68bf", "#b374c3", "#b680c7", "#ba8dcc", "#be99d0", "#c1a5d4", "#c5b1d8", "#c9bddc", "#cdcae0", "#d0d6e4", "#d4e2e8", "#deecf2", "#d1e2ee", "#c5d9ea", "#b8cfe6", "#acc5e3", "#9fbbdf", "#92b2db", "#86a8d7", "#799ed3", "#6c94cf", "#608bcb", "#5381c7", "#4777c4", "#3a6dc0", "#2d64bc", "#215ab8", "#1450b4", "#0f4455", "#1c4e5a", "#2a585f", "#376363", "#456d68", "#52776d", "#5f8172", "#6d8c77", "#7a967c", "#88a080", "#95aa85", "#a3b58a", "#b0bf8f", "#bdc994", "#cbd399", "#d8de9d", "#e6e8a2", "#f3f2a7", "#f8eea2", "#f0e199", "#e8d591", "#e1c888", "#d9bc80", "#d1af77", "#c9a36f", "#c19666", "#ba8a5e", "#b27d55", "#aa714d", "#a26444", "#9b583c", "#8b3f2b", "#833222", "#7b261a", "#7b261a", "#741911", "#6c0d09", "#640000", "#5f0000", "#630507", "#670a0e", "#6c0f15", "#70141c", "#741824", "#781d2b", "#7d2232", "#812739", "#852c40", "#73372d", "#7a4036", "#80493f", "#875349", "#8e5c52", "#94655b", "#9b6e64", "#a88177", "#af8a80", "#b69389", "#bd9c92", "#c3a69c", "#caafa5", "#d1b8ae", "#d7c1b7", "#decac0", "#e5d4ca", "#ebddd3", "#f2e6dc", "#e8dfd6", "#e0d7cf", "#d8d0c8", "#d0c8c0", "#c8c0b9", "#c0b9b2", "#b7b1ab", "#afa9a4", "#a7a29c", "#9f9a95", "#97938e", "#8f8b87", "#878380", "#7f7c78", "#777471", "#6f6c6a", "#666563", "#5e5d5c", "#565554", "#4e4e4d", "#464646" ] }
5
5
  const td2m_colormap_data = { "levels": [-40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90], "colors": [ "#986d4d", "#966c4c", "#946b4c", "#926a4b", "#90694b", "#8e684a", "#8c664a", "#8a6549", "#886448", "#866348", "#846247", "#826147", "#806046", "#7e5f46", "#7c5e45", "#7a5d44", "#785b44", "#765a43", "#745943", "#725842", "#715742", "#6f5641", "#6d5540", "#6b5440", "#69533f", "#67523f", "#65503e", "#634f3d", "#614e3d", "#5f4d3c", "#5d4c3c", "#5b4b3b", "#594a3b", "#57493a", "#554839", "#534739", "#514538", "#4f4438", "#4d4337", "#4b4237", "#494136", "#4d4334", "#514738", "#564c3c", "#5a5041", "#5e5545", "#625949", "#675e4d", "#6b6251", "#6f6755", "#746b5a", "#78705e", "#7c7462", "#807966", "#857d6a", "#89826f", "#8d8673", "#928b77", "#968f7b", "#9a947f", "#9e9883", "#a39d88", "#a7a18c", "#aba690", "#afaa94", "#b8b39c", "#b8b39c", "#bcb8a1", "#c1bca5", "#c9c5ad", "#c9cab1", "#d2ceb6", "#d2ceb6", "#d6d3ba", "#dfdcc2", "#e3e0c6", "#e7e5ca", "#ebe9cf", "#f0eed3", "#f4f2d7", "#e6f5e6", "#d7f0d7", "#c8eac8", "#b9e5b9", "#aadfaa", "#9bda9b", "#8cd48c", "#7dcf7d", "#6ec96e", "#5fc45f", "#30ae30", "#2ca32c", "#279927", "#238e23", "#1e831e", "#1a791a", "#156e15", "#116311", "#0c590c", "#084e08", "#61a3af", "#5896a0", "#508992", "#477b83", "#3e6e74", "#366166", "#2d5457", "#244648", "#1c393a", "#132c2b", "#66669a", "#605e94", "#59568e", "#534e88", "#4d4682", "#463e7c", "#403676", "#3a2e70", "#33266a", "#2d1e64", "#724071", "#784573", "#7d4b75", "#835076", "#885678", "#8e5b7a", "#93617c", "#99667d", "#9e6c7f", "#a47181" ] }
6
6
  const nws_storm_clear_refl_colormap_data = { "levels": [ -15, -14.53608247, -14.07216495, -13.60824742, -13.1443299, -12.68041237, -12.21649485, -11.75257732, -11.28865979, -10.82474227, -10.36082474, -9.89690722, -9.43298969, -8.96907216, -8.50515464, -8.04123711, -7.57731959, -7.11340206, -6.64948454, -6.18556701, -5.72164948, -5.25773196, -4.79381443, -4.32989691, -3.86597938, -3.40206186, -2.93814433, -2.4742268, -2.01030928, -1.54639175, -1.08247423, -0.6185567, -0.15463918, 0.30927835, 0.77319588, 1.2371134, 1.70103093, 2.16494845, 2.62886598, 3.09278351, 3.55670103, 4.02061856, 4.48453608, 4.94845361, 5.41237113, 5.87628866, 6.34020619, 6.80412371, 7.26804124, 7.73195876, 8.19587629, 8.65979381, 9.12371134, 9.58762887, 10.05154639, 10.51546392, 10.97938144, 11.44329897, 11.90721649, 12.37113402, 12.83505155, 13.29896907, 13.7628866, 14.22680412, 14.69072165, 15.15463918, 15.6185567, 16.08247423, 16.54639175, 17.01030928, 17.4742268, 17.93814433, 18.40206186, 18.86597938, 19.32989691, 19.79381443, 20.25773196, 20.72164948, 21.18556701, 21.64948454, 22.11340206, 22.57731959, 23.04123711, 23.50515464, 23.96907216, 24.43298969, 24.89690722, 25.36082474, 25.82474227, 26.28865979, 26.75257732, 27.21649485, 27.68041237, 28.1443299, 28.60824742, 29.07216495, 29.53608247, 30, 30.46391753, 30.92783505, 31.39175258, 31.8556701, 32.31958763, 32.78350515, 33.24742268, 33.71134021, 34.17525773, 34.63917526, 35.10309278, 35.56701031, 36.03092784, 36.49484536, 36.95876289, 37.42268041, 37.88659794, 38.35051546, 38.81443299, 39.27835052, 39.74226804, 40.20618557, 40.67010309, 41.13402062, 41.59793814, 42.06185567, 42.5257732, 42.98969072, 43.45360825, 43.91752577, 44.3814433, 44.84536082, 45.30927835, 45.77319588, 46.2371134, 46.70103093, 47.16494845, 47.62886598, 48.09278351, 48.55670103, 49.02061856, 49.48453608, 49.94845361, 50.41237113, 50.87628866, 51.34020619, 51.80412371, 52.26804124, 52.73195876, 53.19587629, 53.65979381, 54.12371134, 54.58762887, 55.05154639, 55.51546392, 55.97938144, 56.44329897, 56.90721649, 57.37113402, 57.83505155, 58.29896907, 58.7628866, 59.22680412, 59.69072165, 60.15463918, 60.6185567, 61.08247423, 61.54639175, 62.01030928, 62.4742268, 62.93814433, 63.40206186, 63.86597938, 64.32989691, 64.79381443, 65.25773196, 65.72164948, 66.18556701, 66.64948454, 67.11340206, 67.57731959, 68.04123711, 68.50515464, 68.96907216, 69.43298969, 69.89690722, 70.36082474, 70.82474227, 71.28865979, 71.75257732, 72.21649485, 72.68041237, 73.1443299, 73.60824742, 74.07216495, 74.53608247, 75 ], "colors": [ "#959052", "#979356", "#9c9a60", "#a09c64", "#a3a067", "#a8a570", "#aaa875", "#acac79", "#b1b182", "#b5b587", "#b6b88c", "#bcbd93", "#bfc199", "#c1c39c", "#c1c39c", "#c6caa5", "#cacdaa", "#cccfaf", "#cfd1b3", "#cccfb3", "#c8ccb3", "#c6c8b3", "#bfc3b3", "#bfc3b3", "#bcc1b3", "#b8bdb3", "#b5bab3", "#afb5b3", "#acb3b3", "#aaafb3", "#a7aeb3", "#a3aab3", "#a0a8b3", "#9ca5b3", "#9aa1b3", "#97a0b3", "#939cb3", "#909ab3", "#939ab5", "#8c95b3", "#8791b1", "#838eb1", "#808caf", "#7c89af", "#7785ae", "#7482ac", "#7080aa", "#6b7caa", "#6275a8", "#5e72a7", "#5e72a7", "#5b70a5", "#566da3", "#5269a3", "#4f67a1", "#4b64a1", "#4660a0", "#425d9e", "#4260a1", "#4467a5", "#486eaa", "#4975ae", "#4d7cb1", "#4f83b5", "#508aba", "#5491bf", "#5699c3", "#599ec6", "#5ba5ca", "#5daccf", "#60b3d4", "#62bad8", "#64c1db", "#67c8df", "#69cfe4", "#6ed6e8", "#67d6d6", "#60d6c4", "#59d6b3", "#52d6a1", "#4bd690", "#42d67e", "#3bd66d", "#34d65b", "#11d418", "#11d116", "#0fcd16", "#0fc816", "#0fc316", "#0fbf15", "#0fbc15", "#0fb613", "#0eb313", "#0eaf13", "#0eaa13", "#0ca511", "#0ca111", "#0c9e11", "#0c9911", "#0c950f", "#0c900f", "#0a8c0f", "#0a870f", "#0a830e", "#0a800e", "#0a7c0c", "#0a770c", "#08720c", "#086e0c", "#086b0a", "#08660a", "#08620a", "#085d08", "#1c6708", "#317208", "#467c08", "#5b8707", "#6e9107", "#839c05", "#97a805", "#acb105", "#c1bc05", "#d6c603", "#e9d103", "#ffe200", "#ffd800", "#ffd300", "#ffc800", "#ffc300", "#ffba00", "#ffb500", "#ffb000", "#ffac00", "#ffa700", "#ff9e00", "#ff9900", "#ff9300", "#ff8900", "#ff8500", "#ff7f00", "#ff0000", "#f70000", "#f00000", "#e90000", "#e20000", "#db0000", "#d40000", "#cd0000", "#c60000", "#bf0000", "#b80000", "#b10000", "#aa0000", "#a30000", "#9a0000", "#930000", "#8c0000", "#850000", "#7e0000", "#770000", "#700000", "#ffffff", "#fff4ff", "#ffe9ff", "#ffdfff", "#ffd4ff", "#ffc8ff", "#ffbdff", "#ffb3ff", "#ffa8ff", "#ff9cff", "#ff91ff", "#ff75ff", "#fb6bfd", "#f960f9", "#f656f6", "#f24bf4", "#ef3ff0", "#ed36ef", "#e92aeb", "#e61fe8", "#e416e6", "#e10ae2", "#b100ff", "#ac00fb", "#a300f6", "#9a00f4", "#9300ef", "#8700e9", "#8200e8", "#7900e2", "#7200dd", "#6900db", "#6200d6" ] }
7
+ const wv_cimss_data = { "levels": [ 164, 164.75694444, 165.51388889, 166.27083333, 167.02777778, 167.78472222, 168.54166667, 169.29861111, 170.05555556, 170.8125, 171.56944444, 172.32638889, 173.08333333, 173.84027778, 174.59722222, 175.35416667, 176.11111111, 176.86805556, 177.625, 178.38194444, 179.13888889, 179.89583333, 180.65277778, 181.40972222, 182.16666667, 182.92361111, 183.68055556, 184.4375, 185.19444444, 185.95138889, 186.70833333, 187.46527778, 188.22222222, 188.97916667, 189.73611111, 190.49305556, 191.25, 192.00694444, 192.76388889, 193.52083333, 194.27777778, 195.03472222, 195.79166667, 196.54861111, 197.30555556, 198.0625, 198.81944444, 199.57638889, 200.33333333, 201.09027778, 201.84722222, 202.60416667, 203.36111111, 204.11805556, 204.875, 205.63194444, 206.38888889, 207.14583333, 207.90277778, 208.65972222, 209.41666667, 210.17361111, 210.93055556, 211.6875, 212.44444444, 213.20138889, 213.95833333, 214.71527778, 215.47222222, 216.22916667, 216.98611111, 217.74305556, 218.5, 219.25694444, 220.01388889, 220.77083333, 221.52777778, 222.28472222, 223.04166667, 223.79861111, 224.55555556, 225.3125, 226.06944444, 226.82638889, 227.58333333, 228.34027778, 229.09722222, 229.85416667, 230.61111111, 231.36805556, 232.125, 232.88194444, 233.63888889, 234.39583333, 235.15277778, 235.90972222, 236.66666667, 237.42361111, 238.18055556, 238.9375, 239.69444444, 240.45138889, 241.20833333, 241.96527778, 242.72222222, 243.47916667, 244.23611111, 244.99305556, 245.75, 246.50694444, 247.26388889, 248.02083333, 248.77777778, 249.53472222, 250.29166667, 251.04861111, 251.80555556, 252.5625, 253.31944444, 254.07638889, 254.83333333, 255.59027778, 256.34722222, 257.10416667, 257.86111111, 258.61805556, 259.375, 260.13194444, 260.88888889, 261.64583333, 262.40277778, 263.15972222, 263.91666667, 264.67361111, 265.43055556, 266.1875, 266.94444444, 267.70138889, 268.45833333, 269.21527778, 269.97222222, 270.72916667, 271.48611111, 272.24305556, 273 ], "colors": [ "#ff0000", "#ff0800", "#ff0f00", "#ff1800", "#ff1f00", "#ff2800", "#ff2f00", "#ff3800", "#ff3f00", "#ff4800", "#ff4f00", "#ff5901", "#ff6001", "#ff6901", "#ff7001", "#ff7901", "#ff8901", "#ff9001", "#ff9901", "#ffa101", "#ffaa01", "#ffb101", "#ffba01", "#ffc101", "#ffca01", "#ffd101", "#ffda01", "#ffe201", "#ffe901", "#fff201", "#fffb03", "#f6f208", "#efeb0c", "#e6e213", "#ddda18", "#d4d11d", "#cdc823", "#c4c128", "#bcb82d", "#b3af33", "#aaa838", "#a39e3d", "#9a9744", "#918e49", "#89854f", "#827e54", "#797559", "#706d5e", "#676464", "#605d69", "#56546e", "#4f4b75", "#464279", "#3d3b7e", "#363385", "#2d2a89", "#242190", "#1c1a95", "#13119a", "#0c08a0", "#0300a5", "#0f0caa", "#1c18ae", "#2826b3", "#3433b6", "#423fbc", "#4d4bbf", "#5b59c4", "#6766c8", "#7472cd", "#807ed1", "#8c8cd6", "#9a99db", "#a5a5df", "#b3b1e4", "#bfbfe8", "#cccced", "#d8d8f0", "#e4e4f6", "#f2f2f9", "#ffffff", "#f6f9f6", "#edf4ed", "#e2efe2", "#dae9da", "#cfe4cf", "#c6dfc6", "#bdd8bd", "#b3d4b3", "#aacdaa", "#a1c8a1", "#97c397", "#8ebd8e", "#85b885", "#7cb37c", "#72ac72", "#69a869", "#60a160", "#569c56", "#4d974d", "#429142", "#3a8c3a", "#318731", "#268026", "#1d7c1d", "#137513", "#0a700a", "#016b01", "#016e07", "#01720e", "#017515", "#01791c", "#017e23", "#01822a", "#018531", "#018936", "#018e3d", "#019044", "#01954b", "#019952", "#019c59", "#01a160", "#01a567", "#01a86e", "#01ac75", "#01b17c", "#03b382", "#03b889", "#03bc90", "#03bf97", "#03c39e", "#03c8a5", "#03ccac", "#03cfb3", "#03d4ba", "#03d6c1", "#03dbc8", "#03dfcd", "#03e2d4", "#03e6db", "#03ebe2", "#03efe9", "#03f2f0", "#03f6f7" ] }
7
8
  import { Float16Array } from "@petamoriken/float16";
8
9
  import { WGLTexture } from "autumn-wgl";
9
10
  import { getGLFormatTypeAlignment } from "./PlotComponent";
@@ -67,6 +68,25 @@ class ColorMap {
67
68
  getOpacities() {
68
69
  return this.colors.map(s => s.a);
69
70
  }
71
+ /**
72
+ * Sample from the color map
73
+ * @param val - The value to sample from the color map
74
+ * @returns A color as an RGBA hex string
75
+ */
76
+ getColor(val) {
77
+ if (val < this.levels[0]) {
78
+ return this.underflow_color === null ? '#00000000' : this.underflow_color.toRGBAHex();
79
+ }
80
+ if (val > this.levels[this.levels.length - 1]) {
81
+ return this.overflow_color === null ? '#00000000' : this.overflow_color.toRGBAHex();
82
+ }
83
+ let ilev = -1;
84
+ for (ilev = 0; ilev < this.levels.length - 1; ilev++) {
85
+ if (this.levels[ilev] <= val && val < this.levels[ilev + 1])
86
+ break;
87
+ }
88
+ return this.colors[Math.min(ilev, this.levels.length - 2)].toRGBAHex();
89
+ }
70
90
  /**
71
91
  * Make a new color map with different opacities. The opacities are set by func.
72
92
  * @param func - A function which takes the two levels associated with a color (an upper and lower bound) and returns an opacity in the range from 0 to 1.
@@ -161,6 +181,8 @@ function buildColormap(cm_data, overflow) {
161
181
  }
162
182
  return new ColorMap(cm_data.levels, cm_data.colors, opts);
163
183
  }
184
+ // This was dumb. Fix this later.
185
+ wv_cimss_data.colors = wv_cimss_data.colors.reverse();
164
186
  // Some built-in colormaps
165
187
  const pw_speed500mb = buildColormap(spd500_colormap_data, 'over').withOpacity((levl, levu) => Math.min((levu - 20) / 10, 1.));
166
188
  const pw_speed850mb = buildColormap(spd850_colormap_data, 'over').withOpacity((levl, levu) => Math.min((levu - 20) / 10, 1.));
@@ -168,6 +190,7 @@ const pw_cape = buildColormap(cape_colormap_data, 'over').withOpacity((levl, lev
168
190
  const pw_t2m = buildColormap(t2m_colormap_data, 'both');
169
191
  const pw_td2m = buildColormap(td2m_colormap_data, 'both');
170
192
  const nws_storm_clear_refl = buildColormap(nws_storm_clear_refl_colormap_data, 'over');
193
+ const wv_cimss = buildColormap(wv_cimss_data, 'neither');
171
194
  /**
172
195
  * Create a diverging red/blue colormap, where red corresponds to the lowest value and blue corresponds to the highest value
173
196
  * @param level_min - The lowest value in the color map
@@ -261,4 +284,4 @@ function makeIndexMap(colormap) {
261
284
  });
262
285
  return new Float16Array(inv_cmap_norm);
263
286
  }
264
- export { ColorMap, ColorMapGPUInterface, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl };
287
+ export { ColorMap, ColorMapGPUInterface, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl, wv_cimss };
package/lib/Contour.d.ts CHANGED
@@ -4,7 +4,8 @@ import { PlotComponent } from './PlotComponent';
4
4
  import { RawScalarField } from './RawField';
5
5
  import { LineStyle } from './PolylineCollection';
6
6
  import { ColorMap } from './Colormap';
7
- import { StructuredGrid } from './Grid';
7
+ import { StructuredGrid } from './grids/StructuredGrid';
8
+ /** Options for {@link Contour} components */
8
9
  interface ContourOptions {
9
10
  /**
10
11
  * The color of the contours as a hex color string
@@ -47,6 +48,15 @@ interface ContourOptions {
47
48
  }
48
49
  /**
49
50
  * A field of contoured data.
51
+ *
52
+ * ## Grid Compatibility
53
+ * - :white_check_mark: `PlateCarreeGrid`
54
+ * - :white_check_mark: `PlateCarreeRotatedGrid`
55
+ * - :white_check_mark: `LambertGrid`
56
+ * - :x: `UnstructuredGrid`
57
+ * - :white_check_mark: `RadarSweepGrid`
58
+ * - :white_check_mark: `Geostationary`
59
+ *
50
60
  * @example
51
61
  * // Create a contoured height field, with black contours every 30 m (assuming the height field is in
52
62
  * // meters).
@@ -80,6 +90,7 @@ declare class Contour<ArrayType extends TypedArray, GridType extends StructuredG
80
90
  */
81
91
  render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg): void;
82
92
  }
93
+ /** Options for {@link ContourLabels} */
83
94
  interface ContourLabelOptions {
84
95
  /**
85
96
  * Number of decimal places to use in the contour labels
@@ -100,6 +111,12 @@ interface ContourLabelOptions {
100
111
  * URL template to use in retrieving the font data for the labels. The default is to use the template from the map style.
101
112
  */
102
113
  font_url_template?: string;
114
+ /**
115
+ * Function to format the labels from numbers to a string
116
+ * @example val => Math.round(val).toString() // Round a number before to the nearest integer before converting to a string
117
+ * @default val => val.toString()
118
+ */
119
+ label_formatter?: (val: number) => string;
103
120
  /**
104
121
  * Text color for the contour labels
105
122
  * @default '#000000'
@@ -121,6 +138,14 @@ interface ContourLabelOptions {
121
138
  */
122
139
  density?: number;
123
140
  }
141
+ /**
142
+ * Label the contours on a plot
143
+ * @example
144
+ * // Contour some data
145
+ * const contours = new Contour(height_field, {color: '#000000', interval: 30});
146
+ * // Label the contours
147
+ * const labels = new ContourLabels(contours, {text_color: '#ffffff', halo: true});
148
+ */
124
149
  declare class ContourLabels<ArrayType extends TypedArray, GridType extends StructuredGrid, MapType extends MapLikeType> extends PlotComponent<MapType> {
125
150
  private readonly contours;
126
151
  private gl_elems;
package/lib/Contour.js CHANGED
@@ -4,7 +4,7 @@ import { PolylineCollection, isLineStyle } from './PolylineCollection';
4
4
  import { TextCollection } from './TextCollection';
5
5
  import { Color } from './Color';
6
6
  import { normalizeOptions } from './utils';
7
- import { UnstructuredGrid } from './Grid';
7
+ import { UnstructuredGrid } from './grids/UnstructuredGrid';
8
8
  const contour_opt_defaults = {
9
9
  color: '#000000',
10
10
  cmap: null,
@@ -16,6 +16,15 @@ const contour_opt_defaults = {
16
16
  };
17
17
  /**
18
18
  * A field of contoured data.
19
+ *
20
+ * ## Grid Compatibility
21
+ * - :white_check_mark: `PlateCarreeGrid`
22
+ * - :white_check_mark: `PlateCarreeRotatedGrid`
23
+ * - :white_check_mark: `LambertGrid`
24
+ * - :x: `UnstructuredGrid`
25
+ * - :white_check_mark: `RadarSweepGrid`
26
+ * - :white_check_mark: `Geostationary`
27
+ *
19
28
  * @example
20
29
  * // Create a contoured height field, with black contours every 30 m (assuming the height field is in
21
30
  * // meters).
@@ -113,6 +122,7 @@ class Contour extends PlotComponent {
113
122
  const map_height = gl_elems.map.getCanvas().height;
114
123
  const bearing = gl_elems.map.getBearing();
115
124
  const pitch = gl_elems.map.getPitch();
125
+ // XXX: This will compile another shader each time updateField() is called. Is there a way to not do that?
116
126
  this.contours.forEach(cnt => cnt.render(gl, arg, [map_width, map_height], zoom, bearing, pitch));
117
127
  }
118
128
  }
@@ -121,11 +131,20 @@ const contour_label_opt_defaults = {
121
131
  font_face: 'Trebuchet MS',
122
132
  font_size: 12,
123
133
  font_url_template: '',
134
+ label_formatter: (val) => val.toString(),
124
135
  text_color: '#000000',
125
136
  halo_color: '#000000',
126
137
  halo: false,
127
138
  density: 1
128
139
  };
140
+ /**
141
+ * Label the contours on a plot
142
+ * @example
143
+ * // Contour some data
144
+ * const contours = new Contour(height_field, {color: '#000000', interval: 30});
145
+ * // Label the contours
146
+ * const labels = new ContourLabels(contours, {text_color: '#ffffff', halo: true});
147
+ */
129
148
  class ContourLabels extends PlotComponent {
130
149
  constructor(contours, opts) {
131
150
  super();
@@ -155,7 +174,7 @@ class ContourLabels extends PlotComponent {
155
174
  const contour_label_spacing = 0.006 / this.opts.density * Math.pow(2, 7 - map_max_zoom);
156
175
  Object.entries(contour_data).forEach(([level, contours]) => {
157
176
  const icntr = (parseFloat(level) - contour_levels[0]);
158
- const level_str = level.toString();
177
+ const level_str = this.opts.label_formatter(level);
159
178
  contours.forEach(contour => {
160
179
  const c_map = contour.map(v => {
161
180
  const v_ll = new LngLat(...v).toMercatorCoord();
@@ -175,6 +194,8 @@ class ContourLabels extends PlotComponent {
175
194
  let n_labels_placed = 0;
176
195
  for (let idist = 1; idist < dist.length; idist++) {
177
196
  const target_dist = contour_label_spacing * (n_labels_placed + (icntr / 2) % 1);
197
+ // This works fine when contour_label_spacing > the spacing between points along a contour, but when you allow the map to zoom in
198
+ // (and therefore contour_label_spacing gets small), dist[idist] outruns target_dist, so it doesn't put any more labels after the first.
178
199
  if (dist[idist - 1] <= target_dist && target_dist < dist[idist]) {
179
200
  const pt1 = contour[idist - 1];
180
201
  const pt2 = contour[idist];
@@ -219,6 +240,7 @@ class ContourLabels extends PlotComponent {
219
240
  const map_width = gl_elems.map.getCanvas().width;
220
241
  const map_height = gl_elems.map.getCanvas().height;
221
242
  const map_zoom = gl_elems.map.getZoom();
243
+ // XXX: This will compile another shader each time updateField() is called. Is there a way to not do that?
222
244
  this.text_collection.render(gl, arg, [map_width, map_height], map_zoom);
223
245
  }
224
246
  }