autumnplot-gl 3.0.0 → 3.2.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 (44) hide show
  1. package/README.md +6 -11
  2. package/dist/110.autumnplot-gl.js +1 -1
  3. package/dist/110.autumnplot-gl.js.map +1 -1
  4. package/dist/autumnplot-gl.js +1 -1
  5. package/dist/autumnplot-gl.js.map +1 -1
  6. package/dist/marchingsquares.wasm +0 -0
  7. package/lib/Barbs.d.ts +18 -2
  8. package/lib/Barbs.js +25 -19
  9. package/lib/BillboardCollection.d.ts +9 -2
  10. package/lib/BillboardCollection.js +46 -9
  11. package/lib/Color.d.ts +56 -0
  12. package/lib/Color.js +160 -0
  13. package/lib/ColorBar.d.ts +2 -1
  14. package/lib/ColorBar.js +5 -5
  15. package/lib/Colormap.d.ts +19 -18
  16. package/lib/Colormap.js +81 -20
  17. package/lib/Contour.d.ts +25 -6
  18. package/lib/Contour.js +61 -12
  19. package/lib/ContourCreator.js +4 -40
  20. package/lib/Fill.d.ts +2 -4
  21. package/lib/Fill.js +29 -45
  22. package/lib/Grid.d.ts +1 -0
  23. package/lib/Grid.js +6 -1
  24. package/lib/Hodographs.d.ts +19 -3
  25. package/lib/Hodographs.js +23 -20
  26. package/lib/Paintball.d.ts +2 -2
  27. package/lib/Paintball.js +9 -6
  28. package/lib/PlotComponent.js +9 -4
  29. package/lib/PlotLayer.d.ts +1 -1
  30. package/lib/PlotLayer.worker.js +10 -7
  31. package/lib/PolylineCollection.d.ts +13 -6
  32. package/lib/PolylineCollection.js +76 -64
  33. package/lib/StationPlot.d.ts +34 -0
  34. package/lib/StationPlot.js +73 -0
  35. package/lib/TextCollection.d.ts +3 -2
  36. package/lib/TextCollection.js +21 -11
  37. package/lib/cpp/marchingsquares.js +558 -1261
  38. package/lib/cpp/marchingsquares.wasm +0 -0
  39. package/lib/cpp/marchingsquares_embind.d.ts +4 -45
  40. package/lib/index.d.ts +4 -2
  41. package/lib/index.js +2 -1
  42. package/lib/utils.d.ts +2 -8
  43. package/lib/utils.js +1 -83
  44. package/package.json +2 -2
package/lib/Colormap.js CHANGED
@@ -1,4 +1,3 @@
1
- import { hex2rgb, hsv2rgb, rgb2hex, rgb2hsv } from "./utils";
2
1
  const spd500_colormap_data = { "levels": [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, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140], "colors": [ "#e6f4ff", "#dbf0fe", "#d1ebfe", "#c6e7fd", "#bce3fd", "#b1dffc", "#a7dbfc", "#9cd6fb", "#92d2fb", "#87cefa", "#84c2f6", "#81b7f1", "#7eabed", "#7ba0e8", "#7994e4", "#7688df", "#737ddb", "#7071d6", "#6d66d2", "#6a5acd", "#7660cf", "#8366d0", "#8f6cd2", "#9c72d3", "#a878d5", "#b47ed6", "#c184d8", "#cd8ad9", "#da90db", "#e696dc", "#e390d9", "#e08ad6", "#dd84d3", "#da7ed0", "#d778cd", "#d472ca", "#d16cc7", "#ce66c4", "#cb60c1", "#c85abe", "#c453ba", "#c04cb6", "#bc45b2", "#b83eae", "#b437aa", "#b030a6", "#ac29a2", "#a8229e", "#a41b9a", "#a01496", "#a41080", "#a80e75", "#ac0e75", "#b00c6a", "#b4085f", "#b80649", "#bc043e", "#c00233", "#c80028", "#c80028", "#ca042a", "#cc082c", "#d00c2c", "#d21432", "#d41834", "#d41834", "#d61c36", "#da243a", "#dc283c", "#de2c3e", "#e03040", "#e23442", "#e43844", "#e63c46", "#e84048", "#ea444a", "#ec484c", "#ee4c4e", "#f05050", "#f16052", "#f27054", "#f38056", "#f49058", "#f5a05a", "#f6b05c", "#f7c05e", "#f8d060", "#f9e062", "#faf064", "#f7eb61", "#f4e65e", "#f1e15b", "#eedc58", "#ebd755", "#e8d252", "#e5cd4f", "#e2c84c", "#dfc349", "#dcbe46", "#d9b943", "#d6b440", "#d3af3d", "#d0aa3a", "#cda537", "#caa034", "#c79b31", "#c4962e", "#c1912b", "#be8c28", "#bb8725", "#b88222", "#b57d1f", "#b2781c", "#af7319", "#ac6e16", "#a96913", "#a66410", "#a35f0d", "#a05a0a", "#a05a0a" ] }
3
2
  const spd850_colormap_data = { "levels": [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], "colors": [ "#f0f8ff", "#dbf0fe", "#c6e7fd", "#b1dffc", "#9cd6fb", "#87cefa", "#81b7f1", "#7ba0e8", "#7688df", "#7071d6", "#6a5acd", "#8366d0", "#9c72d3", "#b47ed6", "#cd8ad9", "#e696dc", "#e08ad6", "#da7ed0", "#d472ca", "#ce66c4", "#c85abe", "#c04cb6", "#b83eae", "#b030a6", "#a8229e", "#a01496", "#a81080", "#b00c6a", "#b8043e", "#c80028", "#c80028", "#d01030", "#d41834", "#d82038", "#dc283c", "#e03040", "#e43844", "#e84048", "#ec484c", "#f05050", "#f27054", "#f49058", "#f6b05c", "#f8d060", "#faf064", "#f4e65e", "#eedc58", "#e8d252", "#e2c84c", "#dcbe46", "#d6b440", "#d0aa3a", "#caa034", "#c4962e", "#be8c28", "#b88222", "#b2781c", "#ac6e16", "#a66410", "#a05a0a" ] }
4
3
  const cape_colormap_data = { "levels": [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400, 4500, 4600, 4700, 4800, 4900, 5000, 5100, 5200, 5300, 5400, 5500, 5600, 5700, 5800, 5900, 6000, 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000], "colors": [ "#ffffff", "#f0f0f0", "#e1e1e1", "#d2d2d2", "#c3c3c3", "#a5a5a5", "#969696", "#878787", "#787878", "#696969", "#37536a", "#436075", "#506d80", "#5c7a8b", "#698796", "#7594a2", "#82a1ad", "#8eaeb8", "#9bbbc3", "#a7c8ce", "#e9dd96", "#e8d186", "#e7c575", "#e6b865", "#e5ac54", "#e5a044", "#e49433", "#e38723", "#e27b12", "#e16f02", "#dc4110", "#d33b17", "#ca351e", "#c12e25", "#b8282c", "#af2234", "#a61c3b", "#9d1542", "#940f49", "#8b0950", "#73088a", "#7e1894", "#8a289f", "#9538a9", "#a148b3", "#ac59be", "#b869c8", "#c379d2", "#cf89dd", "#da99e7", "#e9bec3", "#e3b0b7", "#dda3ac", "#d795a0", "#d18894", "#ca7a89", "#c46d7d", "#be5f71", "#b85266", "#b2445a", "#893d48", "#8f4752", "#96525b", "#9c5c65", "#a2676f", "#a97178", "#af7c82", "#b6868b" ] }
@@ -6,9 +5,37 @@ const t2m_colormap_data = { "levels": [-60, -59, -58, -57, -56, -55, -54, -5
6
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" ] }
7
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" ] }
8
7
  import { Float16Array } from "@petamoriken/float16";
9
- function isColor(obj) {
10
- return (typeof obj == 'object') && 'color' in obj && 'opacity' in obj;
11
- }
8
+ import { WGLTexture } from "autumn-wgl";
9
+ import { getGLFormatTypeAlignment } from "./PlotComponent";
10
+ import { Color } from "./Color";
11
+ const colormap_shader_src = `
12
+ uniform sampler2D u_cmap_sampler;
13
+ uniform sampler2D u_cmap_nonlin_sampler;
14
+ uniform highp float u_cmap_min;
15
+ uniform highp float u_cmap_max;
16
+ uniform highp vec4 u_underflow_color;
17
+ uniform highp vec4 u_overflow_color;
18
+ uniform int u_n_index;
19
+
20
+ lowp vec4 apply_colormap(highp float value) {
21
+ lowp float normed_val = (value - u_cmap_min) / (u_cmap_max - u_cmap_min);
22
+
23
+ lowp vec4 color;
24
+ if (normed_val < 0.0) {
25
+ color = u_underflow_color;
26
+ }
27
+ else if (normed_val > 1.0) {
28
+ color = u_overflow_color;
29
+ }
30
+ else {
31
+ lowp float index_buffer = 1. / (2. * float(u_n_index));
32
+ normed_val = index_buffer + normed_val * (1. - 2. * index_buffer);
33
+ highp float nonlin_val = texture2D(u_cmap_nonlin_sampler, vec2(normed_val, 0.5)).r;
34
+ color = texture2D(u_cmap_sampler, vec2(nonlin_val, 0.5));
35
+ }
36
+
37
+ return color;
38
+ }`
12
39
  /** A mapping from values to colors */
13
40
  class ColorMap {
14
41
  /**
@@ -21,7 +48,7 @@ class ColorMap {
21
48
  if (levels.length != colors.length + 1) {
22
49
  throw `Mismatch between number of levels (${levels.length}) and number of colors (${colors.length}; expected ${levels.length - 1})`;
23
50
  }
24
- const normalizeColor = (c) => isColor(c) ? c : { 'color': c, 'opacity': 1. };
51
+ const normalizeColor = (c) => c instanceof Color ? c : Color.fromHex(c);
25
52
  this.levels = levels;
26
53
  this.colors = colors.map(c => normalizeColor(c));
27
54
  opts = opts === undefined ? {} : opts;
@@ -32,13 +59,13 @@ class ColorMap {
32
59
  * @returns an array of hex color strings
33
60
  */
34
61
  getColors() {
35
- return this.colors.map(s => s['color']);
62
+ return this.colors.map(s => s.toRGBHex());
36
63
  }
37
64
  /**
38
65
  * @returns an array of opacities, one for each color in the color map
39
66
  */
40
67
  getOpacities() {
41
- return this.colors.map(s => s['opacity']);
68
+ return this.colors.map(s => s.a);
42
69
  }
43
70
  /**
44
71
  * Make a new color map with different opacities. The opacities are set by func.
@@ -54,7 +81,7 @@ class ColorMap {
54
81
  const level_lower = this.levels[ic];
55
82
  const level_upper = this.levels[ic + 1];
56
83
  const new_opacity = func(level_lower, level_upper);
57
- const new_color = { color: color.color, opacity: new_opacity };
84
+ const new_color = color.withOpacity(new_opacity);
58
85
  if (new_opacity > 0) {
59
86
  if (new_levels[new_levels.length - 1] != level_lower)
60
87
  new_levels.push(level_lower);
@@ -65,13 +92,13 @@ class ColorMap {
65
92
  if (this.underflow_color !== null) {
66
93
  const underflow_opacity = func(this.levels[0], this.levels[0]);
67
94
  if (underflow_opacity > 0) {
68
- opts.underflow_color = { color: this.underflow_color.color, opacity: underflow_opacity };
95
+ opts.underflow_color = this.underflow_color.withOpacity(underflow_opacity);
69
96
  }
70
97
  }
71
98
  if (this.overflow_color !== null) {
72
99
  const overflow_opacity = func(this.levels[this.levels.length - 1], this.levels[this.levels.length - 1]);
73
100
  if (overflow_opacity > 0) {
74
- opts.overflow_color = { color: this.overflow_color.color, opacity: overflow_opacity };
101
+ opts.overflow_color = this.overflow_color.withOpacity(overflow_opacity);
75
102
  }
76
103
  }
77
104
  return new ColorMap(new_levels, new_colors, opts);
@@ -91,30 +118,30 @@ class ColorMap {
91
118
  const level_step = (level_max - level_min) / (n_colors - 1);
92
119
  const crossover = (level_max + level_min) / 2;
93
120
  const crossover_hsv = [0, 0, 0.9];
94
- const color1_hsv = rgb2hsv(hex2rgb(color1));
95
- const color2_hsv = rgb2hsv(hex2rgb(color2));
121
+ const color1_hsv = Color.fromHex(color1).toHSVTuple();
122
+ const color2_hsv = Color.fromHex(color2).toHSVTuple();
123
+ const interp_fac_power = 1.5;
96
124
  for (let istop = 0; istop < n_colors; istop++) {
97
125
  const level = level_min + istop * level_step;
98
126
  let h, s, v;
99
127
  let interp_fac;
100
128
  if (level < crossover) {
101
- interp_fac = (crossover - level) / (crossover - level_min);
129
+ interp_fac = Math.pow((crossover - level) / (crossover - level_min), interp_fac_power);
102
130
  [h, s, v] = [
103
131
  color1_hsv[0],
104
132
  crossover_hsv[1] + (color1_hsv[1] - crossover_hsv[1]) * interp_fac,
105
133
  crossover_hsv[2] + (color1_hsv[2] - crossover_hsv[2]) * interp_fac
106
134
  ];
107
135
  }
108
- else if (level >= crossover) {
109
- interp_fac = (level - crossover) / (level_max - crossover);
136
+ else {
137
+ interp_fac = Math.pow((level - crossover) / (level_max - crossover), interp_fac_power);
110
138
  [h, s, v] = [
111
139
  color2_hsv[0],
112
140
  crossover_hsv[1] + (color2_hsv[1] - crossover_hsv[1]) * interp_fac,
113
141
  crossover_hsv[2] + (color2_hsv[2] - crossover_hsv[2]) * interp_fac
114
142
  ];
115
143
  }
116
- const color = rgb2hex(hsv2rgb([h, s, v]));
117
- stops.push({ 'color': color, 'opacity': Math.min(2 * interp_fac, 1) });
144
+ stops.push(Color.fromHSVTuple([h, s, v]).withOpacity(Math.min(2 * interp_fac, 1)));
118
145
  }
119
146
  for (let ilev = 0; ilev <= n_colors; ilev++) {
120
147
  const level_step = (level_max - level_min) / n_colors;
@@ -161,6 +188,40 @@ const redblue = (level_min, level_max, n_colors) => {
161
188
  const bluered = (level_min, level_max, n_colors) => {
162
189
  return ColorMap.diverging('#0000ff', '#ff0000', level_min, level_max, n_colors);
163
190
  };
191
+ const N_INDEX_MAP = 101;
192
+ class ColorMapGPUInterface {
193
+ constructor(colormap) {
194
+ this.colormap = colormap;
195
+ this.gl_elems = null;
196
+ }
197
+ static applyShader(shader_src) {
198
+ return colormap_shader_src + "\n" + shader_src;
199
+ }
200
+ setupShaderVariables(gl, mag_filter) {
201
+ const index_map = makeIndexMap(this.colormap);
202
+ const cmap_image = makeTextureImage(this.colormap);
203
+ const { format: format_nonlin, type: type_nonlin, row_alignment: row_alignment_nonlin } = getGLFormatTypeAlignment(gl, true);
204
+ const cmap_image_spec = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': cmap_image, 'mag_filter': mag_filter };
205
+ const cmap_texture = new WGLTexture(gl, cmap_image_spec);
206
+ const cmap_nonlin_image = { 'format': format_nonlin, 'type': type_nonlin,
207
+ 'width': index_map.length, 'height': 1,
208
+ 'image': new Uint16Array(index_map.buffer),
209
+ 'mag_filter': gl.LINEAR, 'row_alignment': row_alignment_nonlin,
210
+ };
211
+ const cmap_nonlin_texture = new WGLTexture(gl, cmap_nonlin_image);
212
+ this.gl_elems = { cmap_texture: cmap_texture, cmap_nonlin_texture: cmap_nonlin_texture };
213
+ }
214
+ bindShaderVariables(program) {
215
+ if (this.gl_elems === null)
216
+ return;
217
+ const cmap = this.colormap;
218
+ const underflow_color = cmap.underflow_color === null ? [0, 0, 0, 0] : cmap.underflow_color.toRGBATuple();
219
+ const overflow_color = cmap.overflow_color === null ? [0, 0, 0, 0] : cmap.overflow_color.toRGBATuple();
220
+ program.setUniforms({ 'u_cmap_min': cmap.levels[0], 'u_cmap_max': cmap.levels[cmap.levels.length - 1],
221
+ 'u_n_index': N_INDEX_MAP, 'u_underflow_color': underflow_color, 'u_overflow_color': overflow_color });
222
+ program.bindTextures({ 'u_cmap_sampler': this.gl_elems.cmap_texture, 'u_cmap_nonlin_sampler': this.gl_elems.cmap_nonlin_texture });
223
+ }
224
+ }
164
225
  /**
165
226
  * Make a canvas image corresponding to a color map
166
227
  * @param colormap - The color map to use
@@ -175,7 +236,7 @@ function makeTextureImage(colormap) {
175
236
  if (ctx === null) {
176
237
  throw "Could not get rendering context for colormap image canvas";
177
238
  }
178
- ctx.fillStyle = stop['color'] + Math.round(stop['opacity'] * 255).toString(16);
239
+ ctx.fillStyle = stop.toRGBAHex();
179
240
  ctx.fillRect(istop, 0, 1, 1);
180
241
  });
181
242
  return cmap_image;
@@ -183,7 +244,7 @@ function makeTextureImage(colormap) {
183
244
  function makeIndexMap(colormap) {
184
245
  // Build a texture to account for nonlinear colormaps (basically inverts the relationship between
185
246
  // the normalized index and the normalized level)
186
- const n_nonlin = 101;
247
+ const n_nonlin = N_INDEX_MAP;
187
248
  const map_norm = [];
188
249
  for (let i = 0; i < n_nonlin; i++) {
189
250
  map_norm.push(i / (n_nonlin - 1));
@@ -200,4 +261,4 @@ function makeIndexMap(colormap) {
200
261
  });
201
262
  return new Float16Array(inv_cmap_norm);
202
263
  }
203
- export { ColorMap, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl, makeTextureImage, makeIndexMap };
264
+ export { ColorMap, ColorMapGPUInterface, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl };
package/lib/Contour.d.ts CHANGED
@@ -2,22 +2,43 @@ import { TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
2
2
  import { MapLikeType } from './Map';
3
3
  import { PlotComponent } from './PlotComponent';
4
4
  import { RawScalarField } from './RawField';
5
+ import { LineStyle } from './PolylineCollection';
6
+ import { ColorMap } from './Colormap';
5
7
  interface ContourOptions {
6
8
  /**
7
9
  * The color of the contours as a hex color string
8
10
  * @default '#000000'
9
11
  */
10
12
  color?: string;
13
+ /**
14
+ * A color map to use to color the contours. Specifying a colormap overrides the color option.
15
+ * @default null
16
+ */
17
+ cmap?: ColorMap | null;
11
18
  /**
12
19
  * The contour interval for drawing contours at regular intervals
13
20
  * @default 1
14
21
  */
15
22
  interval?: number;
16
23
  /**
17
- * A list of arbitrary levels (up to 40) to contour. This overrides the `interval` option.
18
- * @default Draw contours at regular intervals given by the `interval` option.
24
+ * A list of arbitrary levels to contour. This overrides the `interval` option.
25
+ * @default null
26
+ */
27
+ levels?: number[] | null;
28
+ /**
29
+ * The width of the line in pixels. This could be either a number or a function that takes a contour level as a number and returns a line width. This
30
+ * can be used to vary the width of the contours by value.
31
+ * @example level => level >= 100 ? 3 : 1.5
32
+ * @default 2
33
+ */
34
+ line_width?: number | ((level: number) => number);
35
+ /**
36
+ * The style to use for the line. This can be either a LineStyle or a function that takes a contour level as a number and returns a LineStyle. This
37
+ * can be used to vary the contours by value.
38
+ * @example level => level < 0 ? '--' : '-'
39
+ * @default '-'
19
40
  */
20
- levels?: number[];
41
+ line_style?: LineStyle | ((level: number) => LineStyle);
21
42
  }
22
43
  /**
23
44
  * A field of contoured data.
@@ -28,9 +49,7 @@ interface ContourOptions {
28
49
  */
29
50
  declare class Contour<ArrayType extends TypedArray, MapType extends MapLikeType> extends PlotComponent<MapType> {
30
51
  private field;
31
- readonly color: string;
32
- readonly interval: number;
33
- readonly levels: number[];
52
+ readonly opts: Required<ContourOptions>;
34
53
  private gl_elems;
35
54
  private contours;
36
55
  /**
package/lib/Contour.js CHANGED
@@ -1,9 +1,18 @@
1
1
  import { LngLat } from './Map';
2
2
  import { PlotComponent } from './PlotComponent';
3
- import { PolylineCollection } from './PolylineCollection';
3
+ import { PolylineCollection, isLineStyle } from './PolylineCollection';
4
4
  import { TextCollection } from './TextCollection';
5
- import { hex2rgb, normalizeOptions } from './utils';
5
+ import { Color } from './Color';
6
+ import { normalizeOptions } from './utils';
6
7
  import { kdTree } from 'kd-tree-javascript';
8
+ const contour_opt_defaults = {
9
+ color: '#000000',
10
+ cmap: null,
11
+ interval: 1,
12
+ levels: null,
13
+ line_width: 2,
14
+ line_style: '-'
15
+ };
7
16
  /**
8
17
  * A field of contoured data.
9
18
  * @example
@@ -20,9 +29,7 @@ class Contour extends PlotComponent {
20
29
  constructor(field, opts) {
21
30
  super();
22
31
  this.field = field;
23
- this.interval = opts.interval || 1;
24
- this.levels = opts.levels || [];
25
- this.color = opts.color || '#000000';
32
+ this.opts = normalizeOptions(opts, contour_opt_defaults);
26
33
  this.gl_elems = null;
27
34
  this.contours = null;
28
35
  }
@@ -36,14 +43,51 @@ class Contour extends PlotComponent {
36
43
  return;
37
44
  const gl = this.gl_elems.gl;
38
45
  const contour_data = await this.getContours();
39
- const line_data = Object.values(contour_data).flat().map(c => {
40
- return { vertices: c };
46
+ const line_data = [];
47
+ // Make contour data and sort them by line width and line style
48
+ Object.entries(contour_data).forEach(([cv, cd]) => {
49
+ const cv_ = parseFloat(cv);
50
+ const contour_style = isLineStyle(this.opts.line_style) ? this.opts.line_style : this.opts.line_style(cv_);
51
+ const contour_width = typeof this.opts.line_width === 'number' ? this.opts.line_width : this.opts.line_width(cv_);
52
+ const polyline_data = cd.map(c => {
53
+ const ld = { vertices: c };
54
+ if (this.opts.cmap !== null) {
55
+ ld.data = c.map(() => cv_);
56
+ }
57
+ return ld;
58
+ });
59
+ const line_data_filtered = line_data.filter(ld => ld.line_style == contour_style && ld.line_width == contour_width);
60
+ let contour_line_data;
61
+ if (line_data_filtered.length == 0) {
62
+ contour_line_data = { data: [], line_width: contour_width, line_style: contour_style };
63
+ line_data.push(contour_line_data);
64
+ }
65
+ else {
66
+ contour_line_data = line_data_filtered[0];
67
+ }
68
+ contour_line_data.data = contour_line_data.data.concat(polyline_data);
69
+ });
70
+ // Make one PolylineCollection for each combination of line width and line style
71
+ const promises = line_data.map(async (ld) => {
72
+ const plc_opts = { line_width: ld.line_width, line_style: ld.line_style };
73
+ if (this.opts.cmap !== null) {
74
+ plc_opts.cmap = this.opts.cmap;
75
+ }
76
+ else {
77
+ plc_opts.color = this.opts.color;
78
+ }
79
+ return await PolylineCollection.make(gl, ld.data, plc_opts);
80
+ });
81
+ Promise.all(promises).then(values => {
82
+ if (this.gl_elems === null)
83
+ return;
84
+ this.contours = values;
85
+ this.gl_elems.map.triggerRepaint();
41
86
  });
42
- this.contours = await PolylineCollection.make(gl, line_data, { line_width: 2, color: this.color });
43
- this.gl_elems.map.triggerRepaint();
44
87
  }
45
88
  async getContours() {
46
- return await this.field.getContours({ interval: this.interval, levels: this.levels });
89
+ const levels = this.opts.levels === null ? undefined : this.opts.levels;
90
+ return await this.field.getContours({ interval: this.opts.interval, levels: levels });
47
91
  }
48
92
  /**
49
93
  * @internal
@@ -70,7 +114,7 @@ class Contour extends PlotComponent {
70
114
  const map_height = gl_elems.map.getCanvas().height;
71
115
  const bearing = gl_elems.map.getBearing();
72
116
  const pitch = gl_elems.map.getPitch();
73
- this.contours.render(gl, matrix, [map_width, map_height], zoom, bearing, pitch);
117
+ this.contours.forEach(cnt => cnt.render(gl, matrix, [map_width, map_height], zoom, bearing, pitch));
74
118
  }
75
119
  }
76
120
  const contour_label_opt_defaults = {
@@ -100,6 +144,8 @@ class ContourLabels extends PlotComponent {
100
144
  const gl = this.gl_elems.gl;
101
145
  const map_style = map.getStyle();
102
146
  const font_url_template = this.opts.font_url_template == '' ? map_style.glyphs : this.opts.font_url_template;
147
+ if (font_url_template === undefined)
148
+ throw "The map style doesn't have any glyph information. Please pass the font_url_template option to ContourLabels";
103
149
  const font_url = font_url_template.replace('{range}', '0-255').replace('{fontstack}', this.opts.font_face);
104
150
  const label_pos = [];
105
151
  const contour_data = await this.contours.getContours();
@@ -151,6 +197,9 @@ class ContourLabels extends PlotComponent {
151
197
  });
152
198
  });
153
199
  const tree = new kdTree(label_pos, (a, b) => Math.hypot(a.lon - b.lon, a.lat - b.lat), ['lon', 'lat']);
200
+ if (min_label_lon === null || min_label_lat === null || max_label_lon === null || max_label_lat === null) {
201
+ return;
202
+ }
154
203
  const { x: min_label_x, y: max_label_y } = new LngLat(min_label_lon, min_label_lat).toMercatorCoord();
155
204
  const { x: max_label_x, y: min_label_y } = new LngLat(max_label_lon, max_label_lat).toMercatorCoord();
156
205
  const thin_grid_width = max_label_x - min_label_x;
@@ -181,7 +230,7 @@ class ContourLabels extends PlotComponent {
181
230
  const tc_opts = {
182
231
  horizontal_align: 'center', vertical_align: 'middle', font_size: this.opts.font_size,
183
232
  halo: this.opts.halo,
184
- text_color: hex2rgb(this.opts.text_color), halo_color: hex2rgb(this.opts.halo_color),
233
+ text_color: Color.fromHex(this.opts.text_color), halo_color: Color.fromHex(this.opts.halo_color),
185
234
  };
186
235
  this.text_collection = await TextCollection.make(gl, label_pos, font_url, tc_opts);
187
236
  map.triggerRepaint();
@@ -12,48 +12,12 @@ async function contourCreator(data, grid, opts) {
12
12
  throw "Must supply either an interval or levels to contourCreator()";
13
13
  }
14
14
  const interval = opts.interval === undefined ? 0 : opts.interval;
15
- const levels = opts.levels === undefined ? [] : [...opts.levels];
16
15
  const msm = await initMSModule();
17
16
  const grid_coords = grid.getGridCoords();
18
- const grid_data = new msm.FloatList();
19
- grid_data.resize(grid.ni * grid.nj, 0);
20
- const tex_data = data;
21
- tex_data.forEach((v, i) => grid_data.set(i, v));
22
- const grid_x = new msm.FloatList();
23
- grid_x.resize(grid.ni, 0);
24
- grid_coords.x.forEach((v, i) => grid_x.set(i, v));
25
- const grid_y = new msm.FloatList();
26
- grid_y.resize(grid.nj, 0);
27
- grid_coords.y.forEach((v, i) => grid_y.set(i, v));
28
- if (levels.length == 0) {
29
- const levels_cpp = msm.getContourLevelsFloat32(grid_data, grid.ni, grid.nj, interval);
30
- for (let ilvl = 0; ilvl < levels_cpp.size(); ilvl++) {
31
- levels.push(levels_cpp.get(ilvl));
32
- }
33
- levels_cpp.delete();
34
- }
35
- const contours = {};
36
- levels.forEach(v => {
37
- const contours_ = msm.makeContoursFloat32(grid_data, grid_x, grid_y, v);
38
- contours[v] = [];
39
- for (let icntr = 0; icntr < contours_.size(); icntr++) {
40
- const contour = contours_.get(icntr);
41
- const contour_point_list = contour.point_list;
42
- contours[v].push([]);
43
- for (let ipt = 0; ipt < contour_point_list.size(); ipt++) {
44
- const pt = contour_point_list.get(ipt);
45
- const [lon, lat] = grid.transform(pt.x, pt.y, { inverse: true });
46
- contours[v][icntr].push([lon, lat]);
47
- pt.delete();
48
- }
49
- contour_point_list.delete();
50
- contour.delete();
51
- }
52
- contours_.delete();
53
- });
54
- grid_data.delete();
55
- grid_x.delete();
56
- grid_y.delete();
17
+ const getContourLevels = data instanceof Float32Array ? msm.getContourLevelsFloat32 : msm.getContourLevelsFloat16;
18
+ const makeContours = data instanceof Float32Array ? msm.makeContoursFloat32 : msm.makeContoursFloat16;
19
+ const levels = opts.levels === undefined ? getContourLevels(data, grid.ni, grid.nj, interval) : opts.levels;
20
+ const contours = makeContours(data, grid_coords.x, grid_coords.y, levels, (x, y) => grid.transform(x, y, { inverse: true }));
57
21
  return contours;
58
22
  }
59
23
  export { contourCreator, initMSModule };
package/lib/Fill.d.ts CHANGED
@@ -23,10 +23,8 @@ interface RasterOptions {
23
23
  }
24
24
  declare class PlotComponentFill<ArrayType extends TypedArray, MapType extends MapLikeType> extends PlotComponent<MapType> {
25
25
  private field;
26
- readonly cmap: ColorMap;
27
- readonly opacity: number;
28
- private readonly cmap_image;
29
- private readonly index_map;
26
+ readonly opts: Required<ContourFillOptions>;
27
+ private readonly cmap_gpu;
30
28
  private gl_elems;
31
29
  private fill_texture;
32
30
  protected image_mag_filter: number | null;
package/lib/Fill.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PlotComponent, getGLFormatTypeAlignment } from './PlotComponent';
2
- import { makeIndexMap, makeTextureImage } from './Colormap';
2
+ import { ColorMap, ColorMapGPUInterface } from './Colormap';
3
3
  import { WGLProgram, WGLTexture } from 'autumn-wgl';
4
- import { hex2rgb } from './utils';
4
+ import { normalizeOptions } from './utils';
5
5
  const contourfill_vertex_shader_src = `uniform mat4 u_matrix;
6
6
  uniform int u_offset;
7
7
 
@@ -20,44 +20,38 @@ void main() {
20
20
  const contourfill_fragment_shader_src = `varying highp vec2 v_tex_coord;
21
21
 
22
22
  uniform sampler2D u_fill_sampler;
23
- uniform sampler2D u_cmap_sampler;
24
- uniform sampler2D u_cmap_nonlin_sampler;
25
- uniform highp float u_cmap_min;
26
- uniform highp float u_cmap_max;
27
23
  uniform highp float u_opacity;
28
- uniform highp vec4 u_underflow_color;
29
- uniform highp vec4 u_overflow_color;
30
- uniform int u_n_index;
24
+
25
+ bool isnan(highp float val) {
26
+ return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true;
27
+ }
31
28
 
32
29
  void main() {
33
- lowp float index_buffer = 1. / (2. * float(u_n_index));
34
30
  highp float fill_val = texture2D(u_fill_sampler, v_tex_coord).r;
35
- lowp float normed_val = (fill_val - u_cmap_min) / (u_cmap_max - u_cmap_min);
36
-
37
- lowp vec4 color;
38
- if (normed_val < 0.0) {
39
- color = u_underflow_color;
40
- }
41
- else if (normed_val > 1.0) {
42
- color = u_overflow_color;
43
- }
44
- else {
45
- normed_val = index_buffer + normed_val * (1. - 2. * index_buffer);
46
- highp float nonlin_val = texture2D(u_cmap_nonlin_sampler, vec2(normed_val, 0.5)).r;
47
- color = texture2D(u_cmap_sampler, vec2(nonlin_val, 0.5));
31
+
32
+ if (isnan(fill_val)) {
33
+ discard;
48
34
  }
49
35
 
36
+ lowp vec4 color = apply_colormap(fill_val);
50
37
  color.a = color.a * u_opacity;
51
38
  gl_FragColor = color;
52
39
  }`
40
+ const default_cmap = new ColorMap([0, 1], ['#000000'], { overflow_color: '#000000', underflow_color: '#000000' });
41
+ const contour_fill_opt_defaults = {
42
+ cmap: default_cmap,
43
+ opacity: 1,
44
+ };
45
+ const raster_opt_defaults = {
46
+ cmap: default_cmap,
47
+ opacity: 1,
48
+ };
53
49
  class PlotComponentFill extends PlotComponent {
54
50
  constructor(field, opts) {
55
51
  super();
56
52
  this.field = field;
57
- this.cmap = opts.cmap;
58
- this.opacity = opts.opacity || 1.;
59
- this.cmap_image = makeTextureImage(this.cmap);
60
- this.index_map = makeIndexMap(this.cmap);
53
+ this.opts = normalizeOptions(opts, contour_fill_opt_defaults);
54
+ this.cmap_gpu = new ColorMapGPUInterface(this.opts.cmap);
61
55
  this.gl_elems = null;
62
56
  this.fill_texture = null;
63
57
  this.image_mag_filter = null;
@@ -65,6 +59,9 @@ class PlotComponentFill extends PlotComponent {
65
59
  }
66
60
  async updateField(field) {
67
61
  this.field = field;
62
+ if (this.image_mag_filter === null || this.cmap_mag_filter === null) {
63
+ throw `Implement magnification filtes in a subclass`;
64
+ }
68
65
  if (this.gl_elems === null)
69
66
  return;
70
67
  const gl = this.gl_elems.gl;
@@ -88,22 +85,11 @@ class PlotComponentFill extends PlotComponent {
88
85
  if (this.image_mag_filter === null || this.cmap_mag_filter === null) {
89
86
  throw `Implement magnification filtes in a subclass`;
90
87
  }
91
- const program = new WGLProgram(gl, contourfill_vertex_shader_src, contourfill_fragment_shader_src);
92
- const { vertices: verts_buf, texcoords: tex_coords_buf } = await this.field.grid.getWGLBuffers(gl);
93
- const vertices = verts_buf;
94
- const texcoords = tex_coords_buf;
95
- const cmap_image = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': this.cmap_image, 'mag_filter': this.cmap_mag_filter };
96
- const cmap_texture = new WGLTexture(gl, cmap_image);
97
- const { format: format_nonlin, type: type_nonlin, row_alignment: row_alignment_nonlin } = getGLFormatTypeAlignment(gl, true);
98
- const cmap_nonlin_image = { 'format': format_nonlin, 'type': type_nonlin,
99
- 'width': this.index_map.length, 'height': 1,
100
- 'image': new Uint16Array(this.index_map.buffer),
101
- 'mag_filter': gl.LINEAR, 'row_alignment': row_alignment_nonlin,
102
- };
103
- const cmap_nonlin_texture = new WGLTexture(gl, cmap_nonlin_image);
88
+ const program = new WGLProgram(gl, contourfill_vertex_shader_src, ColorMapGPUInterface.applyShader(contourfill_fragment_shader_src));
89
+ const { vertices: vertices, texcoords: texcoords } = await this.field.grid.getWGLBuffers(gl);
90
+ this.cmap_gpu.setupShaderVariables(gl, this.cmap_mag_filter);
104
91
  this.gl_elems = {
105
92
  gl: gl, map: map, program: program, vertices: vertices, texcoords: texcoords,
106
- cmap_texture: cmap_texture, cmap_nonlin_texture: cmap_nonlin_texture,
107
93
  };
108
94
  this.updateField(this.field);
109
95
  }
@@ -113,10 +99,8 @@ class PlotComponentFill extends PlotComponent {
113
99
  const gl_elems = this.gl_elems;
114
100
  if (matrix instanceof Float32Array)
115
101
  matrix = [...matrix];
116
- const underflow_color = this.cmap.underflow_color === null ? [0, 0, 0, 0] : hex2rgb(this.cmap.underflow_color.color).concat(this.cmap.underflow_color.opacity);
117
- const overflow_color = this.cmap.overflow_color === null ? [0, 0, 0, 0] : hex2rgb(this.cmap.overflow_color.color).concat(this.cmap.overflow_color.opacity);
118
- gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_cmap_min': this.cmap.levels[0], 'u_cmap_max': this.cmap.levels[this.cmap.levels.length - 1], 'u_matrix': matrix, 'u_opacity': this.opacity,
119
- 'u_n_index': this.index_map.length, 'u_underflow_color': underflow_color, 'u_overflow_color': overflow_color, 'u_offset': 0 }, { 'u_fill_sampler': this.fill_texture, 'u_cmap_sampler': gl_elems.cmap_texture, 'u_cmap_nonlin_sampler': gl_elems.cmap_nonlin_texture });
102
+ gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_matrix': matrix, 'u_opacity': this.opts.opacity, 'u_offset': 0 }, { 'u_fill_sampler': this.fill_texture });
103
+ this.cmap_gpu.bindShaderVariables(gl_elems.program);
120
104
  gl.enable(gl.BLEND);
121
105
  gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
122
106
  gl_elems.program.draw();
package/lib/Grid.d.ts CHANGED
@@ -145,6 +145,7 @@ declare class LambertGrid extends Grid {
145
145
  * @param ur_y - The y coordinate in projection space of the upper-right corner of the grid
146
146
  */
147
147
  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);
148
+ 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;
148
149
  copy(opts?: {
149
150
  ni?: number;
150
151
  nj?: number;
package/lib/Grid.js CHANGED
@@ -298,6 +298,11 @@ class LambertGrid extends Grid {
298
298
  return { x: x, y: y };
299
299
  });
300
300
  }
301
+ static fromLLCornerLonLat(ni, nj, lon_0, lat_0, lat_std, ll_lon, ll_lat, dx, dy) {
302
+ const lcc = lambertConformalConic({ lon_0: lon_0, lat_0: lat_0, lat_std: lat_std });
303
+ const [ll_x, ll_y] = lcc(ll_lon, ll_lat);
304
+ return new LambertGrid(ni, nj, lon_0, lat_0, lat_std, ll_x, ll_y, ll_x + ni * dx, ll_y + nj * dy);
305
+ }
301
306
  copy(opts) {
302
307
  opts = opts !== undefined ? opts : {};
303
308
  const ni = opts.ni !== undefined ? opts.ni : this.ni;
@@ -319,7 +324,7 @@ class LambertGrid extends Grid {
319
324
  }
320
325
  transform(x, y, opts) {
321
326
  opts = opts === undefined ? {} : opts;
322
- const inverse = 'inverse' in opts ? opts.inverse : false;
327
+ const inverse = opts.inverse === undefined ? false : opts.inverse;
323
328
  return this.lcc(x, y, { inverse: inverse });
324
329
  }
325
330
  getThinnedGrid(thin_x, thin_y) {