autumnplot-gl 3.2.0 → 4.0.0-beta
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/lib/AutumnTypes.d.ts +53 -5
- package/lib/AutumnTypes.js +25 -1
- package/lib/Barbs.d.ts +6 -5
- package/lib/BillboardCollection.d.ts +8 -7
- package/lib/BillboardCollection.js +69 -58
- package/lib/Color.d.ts +1 -0
- package/lib/Color.js +3 -0
- package/lib/ColorBar.d.ts +10 -0
- package/lib/ColorBar.js +4 -2
- package/lib/Colormap.js +8 -8
- package/lib/Contour.d.ts +18 -8
- package/lib/Contour.js +17 -54
- package/lib/ContourCreator.d.ts +4 -0
- package/lib/ContourCreator.js +2 -1
- package/lib/Fill.d.ts +26 -14
- package/lib/Fill.js +97 -50
- package/lib/Grid.d.ts +124 -29
- package/lib/Grid.js +297 -94
- package/lib/Hodographs.d.ts +9 -8
- package/lib/Hodographs.js +14 -11
- package/lib/Map.js +1 -1
- package/lib/Paintball.d.ts +6 -5
- package/lib/Paintball.js +35 -30
- package/lib/ParticleTracer.d.ts +19 -0
- package/lib/ParticleTracer.js +37 -0
- package/lib/PlotComponent.d.ts +6 -7
- package/lib/PlotComponent.js +8 -3
- package/lib/PlotLayer.d.ts +3 -3
- package/lib/PlotLayer.worker.d.ts +1 -2
- package/lib/PlotLayer.worker.js +15 -50
- package/lib/PolylineCollection.d.ts +5 -3
- package/lib/PolylineCollection.js +60 -37
- package/lib/RawField.d.ts +76 -23
- package/lib/RawField.js +138 -29
- package/lib/ShaderManager.d.ts +12 -0
- package/lib/ShaderManager.js +58 -0
- package/lib/StationPlot.d.ts +136 -25
- package/lib/StationPlot.js +192 -60
- package/lib/TextCollection.d.ts +9 -6
- package/lib/TextCollection.js +94 -62
- package/lib/cpp/marchingsquares.js +483 -585
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +23 -3
- package/lib/index.d.ts +4 -3
- package/lib/index.js +4 -3
- package/lib/utils.d.ts +4 -1
- package/lib/utils.js +12 -1
- package/package.json +2 -2
package/lib/StationPlot.d.ts
CHANGED
|
@@ -1,34 +1,145 @@
|
|
|
1
|
-
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { RenderMethodArg, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
2
|
import { MapLikeType } from "./Map";
|
|
3
3
|
import { PlotComponent } from "./PlotComponent";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { Grid } from "./Grid";
|
|
5
|
+
import { RawObsField } from "./RawField";
|
|
6
|
+
/**
|
|
7
|
+
* Positions around the station plot at which to draw the various elements
|
|
8
|
+
*
|
|
9
|
+
* | Value | Position |
|
|
10
|
+
* | --------|--------------|
|
|
11
|
+
* | `'cl'` | center-left |
|
|
12
|
+
* | `'ll'` | lower-left |
|
|
13
|
+
* | `'lc'` | lower-center |
|
|
14
|
+
* | `'lr'` | lower-right |
|
|
15
|
+
* | `'cr'` | center-right |
|
|
16
|
+
* | `'ur'` | upper-right |
|
|
17
|
+
* | `'uc'` | upper-center |
|
|
18
|
+
* | `'ul'` | upper-left |
|
|
19
|
+
* | `'c'` | center |
|
|
20
|
+
*/
|
|
21
|
+
type SPPosition = 'cl' | 'll' | 'lc' | 'lr' | 'cr' | 'ur' | 'uc' | 'ul' | 'c';
|
|
22
|
+
interface SPNumberConfig {
|
|
23
|
+
type: 'number';
|
|
24
|
+
/**
|
|
25
|
+
* The position on the station plot at which to place the number
|
|
26
|
+
*/
|
|
27
|
+
pos: SPPosition;
|
|
28
|
+
/**
|
|
29
|
+
* The color to use to draw the number
|
|
30
|
+
* @default '#000000'
|
|
31
|
+
*/
|
|
32
|
+
color?: string;
|
|
33
|
+
/**
|
|
34
|
+
* A function that properly formats the number for display
|
|
35
|
+
* @example (val) => val === null ? '' : val.toFixed(0)
|
|
36
|
+
* @param val - The number to format
|
|
37
|
+
* @returns A string containing the formatted nubmer
|
|
38
|
+
*/
|
|
39
|
+
formatter?: (val: number | null) => string;
|
|
7
40
|
}
|
|
8
|
-
interface
|
|
9
|
-
|
|
10
|
-
|
|
41
|
+
interface SPStringConfig {
|
|
42
|
+
type: 'string';
|
|
43
|
+
/**
|
|
44
|
+
* The position on the station plot at which to place the number
|
|
45
|
+
*/
|
|
46
|
+
pos: SPPosition;
|
|
47
|
+
/**
|
|
48
|
+
* The color to use to draw the number
|
|
49
|
+
* @default '#000000'
|
|
50
|
+
*/
|
|
51
|
+
color?: string;
|
|
11
52
|
}
|
|
12
|
-
|
|
13
|
-
type
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
53
|
+
interface SPBarbConfig {
|
|
54
|
+
type: 'barb';
|
|
55
|
+
/**
|
|
56
|
+
* The color to use to draw the number
|
|
57
|
+
* @default '#000000'
|
|
58
|
+
*/
|
|
59
|
+
color?: string;
|
|
60
|
+
/**
|
|
61
|
+
* A multiplier for the barb size
|
|
62
|
+
* @default 1
|
|
63
|
+
*/
|
|
64
|
+
barb_size_multipler?: number;
|
|
18
65
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Accepted symbol codes for sky cover and present weather symbols
|
|
68
|
+
*/
|
|
69
|
+
type SPSymbol = ('0/8' | '1/8' | '2/8' | '3/8' | '4/8' | '5/8' | '6/8' | '7/8' | '8/8' | 'clr' | 'few' | 'sct' | 'bkn' | 'ovc' | 'obsc' | 'va' | 'fu' | 'hz' | 'du' | 'bldu' | 'sa' | 'blsa' | 'vcblsa' | 'vcbldu' | 'blpy' | 'po' | 'vcpo' | 'vcds' | 'vcss' | 'br' | 'bcbr' | 'bc' | 'mifg' | 'vcts' | 'virga' | 'vcsh' | 'ts' | 'thdr' | 'vctshz' | 'tsfzfg' | 'tsbr' | 'tsdz' | 'vctsup' | '-tsup' | 'tsup' | '+tsup' | 'sq' | 'fc' | '+fc' | 'ds' | 'ss' | 'drsa' | 'drdu' | '+ds' | '+ss' | 'drsn' | '+drsn' | '-blsn' | 'blsn' | '+blsn' | 'vcblsn' | 'vcfg' | 'bcfg' | 'prfg' | 'fg' | 'fzfg' | '-vctsdz' | '-dz' | '-dzbr' | 'vctsdz' | 'dz' | '+vctsdz' | '+dz' | '-fzdz' | '-fzdzsn' | 'fzdz' | '+fzdz' | 'fzdzsn' | '-dzra' | 'dzra' | '+dzra' | '-ra' | '-rabr' | 'ra' | 'rabr' | 'rafg' | 'vcra' | '+ra' | '-fzra' | '-fzrasn' | '-fzrabr' | '-fzrapl' | '-fzrasnpl' | 'tsfzrapl' | '-tsfzra' | 'fzra' | '+fzra' | 'fzrasn' | 'tsfzra' | '-dzsn' | '-rasn' | '-snra' | '-sndz' | 'rasn' | '+rasn' | 'snra' | 'dzsn' | 'sndz' | '+dzsn' | '+sndz' | '-sn' | '-snbr' | 'sn' | '+sn' | '-snsg' | 'sg' | '-sg' | 'ic' | '-fzdzpl' | '-fzdzplsn' | 'fzdzpl' | '-fzraplsn' | 'fzrapl' | '+fzrapl' | '-rapl' | '-rasnpl' | '-raplsn' | '+rapl' | 'rapl' | '-snpl' | 'snpl' | '-pl' | 'pl' | '-plsn' | '-plra' | 'plra' | '-pldz' | '+pl' | 'plsn' | 'plup' | '+plsn' | '-sh' | '-shra' | 'sh' | 'shra' | '+sh' | '+shra' | '-shrasn' | '-shsnra' | '+shrabr' | 'shrasn' | '+shrasn' | 'shsnra' | '+shsnra' | '-shsn' | 'shsn' | '+shsn' | '-gs' | '-shgs' | 'fzraplgs' | '-sngs' | 'gsplsn' | 'gspl' | 'plgssn' | 'gs' | 'shgs' | '+gs' | '+shgs' | '-gr' | '-shgr' | '-sngr' | 'gr' | 'shgr' | '+gr' | '+shgr' | '-tsrasn' | 'tsrasn' | '-tssnra' | 'tssnra' | '-vctsra' | '-tsra' | 'tsra' | '-tsdz' | 'vctsra' | 'tspl' | '-tssn' | '-tspl' | 'tssn' | '-vctssn' | 'vctssn' | 'tsplsn' | 'tssnpl' | '-tssnpl' | '-tsragr' | 'tsrags' | 'tsragr' | 'tsgs' | 'tsgr' | '+tsfzrapl' | '+vctsra' | '+tsra' | '+tsfzra' | '+tssn' | '+tspl' | '+tsplsn' | '+vctssn' | 'tssa' | 'tsds' | 'tsdu' | '+tsgs' | '+tsgr' | '+tsrags' | '+tsragr' | 'in' | '-up' | 'up' | '+up' | '-fzup' | 'fzup' | '+fzup');
|
|
70
|
+
interface SPSymbolConfig {
|
|
71
|
+
type: 'symbol';
|
|
72
|
+
/**
|
|
73
|
+
* The position on the station plot at which to place the number
|
|
74
|
+
*/
|
|
75
|
+
pos: SPPosition;
|
|
76
|
+
/**
|
|
77
|
+
* The color to use to draw the number
|
|
78
|
+
* @default '#000000'
|
|
79
|
+
*/
|
|
80
|
+
color?: string;
|
|
23
81
|
}
|
|
24
|
-
|
|
82
|
+
type SPConfig = SPNumberConfig | SPStringConfig | SPBarbConfig | SPSymbolConfig;
|
|
83
|
+
/**
|
|
84
|
+
* Configuration for station data plots
|
|
85
|
+
* @example
|
|
86
|
+
* spconfig : SPDataConfig<'id' | 'tmpf' | 'wind' | 'skyc'> = {
|
|
87
|
+
* // Add a string to the station plot (like the station ID)
|
|
88
|
+
* id: {type: 'string', pos: 'lr'},
|
|
89
|
+
*
|
|
90
|
+
* // Add a number to the station plot (like the temperature)
|
|
91
|
+
* tmpf: {type: 'number', pos: 'ul', color: '#cc0000', formatter: val => val === null ? '' : val.toFixed(0)},
|
|
92
|
+
*
|
|
93
|
+
* // Add a barb to the station plot
|
|
94
|
+
* wind: {type: 'barb', pos: 'c'},
|
|
95
|
+
*
|
|
96
|
+
* // Add a symbol to the station plot
|
|
97
|
+
* skyc: {type: 'symbol', pos: 'c'},
|
|
98
|
+
* }
|
|
99
|
+
*/
|
|
100
|
+
type SPDataConfig<ObsFieldName extends string> = Record<ObsFieldName, SPConfig>;
|
|
101
|
+
interface StationPlotOptions<ObsFieldName extends string> {
|
|
102
|
+
config: SPDataConfig<ObsFieldName>;
|
|
103
|
+
/**
|
|
104
|
+
* Thin factor at zoom level 1 for the station plots. Should be a power of 2.
|
|
105
|
+
* @default 1
|
|
106
|
+
*/
|
|
107
|
+
thin_fac?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Font face to use for plotting text
|
|
110
|
+
* @default 'Trebuchet MS'
|
|
111
|
+
*/
|
|
112
|
+
font_face?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Size of the font to use for the text
|
|
115
|
+
* @default 12
|
|
116
|
+
*/
|
|
117
|
+
font_size?: number;
|
|
118
|
+
/**
|
|
119
|
+
* URL template to use in retrieving the font data for the text. The default is to use the template from the map style.
|
|
120
|
+
*/
|
|
121
|
+
font_url_template?: string;
|
|
25
122
|
}
|
|
26
|
-
declare class StationPlot<
|
|
27
|
-
|
|
28
|
-
readonly
|
|
29
|
-
|
|
30
|
-
|
|
123
|
+
declare class StationPlot<GridType extends Grid, MapType extends MapLikeType, ObsFieldName extends string> extends PlotComponent<MapType> {
|
|
124
|
+
private field;
|
|
125
|
+
readonly opts: Required<StationPlotOptions<ObsFieldName>>;
|
|
126
|
+
private gl_elems;
|
|
127
|
+
private text_components;
|
|
128
|
+
/**
|
|
129
|
+
*
|
|
130
|
+
* @param field
|
|
131
|
+
* @param opts
|
|
132
|
+
*/
|
|
133
|
+
constructor(field: RawObsField<GridType, ObsFieldName>, opts: StationPlotOptions<ObsFieldName>);
|
|
134
|
+
/**
|
|
135
|
+
* Update the data displayed as station plots
|
|
136
|
+
* @param field - The new field to display as station plots
|
|
137
|
+
*/
|
|
138
|
+
updateField(field: RawObsField<GridType, ObsFieldName>): Promise<void>;
|
|
139
|
+
/** @internal */
|
|
31
140
|
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
32
|
-
|
|
141
|
+
/** @internal */
|
|
142
|
+
render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg): void;
|
|
33
143
|
}
|
|
34
|
-
export
|
|
144
|
+
export default StationPlot;
|
|
145
|
+
export type { StationPlotOptions, SPPosition, SPNumberConfig, SPStringConfig, SPBarbConfig, SPSymbolConfig, SPConfig, SPDataConfig, SPSymbol };
|
package/lib/StationPlot.js
CHANGED
|
@@ -1,73 +1,205 @@
|
|
|
1
|
-
import { kdTree } from "kd-tree-javascript";
|
|
2
|
-
import { LngLat } from "./Map";
|
|
3
1
|
import { PlotComponent } from "./PlotComponent";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { normalizeOptions } from "./utils";
|
|
3
|
+
import { TextCollection } from "./TextCollection";
|
|
4
|
+
import { Color } from "./Color";
|
|
5
|
+
import Barbs from "./Barbs";
|
|
6
|
+
const SYMBOLS = {
|
|
7
|
+
// Sky cover symbols
|
|
8
|
+
'0/8': 59658, '1/8': 59659, '2/8': 59660, '3/8': 59661, '4/8': 59662, '5/8': 59663, '6/8': 59664, '7/8': 59665, '8/8': 59666,
|
|
9
|
+
'clr': 59658, 'few': 59660, 'sct': 59662, 'bkn': 59664, 'ovc': 59666, 'obsc': 59667,
|
|
10
|
+
// Present weather symbols
|
|
11
|
+
'va': 59810, 'fu': 59810, 'hz': 59811, 'du': 59812, 'bldu': 59814, 'sa': 59814, 'blsa': 59814, 'vcblsa': 59814, 'vcbldu': 59814, 'blpy': 59814,
|
|
12
|
+
'po': 59816, 'vcpo': 59816, 'vcds': 59817, 'vcss': 59817,
|
|
13
|
+
'br': 59818, 'bcbr': 59818, 'bc': 59819, 'mifg': 59820,
|
|
14
|
+
'vcts': 59821, 'virga': 59822, 'vcsh': 59824, 'ts': 59825, 'thdr': 59825, 'vctshz': 59825,
|
|
15
|
+
'tsfzfg': 59825, 'tsbr': 59825, 'tsdz': 59825, 'vctsup': 59825,
|
|
16
|
+
'-tsup': 59825, 'tsup': 59825, '+tsup': 59825,
|
|
17
|
+
'sq': 59826, 'fc': 59827, '+fc': 59827,
|
|
18
|
+
'ds': 59839, 'ss': 59839, 'drsa': 59839, 'drdu': 59839, '+ds': 59842, '+ss': 59842,
|
|
19
|
+
'drsn': 59844, '+drsn': 59845, '-blsn': 59846, 'blsn': 59846, '+blsn': 59847, 'vcblsn': 59846,
|
|
20
|
+
'vcfg': 59848, 'bcfg': 59849, 'prfg': 59852, 'fg': 59853, 'fzfg': 59857,
|
|
21
|
+
'-vctsdz': 59859, '-dz': 59859, '-dzbr': 59859, 'vctsdz': 59861, 'dz': 59861, '+vctsdz': 59863, '+dz': 59863,
|
|
22
|
+
'-fzdz': 59864, '-fzdzsn': 59864, 'fzdz': 59865, '+fzdz': 59865, 'fzdzsn': 59865,
|
|
23
|
+
'-dzra': 59866, 'dzra': 59867, '+dzra': 59867, '-ra': 59869, '-rabr': 59869, 'ra': 59871, 'rabr': 59871, 'rafg': 59871, 'vcra': 59871, '+ra': 59873,
|
|
24
|
+
'-fzra': 59874, '-fzrasn': 59874, '-fzrabr': 59874, '-fzrapl': 59874, '-fzrasnpl': 59874, 'tsfzrapl': 59875, '-tsfzra': 59875,
|
|
25
|
+
'fzra': 59875, '+fzra': 59875, 'fzrasn': 59875, 'tsfzra': 59875,
|
|
26
|
+
'-dzsn': 59876, '-rasn': 59876, '-snra': 59876, '-sndz': 59876, 'rasn': 59877, '+rasn': 59877, 'snra': 59877, 'dzsn': 59877, 'sndz': 59877, '+dzsn': 59877, '+sndz': 59877,
|
|
27
|
+
'-sn': 59879, '-snbr': 59879, 'sn': 59881, '+sn': 59883, '-snsg': 59885, 'sg': 59885, '-sg': 59885, 'ic': 59886,
|
|
28
|
+
'-fzdzpl': 59887, '-fzdzplsn': 59887, 'fzdzpl': 59887, '-fzraplsn': 59887, 'fzrapl': 59887, '+fzrapl': 59887,
|
|
29
|
+
'-rapl': 59887, '-rasnpl': 59887, '-raplsn': 59887, '+rapl': 59887, 'rapl': 59887, '-snpl': 59887, 'snpl': 59887,
|
|
30
|
+
'-pl': 59887, 'pl': 59887, '-plsn': 59887, '-plra': 59887, 'plra': 59887, '-pldz': 59887, '+pl': 59887, 'plsn': 59887, 'plup': 59887, '+plsn': 59887,
|
|
31
|
+
'-sh': 59888, '-shra': 59888, 'sh': 59889, 'shra': 59889, '+sh': 59889, '+shra': 59889, '-shrasn': 59891, '-shsnra': 59891, '+shrabr': 59892,
|
|
32
|
+
'shrasn': 59892, '+shrasn': 59892, 'shsnra': 59892, '+shsnra': 59892, '-shsn': 59893, 'shsn': 59894, '+shsn': 59894,
|
|
33
|
+
'-gs': 59895, '-shgs': 59895, 'fzraplgs': 59896, '-sngs': 59896, 'gsplsn': 59896, 'gspl': 59896, 'plgssn': 59896, 'gs': 59896, 'shgs': 59896, '+gs': 59896, '+shgs': 59896,
|
|
34
|
+
'-gr': 59897, '-shgr': 59897, '-sngr': 59898, 'gr': 59898, 'shgr': 59898, '+gr': 59898, '+shgr': 59898,
|
|
35
|
+
'-tsrasn': 59907, 'tsrasn': 59907, '-tssnra': 59907, 'tssnra': 59907, '-vctsra': 59908, '-tsra': 59908, 'tsra': 59908, '-tsdz': 59908, 'vctsra': 59908,
|
|
36
|
+
'tspl': 59909, '-tssn': 59909, '-tspl': 59909, 'tssn': 59909, '-vctssn': 59909, 'vctssn': 59909, 'tsplsn': 59909, 'tssnpl': 59909, '-tssnpl': 59909, '-tsragr': 59910,
|
|
37
|
+
'tsrags': 59910, 'tsragr': 59910, 'tsgs': 59910, 'tsgr': 59910,
|
|
38
|
+
'+tsfzrapl': 59911, '+vctsra': 59912, '+tsra': 59912, '+tsfzra': 59912, '+tssn': 59913, '+tspl': 59913, '+tsplsn': 59913, '+vctssn': 59913,
|
|
39
|
+
'tssa': 59914, 'tsds': 59914, 'tsdu': 59914, '+tsgs': 59915, '+tsgr': 59915, '+tsrags': 59915, '+tsragr': 59915, 'in': 59750,
|
|
40
|
+
'-up': 59750, 'up': 59750, '+up': 59751, '-fzup': 59756, 'fzup': 59756, '+fzup': 59757,
|
|
41
|
+
};
|
|
42
|
+
const station_plot_opts_defaults = {
|
|
43
|
+
config: {},
|
|
44
|
+
thin_fac: 1,
|
|
45
|
+
font_face: 'Trebuchet MS',
|
|
46
|
+
font_size: 12,
|
|
47
|
+
font_url_template: '',
|
|
48
|
+
};
|
|
49
|
+
function positionToAlignmentAndOffset(pos, off_size) {
|
|
50
|
+
off_size = off_size === undefined ? 10 : off_size;
|
|
51
|
+
let ha, va;
|
|
52
|
+
let xoff, yoff;
|
|
53
|
+
if (pos == 'll' || pos == 'cl' || pos == 'ul') {
|
|
54
|
+
ha = 'right';
|
|
55
|
+
xoff = -off_size;
|
|
8
56
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (min_label_lon === null || coord.lon < min_label_lon)
|
|
13
|
-
min_label_lon = coord.lon;
|
|
14
|
-
if (max_label_lon === null || coord.lon > max_label_lon)
|
|
15
|
-
max_label_lon = coord.lon;
|
|
16
|
-
if (min_label_lat === null || coord.lat < min_label_lat)
|
|
17
|
-
min_label_lat = coord.lat;
|
|
18
|
-
if (max_label_lat === null || coord.lat > max_label_lat)
|
|
19
|
-
max_label_lat = coord.lat;
|
|
20
|
-
});
|
|
21
|
-
if (min_label_lon === null || min_label_lat === null || max_label_lon === null || max_label_lat === null)
|
|
22
|
-
return [];
|
|
23
|
-
const kd_nodes = this.coords.map(c => ({ lon: c.lon, lat: c.lat, min_zoom: map_max_zoom }));
|
|
24
|
-
const tree = new kdTree(kd_nodes, (a, b) => Math.hypot(a.lon - b.lon, a.lat - b.lat), ['lon', 'lat']);
|
|
25
|
-
const { x: min_label_x, y: max_label_y } = new LngLat(min_label_lon, min_label_lat).toMercatorCoord();
|
|
26
|
-
const { x: max_label_x, y: min_label_y } = new LngLat(max_label_lon, max_label_lat).toMercatorCoord();
|
|
27
|
-
const thin_grid_width = max_label_x - min_label_x;
|
|
28
|
-
const thin_grid_height = max_label_y - min_label_y;
|
|
29
|
-
const ni_thin_grid = Math.round(thin_grid_width * thin_fac); // thin_fac was 4 / contour_label_spacing for the contour labels
|
|
30
|
-
const nj_thin_grid = Math.round(thin_grid_height * thin_fac);
|
|
31
|
-
const thin_grid_xs = [];
|
|
32
|
-
const thin_grid_ys = [];
|
|
33
|
-
for (let idx = 0; idx < ni_thin_grid; idx++) {
|
|
34
|
-
thin_grid_xs.push(min_label_x + (idx / ni_thin_grid) * thin_grid_width);
|
|
35
|
-
}
|
|
36
|
-
for (let jdy = 0; jdy < nj_thin_grid; jdy++) {
|
|
37
|
-
thin_grid_ys.push(min_label_y + (jdy / nj_thin_grid) * thin_grid_height);
|
|
38
|
-
}
|
|
39
|
-
for (let idx = 0; idx < ni_thin_grid; idx++) {
|
|
40
|
-
for (let jdy = 0; jdy < nj_thin_grid; jdy++) {
|
|
41
|
-
const zoom = getMinZoom(jdy, idx, Math.pow(2, map_max_zoom));
|
|
42
|
-
const grid_x = thin_grid_xs[idx];
|
|
43
|
-
const grid_y = thin_grid_ys[jdy];
|
|
44
|
-
const ll = LngLat.fromMercatorCoord(grid_x, grid_y);
|
|
45
|
-
const [label, dist] = tree.nearest({ lon: ll.lng, lat: ll.lat, min_zoom: 0 }, 1)[0];
|
|
46
|
-
label.min_zoom = zoom;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return kd_nodes.map(n => n.min_zoom);
|
|
57
|
+
else if (pos == 'lc' || pos == 'c' || pos == 'uc') {
|
|
58
|
+
ha = 'center';
|
|
59
|
+
xoff = 0;
|
|
50
60
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
else {
|
|
62
|
+
ha = 'left';
|
|
63
|
+
xoff = off_size;
|
|
64
|
+
}
|
|
65
|
+
if (pos == 'll' || pos == 'lc' || pos == 'lr') {
|
|
66
|
+
va = 'top';
|
|
67
|
+
yoff = -off_size;
|
|
68
|
+
}
|
|
69
|
+
else if (pos == 'cl' || pos == 'c' || pos == 'cr') {
|
|
70
|
+
va = 'middle';
|
|
71
|
+
yoff = 0;
|
|
56
72
|
}
|
|
73
|
+
else {
|
|
74
|
+
va = 'baseline';
|
|
75
|
+
yoff = off_size;
|
|
76
|
+
}
|
|
77
|
+
return { horizontal_align: ha, vertical_align: va, offset_x: xoff, offset_y: yoff };
|
|
57
78
|
}
|
|
58
|
-
const station_plot_opts_defaults = {};
|
|
59
79
|
class StationPlot extends PlotComponent {
|
|
60
|
-
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param field
|
|
83
|
+
* @param opts
|
|
84
|
+
*/
|
|
85
|
+
constructor(field, opts) {
|
|
61
86
|
super();
|
|
62
87
|
this.field = field;
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
88
|
+
this.opts = normalizeOptions(opts, station_plot_opts_defaults); // Is there a way to do this without invoking `as`?
|
|
89
|
+
this.gl_elems = null;
|
|
90
|
+
this.text_components = null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Update the data displayed as station plots
|
|
94
|
+
* @param field - The new field to display as station plots
|
|
95
|
+
*/
|
|
96
|
+
async updateField(field) {
|
|
97
|
+
this.field = field;
|
|
98
|
+
if (this.gl_elems === null)
|
|
99
|
+
return;
|
|
100
|
+
const map = this.gl_elems.map;
|
|
101
|
+
const gl = this.gl_elems.gl;
|
|
102
|
+
const barb_components = this.gl_elems.barb_components;
|
|
103
|
+
const map_style = map.getStyle();
|
|
104
|
+
const font_url_template = this.opts.font_url_template == '' ? map_style.glyphs : this.opts.font_url_template;
|
|
105
|
+
if (font_url_template === undefined)
|
|
106
|
+
throw "The map style doesn't have any glyph information. Please pass the font_url_template option to StationPlot";
|
|
107
|
+
const font_url = font_url_template.replace('{fontstack}', this.opts.font_face);
|
|
108
|
+
let ibarb = 0;
|
|
109
|
+
const sub_component_promises = Object.entries(this.opts.config).map(async ([k_, config]) => {
|
|
110
|
+
const k = k_;
|
|
111
|
+
if (config.type == 'number' || config.type == 'string') {
|
|
112
|
+
const pos = config.pos;
|
|
113
|
+
const color_opt = config.color;
|
|
114
|
+
const color = color_opt === undefined ? Color.fromHex('#000000') : Color.normalizeColor(color_opt);
|
|
115
|
+
const coords = this.field.grid.getEarthCoords();
|
|
116
|
+
const zoom = this.field.grid.getMinVisibleZoom(this.opts.thin_fac);
|
|
117
|
+
let text_specs;
|
|
118
|
+
if (config.type == 'number') {
|
|
119
|
+
const comp = this.field.getScalar(k);
|
|
120
|
+
const formatter = config.formatter === undefined ? (val) => val === null ? 'null' : val.toString() : config.formatter;
|
|
121
|
+
text_specs = comp.map((v, i) => ({ text: formatter(v), lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const comp = this.field.getStrings(k);
|
|
125
|
+
text_specs = comp.map((v, i) => ({ text: v === null ? '' : v, lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
|
|
126
|
+
}
|
|
127
|
+
const tc_opts = {
|
|
128
|
+
...positionToAlignmentAndOffset(pos),
|
|
129
|
+
font_size: this.opts.font_size, halo: true,
|
|
130
|
+
text_color: color, halo_color: Color.fromHex('#ffffff'),
|
|
131
|
+
};
|
|
132
|
+
return await TextCollection.make(gl, text_specs, font_url, tc_opts);
|
|
133
|
+
}
|
|
134
|
+
else if (config.type == 'barb') {
|
|
135
|
+
const comp = this.field.getVector(k);
|
|
136
|
+
const barb_comp = barb_components[ibarb++];
|
|
137
|
+
barb_comp.updateField(comp);
|
|
138
|
+
}
|
|
139
|
+
else if (config.type == 'symbol') {
|
|
140
|
+
const pos = config.pos;
|
|
141
|
+
const color_opt = config.color;
|
|
142
|
+
const color = color_opt === undefined ? Color.fromHex('#000000') : Color.normalizeColor(color_opt);
|
|
143
|
+
const comp = this.field.getStrings(k);
|
|
144
|
+
const coords = this.field.grid.getEarthCoords();
|
|
145
|
+
const zoom = this.field.grid.getMinVisibleZoom(this.opts.thin_fac);
|
|
146
|
+
const wxsym_font_url = font_url_template.replace('{fontstack}', 'wx_symbols');
|
|
147
|
+
const text_specs = comp.map((v, i) => ({ text: v === null ? '' : String.fromCharCode(SYMBOLS[v]),
|
|
148
|
+
lat: coords.lats[i], lon: coords.lons[i], min_zoom: zoom[i] }));
|
|
149
|
+
const tc_opts = {
|
|
150
|
+
...positionToAlignmentAndOffset(pos),
|
|
151
|
+
font_size: this.opts.font_size, halo: true,
|
|
152
|
+
text_color: color, halo_color: Color.fromHex('#ffffff'),
|
|
153
|
+
};
|
|
154
|
+
if (tc_opts.offset_x !== undefined)
|
|
155
|
+
tc_opts.offset_x -= 3;
|
|
156
|
+
return await TextCollection.make(gl, text_specs, wxsym_font_url, tc_opts);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
throw `Unknown station plot configuration type ${config.type}`;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
this.text_components = (await Promise.all(sub_component_promises)).filter((c) => c !== undefined);
|
|
163
|
+
map.triggerRepaint();
|
|
65
164
|
}
|
|
165
|
+
/** @internal */
|
|
66
166
|
async onAdd(map, gl) {
|
|
167
|
+
const barb_promises = Object.entries(this.opts.config).map(async ([k_, config]) => {
|
|
168
|
+
const k = k_;
|
|
169
|
+
if (config.type == 'barb') {
|
|
170
|
+
const comp = this.field.getVector(k);
|
|
171
|
+
const color = config.color === undefined ? '#000000' : config.color;
|
|
172
|
+
const barb_size = config.barb_size_multipler === undefined ? 1 : config.barb_size_multipler;
|
|
173
|
+
const barb_comp = new Barbs(comp, { thin_fac: this.opts.thin_fac, color: color, barb_size_multiplier: barb_size });
|
|
174
|
+
await barb_comp.onAdd(map, gl);
|
|
175
|
+
return barb_comp;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
const barb_components = (await Promise.all(barb_promises)).filter((c) => c !== undefined);
|
|
179
|
+
this.gl_elems = {
|
|
180
|
+
map: map, gl: gl, barb_components: barb_components
|
|
181
|
+
};
|
|
182
|
+
this.updateField(this.field);
|
|
67
183
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
184
|
+
/** @internal */
|
|
185
|
+
render(gl, arg) {
|
|
186
|
+
if (this.gl_elems === null || this.text_components === null)
|
|
187
|
+
return;
|
|
188
|
+
const gl_elems = this.gl_elems;
|
|
189
|
+
const text_components = this.text_components;
|
|
190
|
+
const barb_components = this.gl_elems.barb_components;
|
|
191
|
+
const map_width = gl_elems.map.getCanvas().width;
|
|
192
|
+
const map_height = gl_elems.map.getCanvas().height;
|
|
193
|
+
const map_zoom = gl_elems.map.getZoom();
|
|
194
|
+
let itext = 0, ibarb = 0;
|
|
195
|
+
Object.values(this.opts.config).forEach(comp => {
|
|
196
|
+
if (comp.type == 'barb') {
|
|
197
|
+
barb_components[ibarb++].render(gl, arg);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
text_components[itext++].render(gl, arg, [map_width, map_height], map_zoom);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
71
203
|
}
|
|
72
204
|
}
|
|
73
|
-
export
|
|
205
|
+
export default StationPlot;
|
package/lib/TextCollection.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { RenderMethodArg, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
|
-
import {
|
|
3
|
+
import { ShaderProgramManager } from "./ShaderManager";
|
|
4
|
+
import { WGLBuffer, WGLTexture } from "autumn-wgl";
|
|
4
5
|
interface TextSpec {
|
|
5
6
|
lat: number;
|
|
6
7
|
lon: number;
|
|
@@ -16,17 +17,19 @@ interface TextCollectionOptions {
|
|
|
16
17
|
text_color?: Color;
|
|
17
18
|
halo_color?: Color;
|
|
18
19
|
halo?: boolean;
|
|
20
|
+
offset_x?: number;
|
|
21
|
+
offset_y?: number;
|
|
19
22
|
}
|
|
20
23
|
declare class TextCollection {
|
|
21
|
-
readonly
|
|
24
|
+
readonly shader_manager: ShaderProgramManager;
|
|
22
25
|
readonly anchors: WGLBuffer;
|
|
23
26
|
readonly offsets: WGLBuffer;
|
|
24
27
|
readonly texcoords: WGLBuffer;
|
|
25
28
|
readonly texture: WGLTexture;
|
|
26
29
|
readonly opts: Required<TextCollectionOptions>;
|
|
27
30
|
private constructor();
|
|
28
|
-
static make(gl: WebGLAnyRenderingContext, text_locs: TextSpec[],
|
|
29
|
-
render(gl: WebGLAnyRenderingContext,
|
|
31
|
+
static make(gl: WebGLAnyRenderingContext, text_locs: TextSpec[], fontstack_url_template: string, opts?: TextCollectionOptions): Promise<TextCollection>;
|
|
32
|
+
render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg, [map_width, map_height]: [number, number], map_zoom: number): void;
|
|
30
33
|
}
|
|
31
34
|
export { TextCollection };
|
|
32
|
-
export type { TextSpec, TextCollectionOptions };
|
|
35
|
+
export type { TextSpec, TextCollectionOptions, HorizontalAlign, VerticalAlign };
|