gridviz 3.0.36 → 3.0.37
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/dist/gridviz.js +6506 -2937
- package/dist/gridviz.min.js +1 -1
- package/package.json +2 -2
- package/src/core/Dataset.js +78 -0
- package/src/core/Map.js +91 -9
- package/src/dataset/TiledGrid.js +24 -15
- package/src/style/DotDensityStyle.js +3 -3
- package/src/style/SquareColorCategoryWebGLStyle.js +123 -119
- package/src/style/SquareColorWebGLStyle.js +5 -5
- package/src/utils/WebGLSquareColoring.js +28 -32
- package/src/utils/WebGLSquareColoringAdvanced.js +26 -30
- package/src/utils/webGLUtils.js +105 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
import { Style } from '../core/Style.js'
|
|
5
|
-
import {
|
|
5
|
+
import { getSharedWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
6
|
import { WebGLSquareColoringAdvanced } from '../utils/WebGLSquareColoringAdvanced.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -80,11 +80,11 @@ export class SquareColorWebGLStyle extends Style {
|
|
|
80
80
|
//get view scale
|
|
81
81
|
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
82
82
|
|
|
83
|
-
//
|
|
83
|
+
//the shared webgl canvas (one context for all styles, instead of a new one per draw)
|
|
84
84
|
//for opacity control, see: https://webglfundamentals.org/webgl/lessons/webgl-and-alpha.html
|
|
85
|
-
const cvWGL =
|
|
86
|
-
geoCanvas.w
|
|
87
|
-
geoCanvas.h
|
|
85
|
+
const cvWGL = getSharedWebGLCanvas(
|
|
86
|
+
geoCanvas.w,
|
|
87
|
+
geoCanvas.h,
|
|
88
88
|
this.opacity != undefined ? { premultipliedAlpha: false } : undefined
|
|
89
89
|
)
|
|
90
90
|
if (!cvWGL) {
|
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getProgram, getBuffer } from './webGLUtils.js'
|
|
5
5
|
import { color } from 'd3-color'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
* Everything to easily draw colored squares with webGL.
|
|
9
|
-
* All the same size, but different fill color.
|
|
10
|
-
*/
|
|
11
|
-
export class WebGLSquareColoring {
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
* @param {WebGLRenderingContext} gl
|
|
15
|
-
*/
|
|
16
|
-
constructor(gl, sizePix) {
|
|
17
|
-
this.gl = gl
|
|
18
|
-
this.sizePix = sizePix || 10.0
|
|
19
|
-
|
|
20
|
-
this.program = initShaderProgram(
|
|
21
|
-
gl,
|
|
22
|
-
createShader(
|
|
23
|
-
gl,
|
|
24
|
-
gl.VERTEX_SHADER,
|
|
25
|
-
`
|
|
7
|
+
const VERTEX_SHADER = `
|
|
26
8
|
attribute vec2 pos;
|
|
27
9
|
uniform float sizePix;
|
|
28
10
|
uniform mat3 mat;
|
|
@@ -34,11 +16,8 @@ export class WebGLSquareColoring {
|
|
|
34
16
|
vColor = color;
|
|
35
17
|
}
|
|
36
18
|
`
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
gl,
|
|
40
|
-
gl.FRAGMENT_SHADER,
|
|
41
|
-
`
|
|
19
|
+
|
|
20
|
+
const FRAGMENT_SHADER = `
|
|
42
21
|
precision mediump float;
|
|
43
22
|
varying vec4 vColor;
|
|
44
23
|
void main(void) {
|
|
@@ -46,8 +25,22 @@ export class WebGLSquareColoring {
|
|
|
46
25
|
vColor_[3] = 255.0 * vColor_[3];
|
|
47
26
|
gl_FragColor = vColor_;
|
|
48
27
|
}`
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Everything to easily draw colored squares with webGL.
|
|
31
|
+
* All the same size, but different fill color.
|
|
32
|
+
*/
|
|
33
|
+
export class WebGLSquareColoring {
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param {WebGLRenderingContext} gl
|
|
37
|
+
*/
|
|
38
|
+
constructor(gl, sizePix) {
|
|
39
|
+
this.gl = gl
|
|
40
|
+
this.sizePix = sizePix || 10.0
|
|
41
|
+
|
|
42
|
+
// compiled once per context, then reused
|
|
43
|
+
this.program = getProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER)
|
|
51
44
|
gl.useProgram(this.program)
|
|
52
45
|
|
|
53
46
|
//buffer data
|
|
@@ -79,9 +72,11 @@ export class WebGLSquareColoring {
|
|
|
79
72
|
draw(transfoMat) {
|
|
80
73
|
const gl = this.gl
|
|
81
74
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
gl.useProgram(this.program)
|
|
76
|
+
|
|
77
|
+
//vertice data, in a buffer reused from draw to draw
|
|
78
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, getBuffer(gl, 'WebGLSquareColoring.pos'))
|
|
79
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.verticesBuffer), gl.DYNAMIC_DRAW)
|
|
85
80
|
const position = gl.getAttribLocation(this.program, 'pos')
|
|
86
81
|
gl.vertexAttribPointer(
|
|
87
82
|
position,
|
|
@@ -94,8 +89,8 @@ export class WebGLSquareColoring {
|
|
|
94
89
|
gl.enableVertexAttribArray(position)
|
|
95
90
|
|
|
96
91
|
//color data
|
|
97
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, gl.
|
|
98
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.colorsBuffer), gl.
|
|
92
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, getBuffer(gl, 'WebGLSquareColoring.color'))
|
|
93
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.colorsBuffer), gl.DYNAMIC_DRAW)
|
|
99
94
|
var color = gl.getAttribLocation(this.program, 'color')
|
|
100
95
|
gl.vertexAttribPointer(color, 4, gl.FLOAT, false, 0, 0)
|
|
101
96
|
gl.enableVertexAttribArray(color)
|
|
@@ -109,6 +104,7 @@ export class WebGLSquareColoring {
|
|
|
109
104
|
// Enable the depth test
|
|
110
105
|
//gl.enable(gl.DEPTH_TEST);
|
|
111
106
|
// Clear the color buffer bit
|
|
107
|
+
gl.clearColor(0, 0, 0, 0)
|
|
112
108
|
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
113
109
|
// Set the view port
|
|
114
110
|
//gl.viewport(0, 0, cg.w, cg.h);
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getProgram, getBuffer } from './webGLUtils.js'
|
|
5
5
|
import { color } from 'd3-color'
|
|
6
6
|
|
|
7
|
+
const VERTEX_SHADER = `
|
|
8
|
+
attribute vec2 pos;
|
|
9
|
+
uniform float sizePix;
|
|
10
|
+
uniform mat3 mat;
|
|
11
|
+
|
|
12
|
+
attribute float t;
|
|
13
|
+
varying float vt;
|
|
14
|
+
|
|
15
|
+
void main() {
|
|
16
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
17
|
+
gl_PointSize = sizePix;
|
|
18
|
+
vt = t;
|
|
19
|
+
}
|
|
20
|
+
`
|
|
21
|
+
|
|
7
22
|
/**
|
|
8
23
|
* Everything to easily draw colored squares with webGL.
|
|
9
24
|
* All the same size, but different fill color.
|
|
@@ -31,26 +46,6 @@ export class WebGLSquareColoringAdvanced {
|
|
|
31
46
|
//gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
32
47
|
//gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
33
48
|
|
|
34
|
-
/** @type {WebGLShader} */
|
|
35
|
-
const vShader = createShader(
|
|
36
|
-
gl,
|
|
37
|
-
gl.VERTEX_SHADER,
|
|
38
|
-
`
|
|
39
|
-
attribute vec2 pos;
|
|
40
|
-
uniform float sizePix;
|
|
41
|
-
uniform mat3 mat;
|
|
42
|
-
|
|
43
|
-
attribute float t;
|
|
44
|
-
varying float vt;
|
|
45
|
-
|
|
46
|
-
void main() {
|
|
47
|
-
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
48
|
-
gl_PointSize = sizePix;
|
|
49
|
-
vt = t;
|
|
50
|
-
}
|
|
51
|
-
`
|
|
52
|
-
)
|
|
53
|
-
|
|
54
49
|
//prepare fragment shader code
|
|
55
50
|
//declare the uniform and other variables
|
|
56
51
|
const fshBuff = []
|
|
@@ -157,11 +152,9 @@ export class WebGLSquareColoringAdvanced {
|
|
|
157
152
|
//let fshString = fshBuff.join("\n")
|
|
158
153
|
//console.log(fshString)
|
|
159
154
|
|
|
160
|
-
|
|
161
|
-
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fshString)
|
|
162
|
-
|
|
155
|
+
// compiled once per context and fragment source (colours, stretching), then reused
|
|
163
156
|
/** @type {WebGLProgram} */
|
|
164
|
-
this.program =
|
|
157
|
+
this.program = getProgram(gl, VERTEX_SHADER, fshString)
|
|
165
158
|
gl.useProgram(this.program)
|
|
166
159
|
|
|
167
160
|
//set uniforms
|
|
@@ -191,9 +184,11 @@ export class WebGLSquareColoringAdvanced {
|
|
|
191
184
|
const gl = this.gl
|
|
192
185
|
const program = this.program
|
|
193
186
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
187
|
+
gl.useProgram(program)
|
|
188
|
+
|
|
189
|
+
//vertice data, in a buffer reused from draw to draw
|
|
190
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, getBuffer(gl, 'WebGLSquareColoringAdvanced.pos'))
|
|
191
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesBuffer), gl.DYNAMIC_DRAW)
|
|
197
192
|
const position = gl.getAttribLocation(program, 'pos')
|
|
198
193
|
gl.vertexAttribPointer(
|
|
199
194
|
position,
|
|
@@ -206,8 +201,8 @@ export class WebGLSquareColoringAdvanced {
|
|
|
206
201
|
gl.enableVertexAttribArray(position)
|
|
207
202
|
|
|
208
203
|
//t data
|
|
209
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, gl.
|
|
210
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tBuffer), gl.
|
|
204
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, getBuffer(gl, 'WebGLSquareColoringAdvanced.t'))
|
|
205
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tBuffer), gl.DYNAMIC_DRAW)
|
|
211
206
|
const t = gl.getAttribLocation(program, 't')
|
|
212
207
|
gl.vertexAttribPointer(t, 1, gl.FLOAT, false, 0, 0)
|
|
213
208
|
gl.enableVertexAttribArray(t)
|
|
@@ -218,6 +213,7 @@ export class WebGLSquareColoringAdvanced {
|
|
|
218
213
|
// Enable the depth test
|
|
219
214
|
//gl.enable(gl.DEPTH_TEST);
|
|
220
215
|
// Clear the color buffer bit
|
|
216
|
+
gl.clearColor(0, 0, 0, 0)
|
|
221
217
|
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
222
218
|
// Set the view port
|
|
223
219
|
//gl.viewport(0, 0, cg.w, cg.h);
|
package/src/utils/webGLUtils.js
CHANGED
|
@@ -20,6 +20,111 @@ export function makeWebGLCanvas(width, height, opts = {}) {
|
|
|
20
20
|
return { canvas: canvas, gl: gl, width: width, height: height }
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* The shared, off-page WebGL canvases, one per set of context options.
|
|
25
|
+
* Styles draw into one of these and copy the result onto the map's canvas, one style at a
|
|
26
|
+
* time, so they never need a context each. Browsers keep only ~16 live WebGL contexts and
|
|
27
|
+
* drop the oldest beyond that, so one context per style instance (or worse, per draw)
|
|
28
|
+
* eventually blanks other WebGL content on the page.
|
|
29
|
+
* @type {Map<string, {canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number}>} */
|
|
30
|
+
const sharedCanvases = new Map()
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the shared WebGL canvas for these context options, resized to width x height.
|
|
34
|
+
* Resizing keeps the context (and its compiled programs and buffers); only its drawing
|
|
35
|
+
* buffer is reallocated. A lost context is replaced.
|
|
36
|
+
*
|
|
37
|
+
* @param {number} width
|
|
38
|
+
* @param {number} height
|
|
39
|
+
* @param {object} [opts] WebGL context attributes, e.g. { premultipliedAlpha: false }
|
|
40
|
+
* @returns {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number }}
|
|
41
|
+
*/
|
|
42
|
+
export function getSharedWebGLCanvas(width, height, opts = undefined) {
|
|
43
|
+
const key = JSON.stringify(opts || {})
|
|
44
|
+
let cv = sharedCanvases.get(key)
|
|
45
|
+
if (!cv || cv.gl.isContextLost()) {
|
|
46
|
+
cv = makeWebGLCanvas(width + '', height + '', opts)
|
|
47
|
+
cv.width = +width
|
|
48
|
+
cv.height = +height
|
|
49
|
+
sharedCanvases.set(key, cv)
|
|
50
|
+
}
|
|
51
|
+
if (cv.width != width || cv.height != height) {
|
|
52
|
+
cv.canvas.width = width
|
|
53
|
+
cv.canvas.height = height
|
|
54
|
+
cv.width = +width
|
|
55
|
+
cv.height = +height
|
|
56
|
+
}
|
|
57
|
+
cv.gl.viewport(0, 0, cv.width, cv.height)
|
|
58
|
+
return cv
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @type {WeakMap<WebGLRenderingContext, {programs: Map<string, WebGLProgram>, buffers: Map<string, WebGLBuffer>, owners: Map<string, any>}>} */
|
|
62
|
+
const glResources = new WeakMap()
|
|
63
|
+
function resourcesOf(gl) {
|
|
64
|
+
let r = glResources.get(gl)
|
|
65
|
+
if (!r) {
|
|
66
|
+
r = { programs: new Map(), buffers: new Map(), owners: new Map() }
|
|
67
|
+
glResources.set(gl, r)
|
|
68
|
+
}
|
|
69
|
+
return r
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A shader program for these sources, compiled once per context and reused.
|
|
74
|
+
*
|
|
75
|
+
* @param {WebGLRenderingContext} gl
|
|
76
|
+
* @param {string} vertexSource
|
|
77
|
+
* @param {string} fragmentSource
|
|
78
|
+
* @returns {WebGLProgram}
|
|
79
|
+
*/
|
|
80
|
+
export function getProgram(gl, vertexSource, fragmentSource) {
|
|
81
|
+
const programs = resourcesOf(gl).programs
|
|
82
|
+
const key = vertexSource + '\u0000' + fragmentSource
|
|
83
|
+
let program = programs.get(key)
|
|
84
|
+
if (!program) {
|
|
85
|
+
program = initShaderProgram(
|
|
86
|
+
gl,
|
|
87
|
+
createShader(gl, gl.VERTEX_SHADER, vertexSource),
|
|
88
|
+
createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)
|
|
89
|
+
)
|
|
90
|
+
programs.set(key, program)
|
|
91
|
+
}
|
|
92
|
+
return program
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A named buffer of a context, created once and reused: refill it with bufferData instead
|
|
97
|
+
* of creating a new buffer per draw (buffers are never garbage collected while their
|
|
98
|
+
* context lives).
|
|
99
|
+
*
|
|
100
|
+
* @param {WebGLRenderingContext} gl
|
|
101
|
+
* @param {string} name
|
|
102
|
+
* @returns {WebGLBuffer}
|
|
103
|
+
*/
|
|
104
|
+
export function getBuffer(gl, name) {
|
|
105
|
+
const buffers = resourcesOf(gl).buffers
|
|
106
|
+
let buffer = buffers.get(name)
|
|
107
|
+
if (!buffer) {
|
|
108
|
+
buffer = gl.createBuffer()
|
|
109
|
+
buffers.set(name, buffer)
|
|
110
|
+
}
|
|
111
|
+
return buffer
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Who last filled a named buffer, so a style can tell whether the data it uploaded is
|
|
116
|
+
* still there or another style has overwritten it since.
|
|
117
|
+
* @param {WebGLRenderingContext} gl
|
|
118
|
+
* @param {string} name
|
|
119
|
+
* @param {any} [owner] sets the owner when given
|
|
120
|
+
* @returns {any} the owner
|
|
121
|
+
*/
|
|
122
|
+
export function bufferOwner(gl, name, owner = undefined) {
|
|
123
|
+
const owners = resourcesOf(gl).owners
|
|
124
|
+
if (owner !== undefined) owners.set(name, owner)
|
|
125
|
+
return owners.get(name)
|
|
126
|
+
}
|
|
127
|
+
|
|
23
128
|
/**
|
|
24
129
|
* Initialize a shader program, so WebGL knows how to draw our data
|
|
25
130
|
*
|