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.
- package/README.md +6 -11
- package/dist/110.autumnplot-gl.js +1 -1
- package/dist/110.autumnplot-gl.js.map +1 -1
- package/dist/autumnplot-gl.js +1 -1
- package/dist/autumnplot-gl.js.map +1 -1
- package/dist/marchingsquares.wasm +0 -0
- package/lib/Barbs.d.ts +18 -2
- package/lib/Barbs.js +25 -19
- package/lib/BillboardCollection.d.ts +9 -2
- package/lib/BillboardCollection.js +46 -9
- package/lib/Color.d.ts +56 -0
- package/lib/Color.js +160 -0
- package/lib/ColorBar.d.ts +2 -1
- package/lib/ColorBar.js +5 -5
- package/lib/Colormap.d.ts +19 -18
- package/lib/Colormap.js +81 -20
- package/lib/Contour.d.ts +25 -6
- package/lib/Contour.js +61 -12
- package/lib/ContourCreator.js +4 -40
- package/lib/Fill.d.ts +2 -4
- package/lib/Fill.js +29 -45
- package/lib/Grid.d.ts +1 -0
- package/lib/Grid.js +6 -1
- package/lib/Hodographs.d.ts +19 -3
- package/lib/Hodographs.js +23 -20
- package/lib/Paintball.d.ts +2 -2
- package/lib/Paintball.js +9 -6
- package/lib/PlotComponent.js +9 -4
- package/lib/PlotLayer.d.ts +1 -1
- package/lib/PlotLayer.worker.js +10 -7
- package/lib/PolylineCollection.d.ts +13 -6
- package/lib/PolylineCollection.js +76 -64
- package/lib/StationPlot.d.ts +34 -0
- package/lib/StationPlot.js +73 -0
- package/lib/TextCollection.d.ts +3 -2
- package/lib/TextCollection.js +21 -11
- package/lib/cpp/marchingsquares.js +558 -1261
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +4 -45
- package/lib/index.d.ts +4 -2
- package/lib/index.js +2 -1
- package/lib/utils.d.ts +2 -8
- package/lib/utils.js +1 -83
- 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
|
-
|
|
10
|
-
|
|
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) =>
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
95
|
-
const color2_hsv =
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
18
|
-
* @default
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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.
|
|
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 =
|
|
40
|
-
|
|
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
|
-
|
|
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:
|
|
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();
|
package/lib/ContourCreator.js
CHANGED
|
@@ -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
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
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
|
|
27
|
-
readonly
|
|
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 {
|
|
2
|
+
import { ColorMap, ColorMapGPUInterface } from './Colormap';
|
|
3
3
|
import { WGLProgram, WGLTexture } from 'autumn-wgl';
|
|
4
|
-
import {
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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.
|
|
58
|
-
this.
|
|
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:
|
|
93
|
-
|
|
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
|
-
|
|
117
|
-
|
|
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 =
|
|
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) {
|