gridviz 2.1.7 → 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +125 -124
  2. package/dist/gridviz.js +8021 -7991
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +77 -77
  5. package/src/App.js +705 -705
  6. package/src/BackgroundLayer.js +182 -182
  7. package/src/BackgroundLayerWMS.js +131 -131
  8. package/src/Dataset.js +76 -76
  9. package/src/DatasetComponent.js +101 -101
  10. package/src/GeoCanvas.js +420 -420
  11. package/src/LabelLayer.js +190 -190
  12. package/src/Layer.js +103 -103
  13. package/src/Legend.js +86 -86
  14. package/src/LineLayer.js +150 -150
  15. package/src/Style.js +129 -129
  16. package/src/Tooltip.js +180 -172
  17. package/src/dataset/COGeo.js +24 -24
  18. package/src/dataset/CSVGrid.js +104 -104
  19. package/src/dataset/GeoTIFF.js +127 -127
  20. package/src/dataset/GridTile.js +41 -41
  21. package/src/dataset/LGrid.js +54 -54
  22. package/src/dataset/TiledGrid.js +264 -264
  23. package/src/index.js +71 -71
  24. package/src/legend/ColorCategoryLegend.js +124 -124
  25. package/src/legend/ColorDiscreteLegend.js +103 -103
  26. package/src/legend/ColorLegend.js +124 -124
  27. package/src/legend/SegmentOrientationLegend.js +87 -87
  28. package/src/legend/SegmentWidthLegend.js +97 -97
  29. package/src/legend/SizeLegend.js +141 -141
  30. package/src/style/CompositionStyle.js +300 -300
  31. package/src/style/ContourStyle.js +54 -54
  32. package/src/style/DotDensityStyle.js +156 -156
  33. package/src/style/IsoFenceStyle.js +262 -240
  34. package/src/style/JoyPlotStyle.js +135 -135
  35. package/src/style/LegoStyle.js +112 -112
  36. package/src/style/MosaicStyle.js +107 -107
  37. package/src/style/NinjaStarStyle.js +125 -125
  38. package/src/style/PillarStyle.js +230 -230
  39. package/src/style/SegmentStyle.js +142 -142
  40. package/src/style/ShapeColorSizeStyle.js +126 -126
  41. package/src/style/SideCatStyle.js +172 -172
  42. package/src/style/SideStyle.js +216 -216
  43. package/src/style/SquareColorCatWGLStyle.js +120 -120
  44. package/src/style/SquareColorWGLStyle.js +146 -146
  45. package/src/style/StrokeStyle.js +131 -131
  46. package/src/style/TanakaStyle.js +160 -160
  47. package/src/style/TextStyle.js +132 -132
  48. package/src/style/TimeSeriesStyle.js +250 -250
  49. package/src/utils/Utils.js +35 -35
  50. package/src/utils/WebGLRectangleColoring.js +106 -106
  51. package/src/utils/WebGLSquareColoring.js +118 -118
  52. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  53. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  54. package/src/utils/WebGLSquareColoringKS.js +153 -153
  55. package/src/utils/stretching.js +131 -131
  56. package/src/utils/webGLUtils.js +71 -71
  57. package/src/utils/zoomUtils.js +142 -142
@@ -1,216 +1,216 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../Style.js'
5
-
6
- /** @typedef {{x:number,y:number,or:"v"|"h",value:number}} Side */
7
-
8
- /**
9
- *
10
- * @author Julien Gaffuri
11
- */
12
- export class SideStyle extends Style {
13
- /** @param {object} opts */
14
- constructor(opts) {
15
- super(opts)
16
- opts = opts || {}
17
-
18
- /** The name of the column/attribute of the tabular data where to retrieve the variable for the cell values.
19
- * @type {string} */
20
- this.valueCol = opts.valueCol
21
-
22
- /** A function returning the value of a cell side. This value is computed from the two adjacent cell values.
23
- * For horizontal sides, v1 is the value of the cell below and v2 the value of the cell above.
24
- * For vertical sides, v1 is the value of the cell left and v2 the value of the cell right.
25
- * @type {function(number|undefined,number|undefined,number,import("../Style").Stat|undefined,number):number} */
26
- this.value = opts.value || ((v1, v2, r, s, zf) => 1)
27
-
28
- /** A function returning the color of a cell side.
29
- * @type {function(Side,number,import("../Style").Stat|undefined,number):string} */
30
- this.color = opts.color || (() => '#EA6BAC')
31
-
32
- /** A function returning the width of a cell side, in geo unit
33
- * @type {function(Side,number,import("../Style").Stat|undefined,number):number} */
34
- this.width = opts.width || ((side, r, s, zf) => (r * side.value) / 5)
35
-
36
- /** orientation. Set to 90 to show sides as slope lines for example.
37
- * @type {number} */
38
- this.orientation = opts.orientation || 0
39
-
40
- /** A fill color for the cells.
41
- * @type {function(import("../Dataset").Cell):string} */
42
- this.fillColor = opts.fillColor
43
- }
44
-
45
- /**
46
- * @param {Array.<import("../Dataset").Cell>} cells
47
- * @param {number} r
48
- * @param {import("../GeoCanvas").GeoCanvas} cg
49
- */
50
- draw(cells, r, cg) {
51
- //filter
52
- if (this.filter) cells = cells.filter(this.filter)
53
-
54
- //zoom factor
55
- const zf = cg.getZf()
56
-
57
- //compute stats on cell values
58
- let statValue
59
- if (this.valueCol) {
60
- //compute color variable statistics
61
- statValue = Style.getStatistics(cells, (c) => c[this.valueCol], true)
62
- }
63
-
64
- /** @type {Array.<Side>} */
65
- const sides = []
66
-
67
- //make horizontal sides
68
- //sort cells by x and y
69
- cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
70
- let c1 = cells[0]
71
- for (let i = 1; i < cells.length; i++) {
72
- let c2 = cells[i]
73
-
74
- if ((c1.y + r == c2.y) && (c1.x == c2.x))
75
- //cells in same column and touch along horizontal side
76
- //make shared side
77
- sides.push({
78
- x: c1.x,
79
- y: c2.y,
80
- or: 'h',
81
- value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
82
- })
83
- else {
84
- //cells do not touch along horizontal side
85
- //make two sides: top one for c1, bottom for c2
86
- sides.push({
87
- x: c1.x,
88
- y: c1.y + r,
89
- or: 'h',
90
- value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
91
- })
92
- sides.push({
93
- x: c2.x,
94
- y: c2.y,
95
- or: 'h',
96
- value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
97
- })
98
- }
99
-
100
- c1 = c2
101
- }
102
-
103
- //make vertical sides
104
- //sort cells by y and x
105
- cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
106
- c1 = cells[0]
107
- for (let i = 1; i < cells.length; i++) {
108
- let c2 = cells[i]
109
-
110
- if ((c1.x + r == c2.x) && (c1.y == c2.y))
111
- //cells in same row and touch along vertical side
112
- //make shared side
113
- sides.push({
114
- x: c1.x + r,
115
- y: c1.y,
116
- or: 'v',
117
- value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
118
- })
119
- else {
120
- //cells do not touch along vertical side
121
- //make two sides: right one for c1, left for c2
122
- sides.push({
123
- x: c1.x + r,
124
- y: c1.y,
125
- or: 'v',
126
- value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
127
- })
128
- sides.push({
129
- x: c2.x,
130
- y: c2.y,
131
- or: 'v',
132
- value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
133
- })
134
- }
135
-
136
- c1 = c2
137
- }
138
-
139
- //
140
- if (sides.length == 0) return
141
-
142
- //compute stats on sides
143
- const statSides = SideStyle.getSideStatistics(sides, true)
144
-
145
- //draw in geo coordinates
146
- cg.setCanvasTransform()
147
-
148
- //draw cells, if fillColor specified
149
- if (this.fillColor)
150
- for (let c of cells) {
151
- const fc = this.fillColor(c)
152
- if (!fc || fc == 'none') continue
153
- cg.ctx.fillStyle = fc
154
- cg.ctx.fillRect(c.x, c.y, r, r)
155
- }
156
-
157
- //draw sides
158
- cg.ctx.lineCap = 'butt'
159
- const r2 = r / 2
160
- for (let s of sides) {
161
- //color
162
- /** @type {string|undefined} */
163
- const col = this.color ? this.color(s, r, statSides, zf) : undefined
164
- if (!col || col == 'none') continue
165
-
166
- //width
167
- /** @type {number|undefined} */
168
- const wG = this.width ? this.width(s, r, statSides, zf) : undefined
169
- if (!wG || wG <= 0) continue
170
-
171
- //set color and width
172
- cg.ctx.strokeStyle = col
173
- cg.ctx.lineWidth = wG
174
-
175
- //draw segment with correct orientation
176
- cg.ctx.beginPath()
177
- if (this.orientation == 90) {
178
- cg.ctx.moveTo(s.x + r2, s.y + r2)
179
- if (s.or === 'h') cg.ctx.lineTo(s.x + r2, s.y - r2)
180
- else cg.ctx.lineTo(s.x - r2, s.y + r2)
181
- } else {
182
- cg.ctx.moveTo(s.x, s.y)
183
- cg.ctx.lineTo(s.x + (s.or === 'h' ? r : 0), s.y + (s.or === 'v' ? r : 0))
184
- }
185
- cg.ctx.stroke()
186
- }
187
-
188
- //update legends
189
- this.updateLegends({ style: this, r: r, zf: zf })
190
- }
191
-
192
- /**
193
- * Compute some statistics on a value of some sides.
194
- * This is used to define how to draw specifically the sides within the view.
195
- *
196
- * @param {Array.<Side>} sides
197
- * @param {boolean} ignoreZeros
198
- * @returns {import("../Style").Stat | undefined}
199
- */
200
- static getSideStatistics(sides, ignoreZeros) {
201
- if (!sides || sides.length == 0) return undefined
202
- let min = Infinity
203
- let max = -Infinity
204
- //let sum = 0
205
- //let nb = 0
206
- for (const s of sides) {
207
- const v = s.value
208
- if (ignoreZeros && !v) continue
209
- if (v < min) min = v
210
- if (v > max) max = v
211
- //sum += v
212
- //nb++
213
- }
214
- return { min: min, max: max }
215
- }
216
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../Style.js'
5
+
6
+ /** @typedef {{x:number,y:number,or:"v"|"h",value:number}} Side */
7
+
8
+ /**
9
+ *
10
+ * @author Julien Gaffuri
11
+ */
12
+ export class SideStyle extends Style {
13
+ /** @param {object} opts */
14
+ constructor(opts) {
15
+ super(opts)
16
+ opts = opts || {}
17
+
18
+ /** The name of the column/attribute of the tabular data where to retrieve the variable for the cell values.
19
+ * @type {string} */
20
+ this.valueCol = opts.valueCol
21
+
22
+ /** A function returning the value of a cell side. This value is computed from the two adjacent cell values.
23
+ * For horizontal sides, v1 is the value of the cell below and v2 the value of the cell above.
24
+ * For vertical sides, v1 is the value of the cell left and v2 the value of the cell right.
25
+ * @type {function(number|undefined,number|undefined,number,import("../Style").Stat|undefined,number):number} */
26
+ this.value = opts.value || ((v1, v2, r, s, zf) => 1)
27
+
28
+ /** A function returning the color of a cell side.
29
+ * @type {function(Side,number,import("../Style").Stat|undefined,number):string} */
30
+ this.color = opts.color || (() => '#EA6BAC')
31
+
32
+ /** A function returning the width of a cell side, in geo unit
33
+ * @type {function(Side,number,import("../Style").Stat|undefined,number):number} */
34
+ this.width = opts.width || ((side, r, s, zf) => (r * side.value) / 5)
35
+
36
+ /** orientation. Set to 90 to show sides as slope lines for example.
37
+ * @type {number} */
38
+ this.orientation = opts.orientation || 0
39
+
40
+ /** A fill color for the cells.
41
+ * @type {function(import("../Dataset").Cell):string} */
42
+ this.fillColor = opts.fillColor
43
+ }
44
+
45
+ /**
46
+ * @param {Array.<import("../Dataset").Cell>} cells
47
+ * @param {number} r
48
+ * @param {import("../GeoCanvas").GeoCanvas} cg
49
+ */
50
+ draw(cells, r, cg) {
51
+ //filter
52
+ if (this.filter) cells = cells.filter(this.filter)
53
+
54
+ //zoom factor
55
+ const zf = cg.getZf()
56
+
57
+ //compute stats on cell values
58
+ let statValue
59
+ if (this.valueCol) {
60
+ //compute color variable statistics
61
+ statValue = Style.getStatistics(cells, (c) => c[this.valueCol], true)
62
+ }
63
+
64
+ /** @type {Array.<Side>} */
65
+ const sides = []
66
+
67
+ //make horizontal sides
68
+ //sort cells by x and y
69
+ cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
70
+ let c1 = cells[0]
71
+ for (let i = 1; i < cells.length; i++) {
72
+ let c2 = cells[i]
73
+
74
+ if ((c1.y + r == c2.y) && (c1.x == c2.x))
75
+ //cells in same column and touch along horizontal side
76
+ //make shared side
77
+ sides.push({
78
+ x: c1.x,
79
+ y: c2.y,
80
+ or: 'h',
81
+ value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
82
+ })
83
+ else {
84
+ //cells do not touch along horizontal side
85
+ //make two sides: top one for c1, bottom for c2
86
+ sides.push({
87
+ x: c1.x,
88
+ y: c1.y + r,
89
+ or: 'h',
90
+ value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
91
+ })
92
+ sides.push({
93
+ x: c2.x,
94
+ y: c2.y,
95
+ or: 'h',
96
+ value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
97
+ })
98
+ }
99
+
100
+ c1 = c2
101
+ }
102
+
103
+ //make vertical sides
104
+ //sort cells by y and x
105
+ cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
106
+ c1 = cells[0]
107
+ for (let i = 1; i < cells.length; i++) {
108
+ let c2 = cells[i]
109
+
110
+ if ((c1.x + r == c2.x) && (c1.y == c2.y))
111
+ //cells in same row and touch along vertical side
112
+ //make shared side
113
+ sides.push({
114
+ x: c1.x + r,
115
+ y: c1.y,
116
+ or: 'v',
117
+ value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
118
+ })
119
+ else {
120
+ //cells do not touch along vertical side
121
+ //make two sides: right one for c1, left for c2
122
+ sides.push({
123
+ x: c1.x + r,
124
+ y: c1.y,
125
+ or: 'v',
126
+ value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
127
+ })
128
+ sides.push({
129
+ x: c2.x,
130
+ y: c2.y,
131
+ or: 'v',
132
+ value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
133
+ })
134
+ }
135
+
136
+ c1 = c2
137
+ }
138
+
139
+ //
140
+ if (sides.length == 0) return
141
+
142
+ //compute stats on sides
143
+ const statSides = SideStyle.getSideStatistics(sides, true)
144
+
145
+ //draw in geo coordinates
146
+ cg.setCanvasTransform()
147
+
148
+ //draw cells, if fillColor specified
149
+ if (this.fillColor)
150
+ for (let c of cells) {
151
+ const fc = this.fillColor(c)
152
+ if (!fc || fc == 'none') continue
153
+ cg.ctx.fillStyle = fc
154
+ cg.ctx.fillRect(c.x, c.y, r, r)
155
+ }
156
+
157
+ //draw sides
158
+ cg.ctx.lineCap = 'butt'
159
+ const r2 = r / 2
160
+ for (let s of sides) {
161
+ //color
162
+ /** @type {string|undefined} */
163
+ const col = this.color ? this.color(s, r, statSides, zf) : undefined
164
+ if (!col || col == 'none') continue
165
+
166
+ //width
167
+ /** @type {number|undefined} */
168
+ const wG = this.width ? this.width(s, r, statSides, zf) : undefined
169
+ if (!wG || wG <= 0) continue
170
+
171
+ //set color and width
172
+ cg.ctx.strokeStyle = col
173
+ cg.ctx.lineWidth = wG
174
+
175
+ //draw segment with correct orientation
176
+ cg.ctx.beginPath()
177
+ if (this.orientation == 90) {
178
+ cg.ctx.moveTo(s.x + r2, s.y + r2)
179
+ if (s.or === 'h') cg.ctx.lineTo(s.x + r2, s.y - r2)
180
+ else cg.ctx.lineTo(s.x - r2, s.y + r2)
181
+ } else {
182
+ cg.ctx.moveTo(s.x, s.y)
183
+ cg.ctx.lineTo(s.x + (s.or === 'h' ? r : 0), s.y + (s.or === 'v' ? r : 0))
184
+ }
185
+ cg.ctx.stroke()
186
+ }
187
+
188
+ //update legends
189
+ this.updateLegends({ style: this, r: r, zf: zf })
190
+ }
191
+
192
+ /**
193
+ * Compute some statistics on a value of some sides.
194
+ * This is used to define how to draw specifically the sides within the view.
195
+ *
196
+ * @param {Array.<Side>} sides
197
+ * @param {boolean} ignoreZeros
198
+ * @returns {import("../Style").Stat | undefined}
199
+ */
200
+ static getSideStatistics(sides, ignoreZeros) {
201
+ if (!sides || sides.length == 0) return undefined
202
+ let min = Infinity
203
+ let max = -Infinity
204
+ //let sum = 0
205
+ //let nb = 0
206
+ for (const s of sides) {
207
+ const v = s.value
208
+ if (ignoreZeros && !v) continue
209
+ if (v < min) min = v
210
+ if (v > max) max = v
211
+ //sum += v
212
+ //nb++
213
+ }
214
+ return { min: min, max: max }
215
+ }
216
+ }
@@ -1,120 +1,120 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../Style.js'
5
- import { makeWebGLCanvas } from '../utils/webGLUtils.js'
6
- import { WebGLSquareColoringCatAdvanced } from '../utils/WebGLSquareColoringCatAdvanced.js'
7
- import { monitor, monitorDuration } from '../utils/Utils.js'
8
-
9
- /**
10
- * Style based on webGL
11
- * To show cells as colored squares, from categories.
12
- * Alls squares with the same size
13
- *
14
- * @author Julien Gaffuri
15
- */
16
- export class SquareColorCatWGLStyle extends Style {
17
- /** @param {object} opts */
18
- constructor(opts) {
19
- super(opts)
20
- opts = opts || {}
21
-
22
- /**
23
- * The name of the column/attribute of the tabular data where to retrieve the category of the cell, for coloring.
24
- * @type {string} */
25
- this.colorCol = opts.colorCol
26
-
27
- /**
28
- * The dictionary (string -> color) which give the color of each category.
29
- * @type {object} */
30
- opts.color = opts.color || undefined
31
-
32
- /** @type { Array.<string> } @private */
33
- const keys = Object.keys(opts.color)
34
-
35
- /** @type { object } @private */
36
- this.catToI = {}
37
- for (let i = 0; i < keys.length; i++) this.catToI[keys[i]] = i + ''
38
-
39
- /** @type { Array.<string> } @private */
40
- this.colors = []
41
- for (let i = 0; i < keys.length; i++) {
42
- this.colors.push(opts.color['' + keys[i]])
43
- }
44
-
45
- /**
46
- * A function returning the size of the cells, in geographical unit. All cells have the same size.
47
- * @type {function(number,number):number} */
48
- this.size = opts.size // (resolution, zf) => ...
49
-
50
- /**
51
- * @private
52
- * @type { WebGLSquareColoringCatAdvanced } */
53
- this.wgp = new WebGLSquareColoringCatAdvanced(this.colors)
54
- }
55
-
56
- /**
57
- * @param {Array.<import("../Dataset").Cell>} cells
58
- * @param {number} r
59
- * @param {import("../GeoCanvas").GeoCanvas} cg
60
- */
61
- draw(cells, r, cg) {
62
- if (monitor) monitorDuration('*** SquareColorCatWGLStyle draw')
63
-
64
- //filter
65
- if (this.filter) cells = cells.filter(this.filter)
66
-
67
- //zoom factor
68
- const zf = cg.getZf()
69
-
70
- //add vertice and fragment data
71
- const r2 = r / 2
72
- let c,
73
- nb = cells.length
74
- const verticesBuffer = []
75
- const iBuffer = []
76
- for (let i = 0; i < nb; i++) {
77
- c = cells[i]
78
- const cat = c[this.colorCol]
79
- if (cat == undefined) {
80
- console.log('Unexpected category: ' + cat)
81
- continue
82
- }
83
- /** @type {number} */
84
- const i_ = this.catToI[cat]
85
- if (isNaN(+i_)) {
86
- console.log('Unexpected category index: ' + cat + ' ' + i_)
87
- continue
88
- }
89
- verticesBuffer.push(c.x + r2, c.y + r2)
90
- iBuffer.push(+i_)
91
- }
92
-
93
- if (monitor) monitorDuration(' webgl program inputs preparation')
94
-
95
- //create canvas and webgl renderer
96
- const cvWGL = makeWebGLCanvas(cg.w + '', cg.h + '')
97
- if (!cvWGL) {
98
- console.error('No webGL')
99
- return
100
- }
101
- if (monitor) monitorDuration(' web GL canvas creation')
102
-
103
- //draw
104
- const sizeGeo = this.size ? this.size(r, zf) : r + 0.2 * zf
105
- this.wgp.draw(cvWGL.gl, verticesBuffer, iBuffer, cg.getWebGLTransform(), sizeGeo / zf)
106
-
107
- if (monitor) monitorDuration(' webgl drawing')
108
-
109
- //draw in canvas geo
110
- cg.initCanvasTransform()
111
- cg.ctx.drawImage(cvWGL.canvas, 0, 0)
112
-
113
- if (monitor) monitorDuration(' canvas drawing')
114
-
115
- //update legends
116
- this.updateLegends({ style: this, r: r, zf: zf })
117
-
118
- if (monitor) monitorDuration('*** SquareColorCatWGLStyle end draw')
119
- }
120
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../Style.js'
5
+ import { makeWebGLCanvas } from '../utils/webGLUtils.js'
6
+ import { WebGLSquareColoringCatAdvanced } from '../utils/WebGLSquareColoringCatAdvanced.js'
7
+ import { monitor, monitorDuration } from '../utils/Utils.js'
8
+
9
+ /**
10
+ * Style based on webGL
11
+ * To show cells as colored squares, from categories.
12
+ * Alls squares with the same size
13
+ *
14
+ * @author Julien Gaffuri
15
+ */
16
+ export class SquareColorCatWGLStyle extends Style {
17
+ /** @param {object} opts */
18
+ constructor(opts) {
19
+ super(opts)
20
+ opts = opts || {}
21
+
22
+ /**
23
+ * The name of the column/attribute of the tabular data where to retrieve the category of the cell, for coloring.
24
+ * @type {string} */
25
+ this.colorCol = opts.colorCol
26
+
27
+ /**
28
+ * The dictionary (string -> color) which give the color of each category.
29
+ * @type {object} */
30
+ opts.color = opts.color || undefined
31
+
32
+ /** @type { Array.<string> } @private */
33
+ const keys = Object.keys(opts.color)
34
+
35
+ /** @type { object } @private */
36
+ this.catToI = {}
37
+ for (let i = 0; i < keys.length; i++) this.catToI[keys[i]] = i + ''
38
+
39
+ /** @type { Array.<string> } @private */
40
+ this.colors = []
41
+ for (let i = 0; i < keys.length; i++) {
42
+ this.colors.push(opts.color['' + keys[i]])
43
+ }
44
+
45
+ /**
46
+ * A function returning the size of the cells, in geographical unit. All cells have the same size.
47
+ * @type {function(number,number):number} */
48
+ this.size = opts.size // (resolution, zf) => ...
49
+
50
+ /**
51
+ * @private
52
+ * @type { WebGLSquareColoringCatAdvanced } */
53
+ this.wgp = new WebGLSquareColoringCatAdvanced(this.colors)
54
+ }
55
+
56
+ /**
57
+ * @param {Array.<import("../Dataset").Cell>} cells
58
+ * @param {number} r
59
+ * @param {import("../GeoCanvas").GeoCanvas} cg
60
+ */
61
+ draw(cells, r, cg) {
62
+ if (monitor) monitorDuration('*** SquareColorCatWGLStyle draw')
63
+
64
+ //filter
65
+ if (this.filter) cells = cells.filter(this.filter)
66
+
67
+ //zoom factor
68
+ const zf = cg.getZf()
69
+
70
+ //add vertice and fragment data
71
+ const r2 = r / 2
72
+ let c,
73
+ nb = cells.length
74
+ const verticesBuffer = []
75
+ const iBuffer = []
76
+ for (let i = 0; i < nb; i++) {
77
+ c = cells[i]
78
+ const cat = c[this.colorCol]
79
+ if (cat == undefined) {
80
+ console.log('Unexpected category: ' + cat)
81
+ continue
82
+ }
83
+ /** @type {number} */
84
+ const i_ = this.catToI[cat]
85
+ if (isNaN(+i_)) {
86
+ console.log('Unexpected category index: ' + cat + ' ' + i_)
87
+ continue
88
+ }
89
+ verticesBuffer.push(c.x + r2, c.y + r2)
90
+ iBuffer.push(+i_)
91
+ }
92
+
93
+ if (monitor) monitorDuration(' webgl program inputs preparation')
94
+
95
+ //create canvas and webgl renderer
96
+ const cvWGL = makeWebGLCanvas(cg.w + '', cg.h + '')
97
+ if (!cvWGL) {
98
+ console.error('No webGL')
99
+ return
100
+ }
101
+ if (monitor) monitorDuration(' web GL canvas creation')
102
+
103
+ //draw
104
+ const sizeGeo = this.size ? this.size(r, zf) : r + 0.2 * zf
105
+ this.wgp.draw(cvWGL.gl, verticesBuffer, iBuffer, cg.getWebGLTransform(), sizeGeo / zf)
106
+
107
+ if (monitor) monitorDuration(' webgl drawing')
108
+
109
+ //draw in canvas geo
110
+ cg.initCanvasTransform()
111
+ cg.ctx.drawImage(cvWGL.canvas, 0, 0)
112
+
113
+ if (monitor) monitorDuration(' canvas drawing')
114
+
115
+ //update legends
116
+ this.updateLegends({ style: this, r: r, zf: zf })
117
+
118
+ if (monitor) monitorDuration('*** SquareColorCatWGLStyle end draw')
119
+ }
120
+ }