gridviz 3.0.35 → 3.0.36
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 +129 -129
- package/dist/gridviz.js +17486 -17486
- package/dist/gridviz.min.js +2 -2
- package/package.json +73 -73
- package/src/button/Button.js +67 -67
- package/src/button/FullscreenButton.js +121 -121
- package/src/button/ZoomButtons.js +103 -103
- package/src/core/Dataset.js +154 -154
- package/src/core/Drawable.js +78 -78
- package/src/core/GeoCanvas.js +443 -443
- package/src/core/Layer.js +23 -23
- package/src/core/Legend.js +108 -108
- package/src/core/Map.js +568 -568
- package/src/core/MultiResolutionDataset.js +93 -93
- package/src/core/Style.js +98 -98
- package/src/core/Tooltip.js +182 -182
- package/src/dataset/COGeo.js +25 -25
- package/src/dataset/CSVGrid.js +112 -112
- package/src/dataset/GeoTIFF.js +122 -122
- package/src/dataset/JSGrid.js +55 -55
- package/src/dataset/TiledGrid.js +302 -302
- package/src/dataset/worker.js +18 -18
- package/src/index.js +79 -79
- package/src/layer/BackgroundLayer.js +173 -173
- package/src/layer/BackgroundLayerImage.js +81 -81
- package/src/layer/BackgroundLayerWMS.js +104 -104
- package/src/layer/GeoJSONLayer.js +276 -276
- package/src/layer/GridLayer.js +166 -166
- package/src/layer/LabelLayer.js +194 -194
- package/src/legend/ColorCategoryLegend.js +109 -109
- package/src/legend/ColorDiscreteLegend.js +100 -100
- package/src/legend/ColorLegend.js +115 -115
- package/src/legend/OrientationLegend.js +89 -89
- package/src/legend/SizeLegend.js +224 -224
- package/src/legend/TernaryLegend.js +302 -302
- package/src/style/CompositionStyle.js +291 -291
- package/src/style/DotDensityStyle.js +133 -133
- package/src/style/ImageStyle.js +100 -100
- package/src/style/Interpolator.js +258 -258
- package/src/style/IsoFenceStyle.js +217 -217
- package/src/style/JoyPlotStyle.js +180 -180
- package/src/style/LegoStyle.js +132 -132
- package/src/style/MosaicStyle.js +99 -99
- package/src/style/NinjaStarStyle.js +102 -102
- package/src/style/PillarStyle.js +207 -207
- package/src/style/SegmentStyle.js +105 -105
- package/src/style/ShadingRayStyle.js +280 -280
- package/src/style/ShadingStyle.js +72 -72
- package/src/style/ShapeColorSizeStyle.js +147 -147
- package/src/style/SideCategoryStyle.js +112 -112
- package/src/style/SideStyle.js +217 -217
- package/src/style/SideTanakaStyle.js +154 -154
- package/src/style/SquareColorCategoryWebGLStyle.js +307 -294
- package/src/style/SquareColorWebGLStyle.js +126 -126
- package/src/style/StrokeStyle.js +135 -135
- package/src/style/TextStyle.js +110 -110
- package/src/style/TimeSeriesStyle.js +222 -222
- package/src/utils/WebGLRectangleColoring.js +106 -106
- package/src/utils/WebGLSquareColoring.js +118 -118
- package/src/utils/WebGLSquareColoringAdvanced.js +227 -227
- package/src/utils/WebGLSquareColoringKS.js +153 -153
- package/src/utils/scale.js +255 -255
- package/src/utils/stretching.js +120 -120
- package/src/utils/ternary.js +208 -208
- package/src/utils/utils.js +125 -125
- package/src/utils/webGLUtils.js +73 -73
- package/src/utils/zoomUtils.js +142 -142
|
@@ -1,295 +1,308 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Style } from '../core/Style.js'
|
|
5
|
-
import { initShaderProgram, createShader, makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
-
import { color } from 'd3-color'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Style based on webGL
|
|
10
|
-
* To show cells as colored squares, from categories.
|
|
11
|
-
* All cells are drawn as squares, with the same size
|
|
12
|
-
*
|
|
13
|
-
* @module style
|
|
14
|
-
* @author Julien Gaffuri
|
|
15
|
-
*/
|
|
16
|
-
export class SquareColorCategoryWebGLStyle extends Style {
|
|
17
|
-
/** @param {object} opts */
|
|
18
|
-
constructor(opts) {
|
|
19
|
-
super(opts)
|
|
20
|
-
opts = opts || {}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* A function returning the category code of the cell, for coloring.
|
|
24
|
-
* @type {function(import('../core/Dataset.js').Cell, number, number, viewScale):string} */
|
|
25
|
-
this.code = opts.code // (c, resolution, z, viewScale) => "code1"
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* The dictionary (code -> color) which gives the color of each category code.
|
|
29
|
-
* @type {object} */
|
|
30
|
-
opts.color = opts.color || undefined
|
|
31
|
-
|
|
32
|
-
/** @type { Array.<string> } */
|
|
33
|
-
const codes = Object.keys(opts.color)
|
|
34
|
-
|
|
35
|
-
/** @type { object } @private */
|
|
36
|
-
this.catToI = {}
|
|
37
|
-
for (let i = 0; i < codes.length; i++) this.catToI[codes[i]] = i + ''
|
|
38
|
-
|
|
39
|
-
/** @type { Array.<string> } @private */
|
|
40
|
-
this.colors = []
|
|
41
|
-
for (const code of codes) this.colors.push(opts.color['' + code])
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* A function returning the size of the cells, in geographical unit. All cells have the same size.
|
|
45
|
-
* @type {function(number,number):number} */
|
|
46
|
-
this.size = opts.size // (resolution, z) => ...
|
|
47
|
-
|
|
48
|
-
/** * @type {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number }}*/
|
|
49
|
-
this.cvWGL = undefined
|
|
50
|
-
this.programm = undefined
|
|
51
|
-
|
|
52
|
-
this.x = undefined
|
|
53
|
-
this.y = undefined
|
|
54
|
-
this.z = undefined
|
|
55
|
-
this.cellsNb = undefined
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
init(w, h) {
|
|
59
|
-
this.cvWGL = makeWebGLCanvas(w + '', h + '')
|
|
60
|
-
if (!this.cvWGL) { console.error('No webGL'); return }
|
|
61
|
-
|
|
62
|
-
const gl = this.cvWGL.gl
|
|
63
|
-
|
|
64
|
-
//draw
|
|
65
|
-
const vectorShader = `
|
|
66
|
-
attribute vec2 pos;
|
|
67
|
-
uniform float sizePix;
|
|
68
|
-
uniform mat3 mat;
|
|
69
|
-
attribute float i;
|
|
70
|
-
varying float vi;
|
|
71
|
-
void main() {
|
|
72
|
-
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
73
|
-
gl_PointSize = sizePix;
|
|
74
|
-
vi = i;
|
|
75
|
-
}`
|
|
76
|
-
/** @type {WebGLShader} */
|
|
77
|
-
const vShader = createShader(gl, gl.VERTEX_SHADER, vectorShader)
|
|
78
|
-
|
|
79
|
-
const fragmentShader = `
|
|
80
|
-
precision highp float;
|
|
81
|
-
varying float vi;
|
|
82
|
-
uniform sampler2D colorLUT;
|
|
83
|
-
uniform float lutSize;
|
|
84
|
-
void main(void) {
|
|
85
|
-
float idx = floor(vi + 0.5);
|
|
86
|
-
float u = (idx + 0.5) / lutSize;
|
|
87
|
-
gl_FragColor = texture2D(colorLUT, vec2(u, 0.5));
|
|
88
|
-
}`
|
|
89
|
-
/** @type {WebGLShader} */
|
|
90
|
-
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader)
|
|
91
|
-
|
|
92
|
-
/** @type {WebGLProgram} */
|
|
93
|
-
this.program = initShaderProgram(gl, vShader, fShader)
|
|
94
|
-
gl.useProgram(this.program)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
bindColors() {
|
|
98
|
-
const gl = this.cvWGL.gl
|
|
99
|
-
const lutSize = this.colors.length;
|
|
100
|
-
const lutData = new Uint8Array(lutSize * 4); // RGBA for each entry
|
|
101
|
-
|
|
102
|
-
// Fill lutData with your color values (e.g., rainbow, grayscale, etc.)
|
|
103
|
-
for (let i = 0; i < lutSize; i++) {
|
|
104
|
-
const c = color(this.colors[i])
|
|
105
|
-
lutData[i * 4] = +c.r; // R
|
|
106
|
-
lutData[i * 4 + 1] = c.g; // G
|
|
107
|
-
lutData[i * 4 + 2] = c.b; // B
|
|
108
|
-
lutData[i * 4 + 3] = c?.opacity * 255; // A
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Create and bind texture
|
|
112
|
-
const lutTexture = gl.createTexture();
|
|
113
|
-
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
114
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, lutSize, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, lutData);
|
|
115
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
116
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
117
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
118
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
119
|
-
|
|
120
|
-
// Get uniform locations
|
|
121
|
-
const uColorLUT = gl.getUniformLocation(this.program, 'colorLUT');
|
|
122
|
-
const uLutSize = gl.getUniformLocation(this.program, 'lutSize');
|
|
123
|
-
|
|
124
|
-
// Set uniform values
|
|
125
|
-
gl.uniform1i(uColorLUT, 0); // Texture unit 0
|
|
126
|
-
gl.uniform1f(uLutSize, lutSize);
|
|
127
|
-
|
|
128
|
-
// Bind the texture to texture unit 0
|
|
129
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
130
|
-
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
bindVertices(cells, resolution, z, viewScale) {
|
|
134
|
-
const gl = this.cvWGL.gl
|
|
135
|
-
//add vertice and fragment data
|
|
136
|
-
const r2 = resolution / 2
|
|
137
|
-
let c, nb = cells.length
|
|
138
|
-
const verticesBuffer = []
|
|
139
|
-
const iBuffer = []
|
|
140
|
-
for (let i = 0; i < nb; i++) {
|
|
141
|
-
c = cells[i]
|
|
142
|
-
const cat = this.code(c, resolution, z, viewScale)
|
|
143
|
-
if (cat == undefined) {
|
|
144
|
-
//console.log('Unexpected category: ' + cat)
|
|
145
|
-
continue
|
|
146
|
-
}
|
|
147
|
-
const i_ = this.catToI[cat]
|
|
148
|
-
if (isNaN(+i_)) {
|
|
149
|
-
console.log('Unexpected category index: ' + cat + ' ' + i_)
|
|
150
|
-
continue
|
|
151
|
-
}
|
|
152
|
-
verticesBuffer.push(c.x + r2, c.y + r2)
|
|
153
|
-
iBuffer.push(+i_)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
//bind vertice data
|
|
157
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
158
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesBuffer), gl.STATIC_DRAW)
|
|
159
|
-
const position = gl.getAttribLocation(this.program, 'pos')
|
|
160
|
-
gl.vertexAttribPointer(
|
|
161
|
-
position,
|
|
162
|
-
2, //numComponents
|
|
163
|
-
gl.FLOAT, //type
|
|
164
|
-
false, //normalise
|
|
165
|
-
0, //stride
|
|
166
|
-
0 //offset
|
|
167
|
-
)
|
|
168
|
-
gl.enableVertexAttribArray(position)
|
|
169
|
-
|
|
170
|
-
//i data
|
|
171
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
172
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(iBuffer), gl.STATIC_DRAW)
|
|
173
|
-
const i = gl.getAttribLocation(this.program, 'i')
|
|
174
|
-
gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0)
|
|
175
|
-
gl.enableVertexAttribArray(i)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// check if the vertices have to be bound again
|
|
181
|
-
mapContentChanged(v, cellsNb) {
|
|
182
|
-
if (v.x == this.x && v.y == this.y && v.z == this.z && this.cellsNb == cellsNb) return false
|
|
183
|
-
this.x = v.x
|
|
184
|
-
this.y = v.y
|
|
185
|
-
this.z = v.z
|
|
186
|
-
this.cellsNb = cellsNb
|
|
187
|
-
return true
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
193
|
-
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
194
|
-
* @param {number} resolution
|
|
195
|
-
*/
|
|
196
|
-
draw(cells, geoCanvas, resolution) {
|
|
197
|
-
//filter
|
|
198
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
199
|
-
|
|
200
|
-
//
|
|
201
|
-
const z = geoCanvas.view.z
|
|
202
|
-
|
|
203
|
-
//get view scale
|
|
204
|
-
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
205
|
-
|
|
206
|
-
//create canvas and webgl renderer
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
//
|
|
286
|
-
//
|
|
287
|
-
out
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../core/Style.js'
|
|
5
|
+
import { initShaderProgram, createShader, makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
+
import { color } from 'd3-color'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Style based on webGL
|
|
10
|
+
* To show cells as colored squares, from categories.
|
|
11
|
+
* All cells are drawn as squares, with the same size
|
|
12
|
+
*
|
|
13
|
+
* @module style
|
|
14
|
+
* @author Julien Gaffuri
|
|
15
|
+
*/
|
|
16
|
+
export class SquareColorCategoryWebGLStyle extends Style {
|
|
17
|
+
/** @param {object} opts */
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
super(opts)
|
|
20
|
+
opts = opts || {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A function returning the category code of the cell, for coloring.
|
|
24
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, viewScale):string} */
|
|
25
|
+
this.code = opts.code // (c, resolution, z, viewScale) => "code1"
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The dictionary (code -> color) which gives the color of each category code.
|
|
29
|
+
* @type {object} */
|
|
30
|
+
opts.color = opts.color || undefined
|
|
31
|
+
|
|
32
|
+
/** @type { Array.<string> } */
|
|
33
|
+
const codes = Object.keys(opts.color)
|
|
34
|
+
|
|
35
|
+
/** @type { object } @private */
|
|
36
|
+
this.catToI = {}
|
|
37
|
+
for (let i = 0; i < codes.length; i++) this.catToI[codes[i]] = i + ''
|
|
38
|
+
|
|
39
|
+
/** @type { Array.<string> } @private */
|
|
40
|
+
this.colors = []
|
|
41
|
+
for (const code of codes) this.colors.push(opts.color['' + code])
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A function returning the size of the cells, in geographical unit. All cells have the same size.
|
|
45
|
+
* @type {function(number,number):number} */
|
|
46
|
+
this.size = opts.size // (resolution, z) => ...
|
|
47
|
+
|
|
48
|
+
/** * @type {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number }}*/
|
|
49
|
+
this.cvWGL = undefined
|
|
50
|
+
this.programm = undefined
|
|
51
|
+
|
|
52
|
+
this.x = undefined
|
|
53
|
+
this.y = undefined
|
|
54
|
+
this.z = undefined
|
|
55
|
+
this.cellsNb = undefined
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
init(w, h) {
|
|
59
|
+
this.cvWGL = makeWebGLCanvas(w + '', h + '')
|
|
60
|
+
if (!this.cvWGL) { console.error('No webGL'); return }
|
|
61
|
+
|
|
62
|
+
const gl = this.cvWGL.gl
|
|
63
|
+
|
|
64
|
+
//draw
|
|
65
|
+
const vectorShader = `
|
|
66
|
+
attribute vec2 pos;
|
|
67
|
+
uniform float sizePix;
|
|
68
|
+
uniform mat3 mat;
|
|
69
|
+
attribute float i;
|
|
70
|
+
varying float vi;
|
|
71
|
+
void main() {
|
|
72
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
73
|
+
gl_PointSize = sizePix;
|
|
74
|
+
vi = i;
|
|
75
|
+
}`
|
|
76
|
+
/** @type {WebGLShader} */
|
|
77
|
+
const vShader = createShader(gl, gl.VERTEX_SHADER, vectorShader)
|
|
78
|
+
|
|
79
|
+
const fragmentShader = `
|
|
80
|
+
precision highp float;
|
|
81
|
+
varying float vi;
|
|
82
|
+
uniform sampler2D colorLUT;
|
|
83
|
+
uniform float lutSize;
|
|
84
|
+
void main(void) {
|
|
85
|
+
float idx = floor(vi + 0.5);
|
|
86
|
+
float u = (idx + 0.5) / lutSize;
|
|
87
|
+
gl_FragColor = texture2D(colorLUT, vec2(u, 0.5));
|
|
88
|
+
}`
|
|
89
|
+
/** @type {WebGLShader} */
|
|
90
|
+
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader)
|
|
91
|
+
|
|
92
|
+
/** @type {WebGLProgram} */
|
|
93
|
+
this.program = initShaderProgram(gl, vShader, fShader)
|
|
94
|
+
gl.useProgram(this.program)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
bindColors() {
|
|
98
|
+
const gl = this.cvWGL.gl
|
|
99
|
+
const lutSize = this.colors.length;
|
|
100
|
+
const lutData = new Uint8Array(lutSize * 4); // RGBA for each entry
|
|
101
|
+
|
|
102
|
+
// Fill lutData with your color values (e.g., rainbow, grayscale, etc.)
|
|
103
|
+
for (let i = 0; i < lutSize; i++) {
|
|
104
|
+
const c = color(this.colors[i])
|
|
105
|
+
lutData[i * 4] = +c.r; // R
|
|
106
|
+
lutData[i * 4 + 1] = c.g; // G
|
|
107
|
+
lutData[i * 4 + 2] = c.b; // B
|
|
108
|
+
lutData[i * 4 + 3] = c?.opacity * 255; // A
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Create and bind texture
|
|
112
|
+
const lutTexture = gl.createTexture();
|
|
113
|
+
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
114
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, lutSize, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, lutData);
|
|
115
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
116
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
117
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
118
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
119
|
+
|
|
120
|
+
// Get uniform locations
|
|
121
|
+
const uColorLUT = gl.getUniformLocation(this.program, 'colorLUT');
|
|
122
|
+
const uLutSize = gl.getUniformLocation(this.program, 'lutSize');
|
|
123
|
+
|
|
124
|
+
// Set uniform values
|
|
125
|
+
gl.uniform1i(uColorLUT, 0); // Texture unit 0
|
|
126
|
+
gl.uniform1f(uLutSize, lutSize);
|
|
127
|
+
|
|
128
|
+
// Bind the texture to texture unit 0
|
|
129
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
130
|
+
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
bindVertices(cells, resolution, z, viewScale) {
|
|
134
|
+
const gl = this.cvWGL.gl
|
|
135
|
+
//add vertice and fragment data
|
|
136
|
+
const r2 = resolution / 2
|
|
137
|
+
let c, nb = cells.length
|
|
138
|
+
const verticesBuffer = []
|
|
139
|
+
const iBuffer = []
|
|
140
|
+
for (let i = 0; i < nb; i++) {
|
|
141
|
+
c = cells[i]
|
|
142
|
+
const cat = this.code(c, resolution, z, viewScale)
|
|
143
|
+
if (cat == undefined) {
|
|
144
|
+
//console.log('Unexpected category: ' + cat)
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
const i_ = this.catToI[cat]
|
|
148
|
+
if (isNaN(+i_)) {
|
|
149
|
+
console.log('Unexpected category index: ' + cat + ' ' + i_)
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
verticesBuffer.push(c.x + r2, c.y + r2)
|
|
153
|
+
iBuffer.push(+i_)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//bind vertice data
|
|
157
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
158
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesBuffer), gl.STATIC_DRAW)
|
|
159
|
+
const position = gl.getAttribLocation(this.program, 'pos')
|
|
160
|
+
gl.vertexAttribPointer(
|
|
161
|
+
position,
|
|
162
|
+
2, //numComponents
|
|
163
|
+
gl.FLOAT, //type
|
|
164
|
+
false, //normalise
|
|
165
|
+
0, //stride
|
|
166
|
+
0 //offset
|
|
167
|
+
)
|
|
168
|
+
gl.enableVertexAttribArray(position)
|
|
169
|
+
|
|
170
|
+
//i data
|
|
171
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
172
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(iBuffer), gl.STATIC_DRAW)
|
|
173
|
+
const i = gl.getAttribLocation(this.program, 'i')
|
|
174
|
+
gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0)
|
|
175
|
+
gl.enableVertexAttribArray(i)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
// check if the vertices have to be bound again
|
|
181
|
+
mapContentChanged(v, cellsNb) {
|
|
182
|
+
if (v.x == this.x && v.y == this.y && v.z == this.z && this.cellsNb == cellsNb) return false
|
|
183
|
+
this.x = v.x
|
|
184
|
+
this.y = v.y
|
|
185
|
+
this.z = v.z
|
|
186
|
+
this.cellsNb = cellsNb
|
|
187
|
+
return true
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
193
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
194
|
+
* @param {number} resolution
|
|
195
|
+
*/
|
|
196
|
+
draw(cells, geoCanvas, resolution) {
|
|
197
|
+
//filter
|
|
198
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
199
|
+
|
|
200
|
+
//
|
|
201
|
+
const z = geoCanvas.view.z
|
|
202
|
+
|
|
203
|
+
//get view scale
|
|
204
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
205
|
+
|
|
206
|
+
//create canvas and webgl renderer
|
|
207
|
+
let contextRecreated = false
|
|
208
|
+
if (!this.cvWGL || geoCanvas.w != this.cvWGL.width || geoCanvas.h != this.cvWGL.height) {
|
|
209
|
+
contextRecreated = true
|
|
210
|
+
this.init(geoCanvas.w, geoCanvas.h)
|
|
211
|
+
this.bindColors()
|
|
212
|
+
}
|
|
213
|
+
const gl = this.cvWGL.gl
|
|
214
|
+
const canvas = this.cvWGL.canvas
|
|
215
|
+
|
|
216
|
+
//bind sizePix
|
|
217
|
+
const sizePix = this.size ? this.size(resolution, z) / z : resolution / z + 0.2
|
|
218
|
+
gl.uniform1f(gl.getUniformLocation(this.program, 'sizePix'), 1.0 * sizePix)
|
|
219
|
+
|
|
220
|
+
//
|
|
221
|
+
// mapContentChanged() is a cheap proxy for "did the content change" based
|
|
222
|
+
// on view x/y/z and cell count alone - it has no idea the WebGL context
|
|
223
|
+
// itself was just thrown away and recreated a few lines up (geoCanvas.w/h
|
|
224
|
+
// changing, e.g. from a browser/devtools resize, recreates cvWGL with a
|
|
225
|
+
// fresh, empty vertex buffer). A resize alone often leaves the geographic
|
|
226
|
+
// view and cell count identical to the previous draw, so without forcing
|
|
227
|
+
// a rebind here, mapContentChanged reports "unchanged" and the rebind gets
|
|
228
|
+
// skipped - leaving the new context's vertex buffer never populated and
|
|
229
|
+
// gl.drawArrays() drawing nothing, silently (confirmed via a resize-storm
|
|
230
|
+
// test: reinit-without-rebind happened on 5 of 9 context recreations).
|
|
231
|
+
const shouldRebind = this.mapContentChanged(geoCanvas.view, cells.length) || contextRecreated
|
|
232
|
+
if (shouldRebind)
|
|
233
|
+
//bind vertices
|
|
234
|
+
this.bindVertices(cells, resolution, z, viewScale)
|
|
235
|
+
//transformation
|
|
236
|
+
gl.uniformMatrix3fv(gl.getUniformLocation(this.program, 'mat'), false, new Float32Array(geoCanvas.getWebGLTransform()))
|
|
237
|
+
|
|
238
|
+
// Enable the depth test
|
|
239
|
+
//gl.enable(gl.DEPTH_TEST);
|
|
240
|
+
// Clear the color buffer bit
|
|
241
|
+
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
242
|
+
// Set the view port
|
|
243
|
+
//gl.viewport(0, 0, cg.w, cg.h);
|
|
244
|
+
|
|
245
|
+
gl.drawArrays(gl.POINTS, 0, cells.length)
|
|
246
|
+
|
|
247
|
+
//draw in canvas geo
|
|
248
|
+
geoCanvas.initCanvasTransform()
|
|
249
|
+
geoCanvas.offscreenCtx.drawImage(canvas, 0, 0)
|
|
250
|
+
|
|
251
|
+
//update legends
|
|
252
|
+
this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
// early tests for webgl2 migration
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
function getVectorShader2() {
|
|
262
|
+
return `
|
|
263
|
+
#version 300 es
|
|
264
|
+
precision highp float;
|
|
265
|
+
|
|
266
|
+
in vec2 pos;
|
|
267
|
+
in int i;
|
|
268
|
+
|
|
269
|
+
uniform float sizePix;
|
|
270
|
+
uniform mat3 mat;
|
|
271
|
+
|
|
272
|
+
flat out int vi;
|
|
273
|
+
|
|
274
|
+
void main() {
|
|
275
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
276
|
+
gl_PointSize = sizePix;
|
|
277
|
+
vi = i;
|
|
278
|
+
}
|
|
279
|
+
`
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
function getFragmentShader2(colors) {
|
|
284
|
+
|
|
285
|
+
//prepare fragment shader code
|
|
286
|
+
//declare the uniform and other variables
|
|
287
|
+
const out = []
|
|
288
|
+
out.push('#version 300 es\nprecision highp float;\nflat in int vi;\n')
|
|
289
|
+
|
|
290
|
+
//add color uniforms
|
|
291
|
+
//uniform vec4 colors[12];
|
|
292
|
+
out.push('uniform vec4 colors[')
|
|
293
|
+
out.push(colors.length)
|
|
294
|
+
out.push('];\n')
|
|
295
|
+
|
|
296
|
+
out.push('out vec4 fragColor;\n')
|
|
297
|
+
|
|
298
|
+
//start the main function
|
|
299
|
+
//void main() { fragColor = colors[clamp(vi, 0, 11)]; }
|
|
300
|
+
out.push('void main() { fragColor = colors[vi]; }\n')
|
|
301
|
+
|
|
302
|
+
/** Fragment shader program
|
|
303
|
+
const fshString = out.join('')
|
|
304
|
+
console.log(fshString)
|
|
305
|
+
return fshString
|
|
306
|
+
}
|
|
307
|
+
|
|
295
308
|
*/
|