gridviz 3.0.18 → 3.0.20

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 (56) hide show
  1. package/README.md +128 -127
  2. package/dist/gridviz.js +7862 -7819
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/ZoomButtons.js +101 -101
  6. package/src/core/Dataset.js +154 -154
  7. package/src/core/Drawable.js +60 -60
  8. package/src/core/GeoCanvas.js +430 -419
  9. package/src/core/Layer.js +23 -23
  10. package/src/core/Legend.js +108 -108
  11. package/src/core/Map.js +516 -503
  12. package/src/core/MultiResolutionDataset.js +93 -93
  13. package/src/core/Style.js +98 -98
  14. package/src/core/Tooltip.js +1 -0
  15. package/src/dataset/CSVGrid.js +112 -112
  16. package/src/dataset/GeoTIFF.js +122 -122
  17. package/src/dataset/JSGrid.js +55 -55
  18. package/src/dataset/TiledGrid.js +302 -289
  19. package/src/dataset/worker.js +18 -18
  20. package/src/index.js +77 -77
  21. package/src/layer/BackgroundLayer.js +162 -162
  22. package/src/layer/BackgroundLayerImage.js +81 -81
  23. package/src/layer/BackgroundLayerWMS.js +104 -104
  24. package/src/layer/GeoJSONLayer.js +214 -214
  25. package/src/layer/GridLayer.js +148 -148
  26. package/src/layer/LabelLayer.js +194 -194
  27. package/src/legend/ColorCategoryLegend.js +109 -109
  28. package/src/legend/ColorDiscreteLegend.js +100 -100
  29. package/src/legend/ColorLegend.js +115 -115
  30. package/src/legend/OrientationLegend.js +89 -89
  31. package/src/legend/SizeLegend.js +224 -224
  32. package/src/legend/TernaryLegend.js +302 -302
  33. package/src/style/CompositionStyle.js +291 -291
  34. package/src/style/DotDensityStyle.js +133 -133
  35. package/src/style/ImageStyle.js +100 -100
  36. package/src/style/IsoFenceStyle.js +217 -217
  37. package/src/style/JoyPlotStyle.js +127 -127
  38. package/src/style/LegoStyle.js +110 -110
  39. package/src/style/MosaicStyle.js +99 -99
  40. package/src/style/NinjaStarStyle.js +102 -102
  41. package/src/style/PillarStyle.js +207 -207
  42. package/src/style/SegmentStyle.js +105 -105
  43. package/src/style/ShapeColorSizeStyle.js +147 -147
  44. package/src/style/SideCategoryStyle.js +112 -112
  45. package/src/style/SideStyle.js +212 -212
  46. package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
  47. package/src/style/SquareColorWebGLStyle.js +126 -126
  48. package/src/style/StrokeStyle.js +135 -135
  49. package/src/style/TanakaStyle.js +69 -69
  50. package/src/style/TextStyle.js +110 -110
  51. package/src/style/TimeSeriesStyle.js +222 -222
  52. package/src/utils/scale.js +218 -218
  53. package/src/utils/stretching.js +120 -120
  54. package/src/utils/ternary.js +208 -203
  55. package/src/utils/utils.js +58 -58
  56. package/src/utils/webGLUtils.js +72 -72
@@ -1,291 +1,291 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../core/Style.js'
5
-
6
- /** @typedef {"flag"|"piechart"|"ring"|"segment"|"radar"|"agepyramid"|"halftone"} CompositionType */
7
-
8
- /**
9
- * A style showing the composition of a total in different categories, with different color hues.
10
- * It consists of a symbol with different parts, whose size reflect the proportion of the corresponding category.
11
- * For a list of supported symbols, @see CompositionType
12
- * The symbol can be scaled depending on the cell importance.
13
- *
14
- * @module style
15
- * @author Julien Gaffuri
16
- */
17
- export class CompositionStyle extends Style {
18
- /** @param {object} opts */
19
- constructor(opts) {
20
- super(opts)
21
- opts = opts || {}
22
-
23
- /**
24
- * The dictionary (string -> color) which give the color of each category.
25
- * @type {object} */
26
- this.color = opts.color
27
-
28
- /**
29
- * A function returning the type of decomposition symbol of a cell, @see CompositionType
30
- * @type {function(import("../core/Dataset.js").Cell,number, number,object):CompositionType} */
31
- this.type = opts.type || (() => 'flag') //(c,r,z,vs) => {}
32
-
33
- /** A function returning the size of a cell in geographical unit.
34
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
35
- this.size = opts.size || ((c, r) => r) //(c,r,z,vs) => {}
36
-
37
- /** For style types with stripes (flag, segment), the orientation of the stripes (0 for horizontal, other for vertical).
38
- * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
39
- this.stripesOrientation = opts.stripesOrientation || (() => 0) //(c,r,z,vs) => ...
40
-
41
- /** The function specifying an offset angle for a radar, halftone or pie chart style.
42
- * The angle is specified in degree. The rotation is anti-clockwise.
43
- * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
44
- this.offsetAngle = opts.offsetAngle || (() => 0) //(c,r,z,vs) => ...
45
-
46
- /** The function specifying the height of the age pyramid, in geo unit.
47
- * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
48
- this.agePyramidHeight = opts.agePyramidHeight || ((c, r) => r) //(c,r,z,vs) => ...
49
-
50
- /** For pie chart, this is parameter for internal radius, so that the pie chart looks like a donut.
51
- * 0 for normal pie charts, 0.5 to empty half of the radius.
52
- * @type {number} */
53
- this.pieChartInternalRadiusFactor = opts.pieChartInternalRadiusFactor || 0
54
- }
55
-
56
- /**
57
- * Draw cells as squares depending on their value.
58
- *
59
- * @param {Array.<import("../core/Dataset.js").Cell>} cells
60
- * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
61
- * @param {number} resolution
62
- */
63
- draw(cells, geoCanvas, resolution) {
64
- //filter
65
- if (this.filter) cells = cells.filter(this.filter)
66
-
67
- //
68
- const z = geoCanvas.view.z
69
- const ctx = geoCanvas.offscreenCtx
70
-
71
- //get view scale
72
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
73
-
74
- //nb categories - used for radar and agepyramid
75
- const nbCat = Object.entries(this.color).length
76
-
77
- //draw calls
78
- for (let cell of cells) {
79
- //size
80
- const sG = this.size ? this.size(cell, resolution, z, viewScale) : resolution
81
- if (!sG) continue
82
-
83
- //get offset
84
- const offset = this.offset(cell, resolution, z)
85
-
86
- //get symbol type
87
- const type_ = this.type ? this.type(cell, resolution, z, viewScale) : 'flag'
88
-
89
- //compute center position
90
- const xc = cell.x + offset.dx + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
91
- const yc = cell.y + offset.dy + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
92
-
93
- //compute offset angle, when relevant
94
- const offAng = this.offsetAngle
95
- ? (this.offsetAngle(cell, resolution, z, viewScale) * Math.PI) / 180
96
- : 0
97
-
98
- if (type_ === 'agepyramid' || type_ === 'radar' || type_ === 'halftone') {
99
- //get cell category max value
100
- let maxVal = -Infinity
101
- for (let key of Object.keys(this.color)) {
102
- const v = +cell[key]
103
- if (v > maxVal) maxVal = v
104
- }
105
-
106
- //cumul
107
- let cumul = 0
108
- if (type_ === 'agepyramid' && this.agePyramidHeight)
109
- cumul = (resolution - this.agePyramidHeight(cell, resolution, z, viewScale)) / 2
110
- if (type_ === 'radar' || type_ === 'halftone') cumul = Math.PI / 2 + offAng
111
-
112
- //compute the increment, which is the value to increment the cumul for each category
113
- const incr =
114
- type_ === 'agepyramid'
115
- ? (this.agePyramidHeight
116
- ? this.agePyramidHeight(cell, resolution, z, viewScale)
117
- : resolution) / nbCat
118
- : type_ === 'radar' || type_ === 'halftone'
119
- ? (2 * Math.PI) / nbCat
120
- : undefined
121
- if (incr === undefined) throw new Error('Unexpected symbol type:' + type_)
122
-
123
- for (let [column, color] of Object.entries(this.color)) {
124
- if (type_ === 'agepyramid') {
125
- //set category color
126
- ctx.fillStyle = color
127
-
128
- //get category value
129
- const val = cell[column]
130
-
131
- //compute category length - in geo
132
- /** @type {number} */
133
- const wG = (sG * val) / maxVal
134
-
135
- //draw bar
136
- ctx.fillRect(xc + (resolution - wG) / 2, yc + cumul, wG, incr)
137
-
138
- //next height
139
- cumul += incr
140
- } else if (type_ === 'radar') {
141
- //set category color
142
- ctx.fillStyle = color
143
-
144
- //get categroy value
145
- const val = cell[column]
146
-
147
- //compute category radius - in geo
148
- /** @type {number} */
149
- //const rG = this.radius(val, r, stat, cellStat, z)
150
- const rG = (sG / 2) * Math.sqrt(val / maxVal)
151
-
152
- //draw angular sector
153
- ctx.beginPath()
154
- ctx.moveTo(xc, yc)
155
- ctx.arc(xc, yc, rG, cumul - incr, cumul)
156
- ctx.lineTo(xc, yc)
157
- ctx.fill()
158
-
159
- //next angular sector
160
- cumul += incr
161
- } else if (type_ === 'halftone') {
162
- //set category color
163
- ctx.fillStyle = color
164
-
165
- //get categroy value
166
- const val = cell[column]
167
-
168
- //compute category radius - in geo
169
- /** @type {number} */
170
- const rG = sG * 0.333 * Math.sqrt(val / maxVal)
171
-
172
- //draw circle
173
- ctx.beginPath()
174
- ctx.arc(
175
- xc + resolution * 0.25 * Math.cos(cumul),
176
- yc + resolution * 0.25 * Math.sin(cumul),
177
- rG,
178
- 0,
179
- 2 * Math.PI
180
- )
181
- ctx.fill()
182
-
183
- //next angular sector
184
- cumul += incr
185
- } else {
186
- throw new Error('Unexpected symbol type:' + type_)
187
- }
188
- }
189
- } else {
190
- //compute total
191
- let total = 0
192
- for (let column of Object.keys(this.color)) {
193
- const v = +cell[column]
194
- if (!v) continue
195
- total += v
196
- }
197
- if (!total || isNaN(total)) continue
198
-
199
- //draw decomposition symbol
200
- let cumul = 0
201
- const d = resolution * (1 - sG / resolution) * 0.5
202
- const ori = this.stripesOrientation(cell, resolution, z, viewScale)
203
-
204
- for (let [column, color] of Object.entries(this.color)) {
205
- //get share
206
- const share = cell[column] / total
207
- if (!share || isNaN(share)) continue
208
-
209
- //set color
210
- ctx.fillStyle = color
211
-
212
- //draw symbol part
213
- if (type_ === 'flag') {
214
- //draw flag stripe
215
- if (ori == 0) {
216
- //horizontal
217
- ctx.fillRect(
218
- cell.x + d + offset.dx,
219
- cell.y + d + cumul * sG + offset.dy,
220
- sG,
221
- share * sG
222
- )
223
- } else {
224
- //vertical
225
- ctx.fillRect(
226
- cell.x + d + cumul * sG + offset.dx,
227
- cell.y + d + offset.dy,
228
- share * sG,
229
- sG
230
- )
231
- }
232
- } else if (type_ === 'piechart') {
233
- //draw pie chart angular sector
234
-
235
- //compute angles
236
- const a1 = cumul * 2 * Math.PI
237
- const a2 = (cumul + share) * 2 * Math.PI
238
-
239
- //draw
240
- ctx.beginPath()
241
- ctx.moveTo(xc, yc)
242
- ctx.arc(xc, yc, sG * 0.5, a1 + offAng, a2 + offAng)
243
- if (this.pieChartInternalRadiusFactor)
244
- ctx.arc(
245
- xc,
246
- yc,
247
- sG * 0.5 * this.pieChartInternalRadiusFactor,
248
- a1 + offAng,
249
- a2 + offAng,
250
- true
251
- )
252
- ctx.closePath()
253
- ctx.fill()
254
- } else if (type_ === 'ring') {
255
- //draw ring
256
- ctx.beginPath()
257
- ctx.arc(xc, yc, Math.sqrt(1 - cumul) * sG * 0.5, 0, 2 * Math.PI)
258
- ctx.fill()
259
- } else if (type_ === 'segment') {
260
- //draw segment sections
261
- const wG = (sG * sG) / resolution
262
- if (ori == 0) {
263
- //horizontal
264
- ctx.fillRect(
265
- cell.x + offset.dx,
266
- cell.y + (resolution - wG) / 2 + cumul * wG + offset.dy,
267
- resolution,
268
- share * wG
269
- )
270
- } else {
271
- //vertical
272
- ctx.fillRect(
273
- cell.x + cumul * resolution + offset.dx,
274
- cell.y + (resolution - wG) / 2 + offset.dy,
275
- share * resolution,
276
- wG
277
- )
278
- }
279
- } else {
280
- throw new Error('Unexpected symbol type:' + type_)
281
- }
282
-
283
- cumul += share
284
- }
285
- }
286
- }
287
-
288
- //update legends
289
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
290
- }
291
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../core/Style.js'
5
+
6
+ /** @typedef {"flag"|"piechart"|"ring"|"segment"|"radar"|"agepyramid"|"halftone"} CompositionType */
7
+
8
+ /**
9
+ * A style showing the composition of a total in different categories, with different color hues.
10
+ * It consists of a symbol with different parts, whose size reflect the proportion of the corresponding category.
11
+ * For a list of supported symbols, @see CompositionType
12
+ * The symbol can be scaled depending on the cell importance.
13
+ *
14
+ * @module style
15
+ * @author Julien Gaffuri
16
+ */
17
+ export class CompositionStyle extends Style {
18
+ /** @param {object} opts */
19
+ constructor(opts) {
20
+ super(opts)
21
+ opts = opts || {}
22
+
23
+ /**
24
+ * The dictionary (string -> color) which give the color of each category.
25
+ * @type {object} */
26
+ this.color = opts.color
27
+
28
+ /**
29
+ * A function returning the type of decomposition symbol of a cell, @see CompositionType
30
+ * @type {function(import("../core/Dataset.js").Cell,number, number,object):CompositionType} */
31
+ this.type = opts.type || (() => 'flag') //(c,r,z,vs) => {}
32
+
33
+ /** A function returning the size of a cell in geographical unit.
34
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
35
+ this.size = opts.size || ((c, r) => r) //(c,r,z,vs) => {}
36
+
37
+ /** For style types with stripes (flag, segment), the orientation of the stripes (0 for horizontal, other for vertical).
38
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
39
+ this.stripesOrientation = opts.stripesOrientation || (() => 0) //(c,r,z,vs) => ...
40
+
41
+ /** The function specifying an offset angle for a radar, halftone or pie chart style.
42
+ * The angle is specified in degree. The rotation is anti-clockwise.
43
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
44
+ this.offsetAngle = opts.offsetAngle || (() => 0) //(c,r,z,vs) => ...
45
+
46
+ /** The function specifying the height of the age pyramid, in geo unit.
47
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
48
+ this.agePyramidHeight = opts.agePyramidHeight || ((c, r) => r) //(c,r,z,vs) => ...
49
+
50
+ /** For pie chart, this is parameter for internal radius, so that the pie chart looks like a donut.
51
+ * 0 for normal pie charts, 0.5 to empty half of the radius.
52
+ * @type {number} */
53
+ this.pieChartInternalRadiusFactor = opts.pieChartInternalRadiusFactor || 0
54
+ }
55
+
56
+ /**
57
+ * Draw cells as squares depending on their value.
58
+ *
59
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
60
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
61
+ * @param {number} resolution
62
+ */
63
+ draw(cells, geoCanvas, resolution) {
64
+ //filter
65
+ if (this.filter) cells = cells.filter(this.filter)
66
+
67
+ //
68
+ const z = geoCanvas.view.z
69
+ const ctx = geoCanvas.offscreenCtx
70
+
71
+ //get view scale
72
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
73
+
74
+ //nb categories - used for radar and agepyramid
75
+ const nbCat = Object.entries(this.color).length
76
+
77
+ //draw calls
78
+ for (let cell of cells) {
79
+ //size
80
+ const sG = this.size ? this.size(cell, resolution, z, viewScale) : resolution
81
+ if (!sG) continue
82
+
83
+ //get offset
84
+ const offset = this.offset(cell, resolution, z)
85
+
86
+ //get symbol type
87
+ const type_ = this.type ? this.type(cell, resolution, z, viewScale) : 'flag'
88
+
89
+ //compute center position
90
+ const xc = cell.x + offset.dx + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
91
+ const yc = cell.y + offset.dy + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
92
+
93
+ //compute offset angle, when relevant
94
+ const offAng = this.offsetAngle
95
+ ? (this.offsetAngle(cell, resolution, z, viewScale) * Math.PI) / 180
96
+ : 0
97
+
98
+ if (type_ === 'agepyramid' || type_ === 'radar' || type_ === 'halftone') {
99
+ //get cell category max value
100
+ let maxVal = -Infinity
101
+ for (let key of Object.keys(this.color)) {
102
+ const v = +cell[key]
103
+ if (v > maxVal) maxVal = v
104
+ }
105
+
106
+ //cumul
107
+ let cumul = 0
108
+ if (type_ === 'agepyramid' && this.agePyramidHeight)
109
+ cumul = (resolution - this.agePyramidHeight(cell, resolution, z, viewScale)) / 2
110
+ if (type_ === 'radar' || type_ === 'halftone') cumul = Math.PI / 2 + offAng
111
+
112
+ //compute the increment, which is the value to increment the cumul for each category
113
+ const incr =
114
+ type_ === 'agepyramid'
115
+ ? (this.agePyramidHeight
116
+ ? this.agePyramidHeight(cell, resolution, z, viewScale)
117
+ : resolution) / nbCat
118
+ : type_ === 'radar' || type_ === 'halftone'
119
+ ? (2 * Math.PI) / nbCat
120
+ : undefined
121
+ if (incr === undefined) throw new Error('Unexpected symbol type:' + type_)
122
+
123
+ for (let [column, color] of Object.entries(this.color)) {
124
+ if (type_ === 'agepyramid') {
125
+ //set category color
126
+ ctx.fillStyle = color
127
+
128
+ //get category value
129
+ const val = cell[column]
130
+
131
+ //compute category length - in geo
132
+ /** @type {number} */
133
+ const wG = (sG * val) / maxVal
134
+
135
+ //draw bar
136
+ ctx.fillRect(xc + (resolution - wG) / 2, yc + cumul, wG, incr)
137
+
138
+ //next height
139
+ cumul += incr
140
+ } else if (type_ === 'radar') {
141
+ //set category color
142
+ ctx.fillStyle = color
143
+
144
+ //get categroy value
145
+ const val = cell[column]
146
+
147
+ //compute category radius - in geo
148
+ /** @type {number} */
149
+ //const rG = this.radius(val, r, stat, cellStat, z)
150
+ const rG = (sG / 2) * Math.sqrt(val / maxVal)
151
+
152
+ //draw angular sector
153
+ ctx.beginPath()
154
+ ctx.moveTo(xc, yc)
155
+ ctx.arc(xc, yc, rG, cumul - incr, cumul)
156
+ ctx.lineTo(xc, yc)
157
+ ctx.fill()
158
+
159
+ //next angular sector
160
+ cumul += incr
161
+ } else if (type_ === 'halftone') {
162
+ //set category color
163
+ ctx.fillStyle = color
164
+
165
+ //get categroy value
166
+ const val = cell[column]
167
+
168
+ //compute category radius - in geo
169
+ /** @type {number} */
170
+ const rG = sG * 0.333 * Math.sqrt(val / maxVal)
171
+
172
+ //draw circle
173
+ ctx.beginPath()
174
+ ctx.arc(
175
+ xc + resolution * 0.25 * Math.cos(cumul),
176
+ yc + resolution * 0.25 * Math.sin(cumul),
177
+ rG,
178
+ 0,
179
+ 2 * Math.PI
180
+ )
181
+ ctx.fill()
182
+
183
+ //next angular sector
184
+ cumul += incr
185
+ } else {
186
+ throw new Error('Unexpected symbol type:' + type_)
187
+ }
188
+ }
189
+ } else {
190
+ //compute total
191
+ let total = 0
192
+ for (let column of Object.keys(this.color)) {
193
+ const v = +cell[column]
194
+ if (!v) continue
195
+ total += v
196
+ }
197
+ if (!total || isNaN(total)) continue
198
+
199
+ //draw decomposition symbol
200
+ let cumul = 0
201
+ const d = resolution * (1 - sG / resolution) * 0.5
202
+ const ori = this.stripesOrientation(cell, resolution, z, viewScale)
203
+
204
+ for (let [column, color] of Object.entries(this.color)) {
205
+ //get share
206
+ const share = cell[column] / total
207
+ if (!share || isNaN(share)) continue
208
+
209
+ //set color
210
+ ctx.fillStyle = color
211
+
212
+ //draw symbol part
213
+ if (type_ === 'flag') {
214
+ //draw flag stripe
215
+ if (ori == 0) {
216
+ //horizontal
217
+ ctx.fillRect(
218
+ cell.x + d + offset.dx,
219
+ cell.y + d + cumul * sG + offset.dy,
220
+ sG,
221
+ share * sG
222
+ )
223
+ } else {
224
+ //vertical
225
+ ctx.fillRect(
226
+ cell.x + d + cumul * sG + offset.dx,
227
+ cell.y + d + offset.dy,
228
+ share * sG,
229
+ sG
230
+ )
231
+ }
232
+ } else if (type_ === 'piechart') {
233
+ //draw pie chart angular sector
234
+
235
+ //compute angles
236
+ const a1 = cumul * 2 * Math.PI
237
+ const a2 = (cumul + share) * 2 * Math.PI
238
+
239
+ //draw
240
+ ctx.beginPath()
241
+ ctx.moveTo(xc, yc)
242
+ ctx.arc(xc, yc, sG * 0.5, a1 + offAng, a2 + offAng)
243
+ if (this.pieChartInternalRadiusFactor)
244
+ ctx.arc(
245
+ xc,
246
+ yc,
247
+ sG * 0.5 * this.pieChartInternalRadiusFactor,
248
+ a1 + offAng,
249
+ a2 + offAng,
250
+ true
251
+ )
252
+ ctx.closePath()
253
+ ctx.fill()
254
+ } else if (type_ === 'ring') {
255
+ //draw ring
256
+ ctx.beginPath()
257
+ ctx.arc(xc, yc, Math.sqrt(1 - cumul) * sG * 0.5, 0, 2 * Math.PI)
258
+ ctx.fill()
259
+ } else if (type_ === 'segment') {
260
+ //draw segment sections
261
+ const wG = (sG * sG) / resolution
262
+ if (ori == 0) {
263
+ //horizontal
264
+ ctx.fillRect(
265
+ cell.x + offset.dx,
266
+ cell.y + (resolution - wG) / 2 + cumul * wG + offset.dy,
267
+ resolution,
268
+ share * wG
269
+ )
270
+ } else {
271
+ //vertical
272
+ ctx.fillRect(
273
+ cell.x + cumul * resolution + offset.dx,
274
+ cell.y + (resolution - wG) / 2 + offset.dy,
275
+ share * resolution,
276
+ wG
277
+ )
278
+ }
279
+ } else {
280
+ throw new Error('Unexpected symbol type:' + type_)
281
+ }
282
+
283
+ cumul += share
284
+ }
285
+ }
286
+ }
287
+
288
+ //update legends
289
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
290
+ }
291
+ }