gridviz 3.0.41 → 3.1.1

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 (48) hide show
  1. package/README.md +18 -15
  2. package/dist/gridviz.js +3227 -1941
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +6 -4
  5. package/src/button/Button.js +77 -68
  6. package/src/button/FullscreenButton.js +123 -123
  7. package/src/button/ZoomButtons.js +109 -104
  8. package/src/core/Drawable.js +25 -3
  9. package/src/core/GeoCanvas.js +15 -0
  10. package/src/core/Legend.js +267 -245
  11. package/src/core/Map.js +180 -30
  12. package/src/core/Tooltip.js +191 -185
  13. package/src/dataset/TiledGrid.js +74 -24
  14. package/src/index.js +82 -79
  15. package/src/layer/GridLayer.js +196 -194
  16. package/src/layer/LabelLayer.js +7 -4
  17. package/src/legend/ColorCategoryLegend.js +127 -125
  18. package/src/legend/ColorDiscreteLegend.js +116 -114
  19. package/src/legend/ColorLegend.js +33 -11
  20. package/src/legend/OrientationLegend.js +94 -92
  21. package/src/legend/SizeLegend.js +8 -1
  22. package/src/legend/TernaryLegend.js +317 -314
  23. package/src/legend/VennLegend.js +202 -0
  24. package/src/style/CircleColorSizeWebGLStyle.js +249 -0
  25. package/src/style/CompositionStyle.js +1 -1
  26. package/src/style/DotDensityStyle.js +8 -4
  27. package/src/style/ImageStyle.js +1 -1
  28. package/src/style/Interpolator.js +31 -6
  29. package/src/style/IsoFenceStyle.js +1 -1
  30. package/src/style/LegoStyle.js +6 -5
  31. package/src/style/MosaicStyle.js +1 -1
  32. package/src/style/NinjaStarStyle.js +1 -1
  33. package/src/style/PillarStyle.js +1 -1
  34. package/src/style/RandomWalkInterpolator.js +213 -0
  35. package/src/style/ShadingRayStyle.js +16 -2
  36. package/src/style/ShadingStyle.js +80 -72
  37. package/src/style/ShapeColorSizeStyle.js +18 -2
  38. package/src/style/SideCategoryStyle.js +1 -1
  39. package/src/style/SideStyle.js +1 -1
  40. package/src/style/SideTanakaStyle.js +1 -1
  41. package/src/style/SquareColorCategoryWebGLStyle.js +71 -20
  42. package/src/style/SquareColorWebGLStyle.js +7 -4
  43. package/src/style/StrokeStyle.js +1 -1
  44. package/src/style/TextStyle.js +1 -1
  45. package/src/style/TimeSeriesStyle.js +14 -7
  46. package/src/utils/WebGLSquareColoringAdvanced.js +47 -9
  47. package/src/utils/scale.js +20 -0
  48. package/src/utils/webGLUtils.js +52 -0
@@ -0,0 +1,213 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Interpolator } from './Interpolator.js'
5
+ import { cellsToMatrix } from '../utils/utils.js'
6
+
7
+ /**
8
+ * A style which makes a finer grid from a grid of categories (a land cover for example), and draws it with other styles.
9
+ * It does not draw anything by itself.
10
+ *
11
+ * A category has no value between categories to interpolate, as a number has. This style uses the random walk interpolator
12
+ * described in "Spatial interpolators in Observable Plot" (VISU 2023): each cell of the finer grid is given the category
13
+ * of the first cell of the original grid which a random walk, starting from it, reaches. The cells of the original grid are
14
+ * taken as points at their centre. A cell of the finer grid is then most often given the category of its closest neighbours,
15
+ * and the limits between the categories become irregular, with fine details, instead of squares.
16
+ *
17
+ * The random walks are drawn from the position of the cell, so that the result does not change when the map is panned,
18
+ * or drawn again.
19
+ *
20
+ * @example
21
+ * const interpolator = new gridviz.RandomWalkInterpolator({ value: (c) => c.clc, targetResolution: (r, z) => r / 5, interpolatedProperty: 'clc' })
22
+ * interpolator.styles.push(new gridviz.SquareColorCategoryWebGLStyle({ code: (c) => c.clc, color: colors }))
23
+ *
24
+ * @module style
25
+ */
26
+ export class RandomWalkInterpolator extends Interpolator {
27
+ /** @param {object} opts The options of the style (see Style for the others: filter, visible...).
28
+ * @param {function(import('../core/Dataset.js').Cell):(string|number|undefined)} opts.value The category of a cell. A cell without category (undefined) is not interpolated.
29
+ * @param {function(number, number):number} [opts.targetResolution] (resolution, z) => the resolution of the interpolated cells. The ratio between the resolution and this one is rounded to an integer. Default: resolution / 5.
30
+ * @param {string} [opts.interpolatedProperty] The property of the interpolated cells which holds their category. Default: 'value'.
31
+ * @param {function(number):number} [opts.maxSteps] (factor) => the maximum number of steps of a random walk, from the ratio between the resolutions. A walk which has not reached a cell of the original grid then gives its cell the category of the cell it is in. Default: 6 * factor * factor.
32
+ * @param {number} [opts.seed] A number to change the random walks, and thus the result. Default: 0.
33
+ * @param {Array.<import('../core/Style.js').Style>} [opts.styles] The styles which draw the interpolated cells.
34
+ */
35
+ constructor(opts) {
36
+ super(opts)
37
+ opts = opts || {}
38
+
39
+ /** The category of a cell.
40
+ * @type {function(import('../core/Dataset.js').Cell):(string|number|undefined)} */
41
+ this.value = opts.value
42
+
43
+ /** The maximum number of steps of a random walk, as a function of the ratio between the resolutions.
44
+ * @type {function(number):number} */
45
+ this.maxSteps = opts.maxSteps || ((factor) => 6 * factor * factor)
46
+
47
+ /** A number to change the random walks.
48
+ * @type {number} */
49
+ this.seed = opts.seed || 0
50
+ }
51
+
52
+ /**
53
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
54
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
55
+ * @param {number} resolution
56
+ * @override
57
+ */
58
+ draw(cells, geoCanvas, resolution) {
59
+ //filter cells
60
+ if (this.filter) cells = cells.filter(this.filter)
61
+ if (cells.length == 0) return
62
+
63
+ const z = geoCanvas.view.z
64
+
65
+ //get target resolution and scale factor
66
+ let targetResolution = this.targetResolution(resolution, z)
67
+ const factor = Math.max(1, Math.round(resolution / targetResolution))
68
+ targetResolution = resolution / factor
69
+
70
+ //the categories of the cells, in a matrix: the lines go from the top to the bottom
71
+ const m = cellsToMatrix(cells, resolution, (c) => this.value(c))
72
+ const x0 = m.x0,
73
+ y0 = m.y0
74
+
75
+ //the categories as numbers, for speed
76
+ /** @type {Array.<string|number>} */
77
+ const categories = []
78
+ const index = new Map()
79
+ const rows = m.length,
80
+ cols = rows ? m[0].length : 0
81
+ const codes = new Int32Array(rows * cols).fill(-1)
82
+ for (let i = 0; i < rows; i++)
83
+ for (let j = 0; j < cols; j++) {
84
+ const v = m[i][j]
85
+ if (v === undefined || v === null) continue
86
+ let k = index.get(v)
87
+ if (k === undefined) {
88
+ k = categories.length
89
+ categories.push(v)
90
+ index.set(v, k)
91
+ }
92
+ codes[i * cols + j] = k
93
+ }
94
+
95
+ //the position of the first fine cell in the grid of all the fine cells of the map: the random walks depend on it only
96
+ const offsetI = -Math.round(y0 / targetResolution) - factor
97
+ const offsetJ = Math.round(x0 / targetResolution)
98
+
99
+ const fine = randomWalkInterpolate(codes, rows, cols, factor, {
100
+ maxSteps: this.maxSteps(factor),
101
+ seed: this.seed,
102
+ offsetI: offsetI,
103
+ offsetJ: offsetJ,
104
+ })
105
+
106
+ //make the cells
107
+ const out = []
108
+ const fineCols = cols * factor
109
+ const r = targetResolution
110
+ for (let I = 0; I < rows * factor; I++) {
111
+ const y = y0 + resolution - (I + 1) * r
112
+ for (let J = 0; J < fineCols; J++) {
113
+ const k = fine[I * fineCols + J]
114
+ if (k < 0) continue
115
+ const c = { x: x0 + J * r, y: y }
116
+ c[this.interpolatedProperty] = categories[k]
117
+ out.push(c)
118
+ }
119
+ }
120
+
121
+ //draw the interpolated cells with the styles
122
+ this.drawStyles(out, geoCanvas, targetResolution)
123
+ }
124
+ }
125
+
126
+ /**
127
+ * The random walk interpolation of a grid of categories to a grid `factor` times finer.
128
+ *
129
+ * The cell (i,j) of the grid is a point at the centre of its factor x factor fine cells. The category of a fine cell
130
+ * is the one of the first point reached by a random walk which starts on it and moves to a neighbour fine cell
131
+ * (up, down, left or right) at each step. A walk which has not reached a point after maxSteps steps, or which leaves the
132
+ * grid, is ended: the fine cell gets the category of the cell of the grid it is in. The fine cells of the cells without
133
+ * category get no category.
134
+ *
135
+ * The walks are deterministic: they come from the position of the fine cell in the grid of the map, and a seed.
136
+ *
137
+ * @param {Int32Array|Array.<number>} codes The categories of the cells of the grid, as numbers (0, 1, 2...), -1 for no category. Line by line (rows * cols values).
138
+ * @param {number} rows The number of lines
139
+ * @param {number} cols The number of columns
140
+ * @param {number} factor The number of fine cells for a cell, in each direction.
141
+ * @param {{maxSteps?:number, seed?:number, offsetI?:number, offsetJ?:number}} [opts] maxSteps: the maximum number of steps of a walk (default: 6*factor*factor). seed. offsetI and offsetJ: the position of the first fine cell in a larger grid, so that the same fine cell has the same walk in different extents (default: 0).
142
+ * @returns {Int32Array} The categories of the fine cells, line by line (rows * factor lines of cols * factor values), -1 for no category.
143
+ */
144
+ export function randomWalkInterpolate(codes, rows, cols, factor, opts = {}) {
145
+ const maxSteps = opts.maxSteps === undefined ? 6 * factor * factor : opts.maxSteps
146
+ const seed = (opts.seed || 0) | 0
147
+ const offsetI = opts.offsetI || 0
148
+ const offsetJ = opts.offsetJ || 0
149
+
150
+ const fineRows = rows * factor,
151
+ fineCols = cols * factor
152
+ const out = new Int32Array(fineRows * fineCols).fill(-1)
153
+
154
+ // the point of a cell is the fine cell h cells from its top left corner
155
+ const h = Math.floor(factor / 2)
156
+
157
+ for (let I = 0; I < fineRows; I++) {
158
+ const i = Math.floor(I / factor)
159
+ for (let J = 0; J < fineCols; J++) {
160
+ const j = Math.floor(J / factor)
161
+ const own = codes[i * cols + j]
162
+ //no category here
163
+ if (own < 0) continue
164
+
165
+ //a random generator for this fine cell
166
+ let rnd = hash(I + offsetI, J + offsetJ, seed)
167
+
168
+ let a = I,
169
+ b = J,
170
+ found = -1
171
+ for (let step = 0; ; step++) {
172
+ //the fine cell is the point of a cell of the grid?
173
+ if (a % factor === h && b % factor === h) {
174
+ const c = codes[Math.floor(a / factor) * cols + Math.floor(b / factor)]
175
+ if (c >= 0) {
176
+ found = c
177
+ break
178
+ }
179
+ }
180
+ if (step >= maxSteps) break
181
+ //next step, to a neighbour: xorshift32
182
+ rnd ^= rnd << 13
183
+ rnd ^= rnd >>> 17
184
+ rnd ^= rnd << 5
185
+ const dir = (rnd >>> 0) & 3
186
+ if (dir === 0) a--
187
+ else if (dir === 1) a++
188
+ else if (dir === 2) b--
189
+ else b++
190
+ //out of the grid: the walk is ended
191
+ if (a < 0 || a >= fineRows || b < 0 || b >= fineCols) break
192
+ }
193
+ out[I * fineCols + J] = found >= 0 ? found : own
194
+ }
195
+ }
196
+ return out
197
+ }
198
+
199
+ /**
200
+ * A 32 bits number from two integers and a seed, never 0.
201
+ * @param {number} a
202
+ * @param {number} b
203
+ * @param {number} seed
204
+ * @returns {number}
205
+ */
206
+ function hash(a, b, seed) {
207
+ let h = (Math.imul(a | 0, 73856093) ^ Math.imul(b | 0, 19349663) ^ Math.imul(seed, 83492791)) | 0
208
+ //mix the bits
209
+ h = Math.imul(h ^ (h >>> 16), 2246822507)
210
+ h = Math.imul(h ^ (h >>> 13), 3266489909)
211
+ h ^= h >>> 16
212
+ return h === 0 ? 1 : h
213
+ }
@@ -14,11 +14,23 @@ import { extent } from 'd3-array'
14
14
  // style with SquareColorWebGLStyle, improved version !
15
15
 
16
16
  /**
17
+ * A style to draw the shadows cast by the relief, for a position of the sun.
18
+ * For each cell, a ray is cast towards the sun across the elevation grid. The cells in the shadow are drawn as squares of a single color.
19
+ *
20
+ * @example
21
+ * new gridviz.ShadingRayStyle({ elevation: (c) => c.v, sunAzimuth: () => 2.356, sunAltitude: () => 0.2, alpha: () => 0.4 })
22
+ *
17
23
  * @module style
18
24
  * @author Julien Gaffuri
19
25
  */
20
26
  export class ShadingRayStyle extends Style {
21
- /** @param {object} opts */
27
+ /** @param {object} opts The options of the style (see Style for the others: filter, alpha, blendOperation, visible...).
28
+ * @param {function(import('../core/Dataset.js').Cell):number} opts.elevation The elevation of a cell.
29
+ * @param {function(number, number, object):number} [opts.sunAzimuth] (resolution, z, viewScale) => the direction of the sun, in radians, clockwise from the north. Default: 2.356 (south-east).
30
+ * @param {function(number, number, object):number} [opts.sunAltitude] (resolution, z, viewScale) => the height of the sun above the horizon, in radians. Default: 0.2.
31
+ * @param {function(number, number, object):string} [opts.color] (resolution, z, viewScale) => the color of the shadows. Default: black.
32
+ * @param {number} [opts.undefinedValue] The elevation to use for the cells without elevation. Default: 0.
33
+ */
22
34
  constructor(opts) {
23
35
  super(opts)
24
36
  opts = opts || {}
@@ -48,6 +60,8 @@ export class ShadingRayStyle extends Style {
48
60
  //filter
49
61
  if (this.filter) cells = cells.filter(this.filter)
50
62
  if (cells.length == 0) return;
63
+ //the cells of the grid, for the legends: the cells below are the ones of the shading
64
+ const gridCells = cells
51
65
 
52
66
  //
53
67
  const z = geoCanvas.view.z
@@ -124,7 +138,7 @@ export class ShadingRayStyle extends Style {
124
138
  //if (s.filterColor) s.drawFilter(geoCanvas)
125
139
 
126
140
  //update legends
127
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
141
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale, cells: gridCells })
128
142
  }
129
143
  }
130
144
 
@@ -1,72 +1,80 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { SideStyle } from './SideStyle.js'
5
- import { max } from 'd3-array'
6
-
7
- /** @typedef {{ x:number, y:number, or:"v"|"h", c1:(import('../core/Dataset.js').Cell)|undefined, c2:(import('../core/Dataset.js').Cell)|undefined }} Side */
8
-
9
-
10
- /**
11
- * @module style
12
- * @author Julien Gaffuri
13
- */
14
- export class ShadingStyle extends SideStyle {
15
-
16
- /** @param {object} opts
17
- * @param {string} opts.elevation
18
- * @param {boolean} opts.diamond
19
- * @param {function} opts.scale
20
- * @param {function} opts.width
21
- * @param {number} opts.reliefDirection
22
- * @param {string} opts.colorTopLeft
23
- * @param {string} opts.colorBottomRight
24
- */
25
- constructor(opts = {}) {
26
- super(opts)
27
-
28
- /** The cell elevation field name
29
- * @type {string} */
30
- const elevation = opts.elevation
31
-
32
- // compute side value as elevation difference and attach to side
33
- const sideValue = (/** @type {Side} */ side) => {
34
- if (!side.c1) side.v = 0
35
- else if (!side.c2) side.v = 0
36
- else if (!side.c1[elevation]) side.v = 0
37
- else if (!side.c2[elevation]) side.v = 0
38
- else side.v = +side.c2[elevation] - side.c1[elevation]
39
- return side.v
40
- }
41
-
42
- // compute maximum side value for normalization
43
- this.viewScale = sides => max(sides, s => sideValue(s))
44
-
45
- // get colors
46
- let colorTopLeft = opts.colorTopLeft || '255,255,255'
47
- let colorBottomRight = opts.colorBottomRight || '0,0,0'
48
-
49
- // revert colors (to revert the relief, show depressions as hills)
50
- const revert = opts.revert == undefined? false : opts.revert
51
- if(revert) {
52
- let a = colorTopLeft
53
- colorTopLeft = colorBottomRight
54
- colorBottomRight = a
55
- }
56
-
57
- //
58
- const scale = opts.scale
59
-
60
- this.color = (side, resolution, z, max) => {
61
- if (side.v == 0) return
62
- let coeff = Math.abs(side.v / max)
63
- if(scale) coeff = scale(coeff)
64
- if ((side.v < 0 && side.or === 'h') || (side.v > 0 && side.or === 'v'))
65
- return 'rgba(' + colorTopLeft + ',' + coeff + ')'
66
- return 'rgba(' + colorBottomRight + ',' + coeff + ')'
67
- }
68
-
69
- this.width = (_, r, z) => opts.width | Math.min(2 * z, r / 3)
70
- this.diamond = opts.diamond
71
- }
72
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { SideStyle } from './SideStyle.js'
5
+ import { max } from 'd3-array'
6
+
7
+ /** @typedef {{ x:number, y:number, or:"v"|"h", c1:(import('../core/Dataset.js').Cell)|undefined, c2:(import('../core/Dataset.js').Cell)|undefined }} Side */
8
+
9
+
10
+ /**
11
+ * A style to show the relief of an elevation grid as hillshading.
12
+ * For each side between two adjacent cells, a segment is drawn: light when the side faces the top left, dark when it faces the bottom right,
13
+ * with an opacity proportional to the elevation difference between the two cells (relative to the biggest one in the view).
14
+ *
15
+ * @example
16
+ * new gridviz.ShadingStyle({ elevation: 'v', colorTopLeft: '255,155,155', colorBottomRight: '0,0,100' })
17
+ *
18
+ * @module style
19
+ * @author Julien Gaffuri
20
+ */
21
+ export class ShadingStyle extends SideStyle {
22
+
23
+ /** @param {object} opts The options of the style (see SideStyle and Style for the others: filter, alpha, blendOperation, visible...).
24
+ * @param {string} opts.elevation The name of the cell property with the elevation.
25
+ * @param {string} [opts.colorTopLeft] The color of the sides which face the top left, as 'r,g,b'. Default: '255,255,255'.
26
+ * @param {string} [opts.colorBottomRight] The color of the sides which face the bottom right, as 'r,g,b'. Default: '0,0,0'.
27
+ * @param {boolean} [opts.revert] Swaps the two colors, to show depressions as hills. Default: false.
28
+ * @param {function(number):number} [opts.scale] Stretches the opacity, from a value within [0,1] to a value within [0,1]. Default: linear.
29
+ * @param {number} [opts.width] The width of the segments, in geographical unit. Default: 2 pixels, and at most a third of the resolution.
30
+ * @param {boolean} [opts.diamond] Draws the sides as diamonds.
31
+ */
32
+ constructor(opts = {}) {
33
+ super(opts)
34
+
35
+ /** The cell elevation field name
36
+ * @type {string} */
37
+ const elevation = opts.elevation
38
+
39
+ // compute side value as elevation difference and attach to side
40
+ const sideValue = (/** @type {Side} */ side) => {
41
+ if (!side.c1) side.v = 0
42
+ else if (!side.c2) side.v = 0
43
+ else if (!side.c1[elevation]) side.v = 0
44
+ else if (!side.c2[elevation]) side.v = 0
45
+ else side.v = +side.c2[elevation] - side.c1[elevation]
46
+ return side.v
47
+ }
48
+
49
+ // compute maximum side value for normalization
50
+ this.viewScale = sides => max(sides, s => sideValue(s))
51
+
52
+ // get colors
53
+ let colorTopLeft = opts.colorTopLeft || '255,255,255'
54
+ let colorBottomRight = opts.colorBottomRight || '0,0,0'
55
+
56
+ // revert colors (to revert the relief, show depressions as hills)
57
+ const revert = opts.revert == undefined? false : opts.revert
58
+ if(revert) {
59
+ let a = colorTopLeft
60
+ colorTopLeft = colorBottomRight
61
+ colorBottomRight = a
62
+ }
63
+
64
+ //
65
+ const scale = opts.scale
66
+
67
+ this.color = (side, resolution, z, max) => {
68
+ if (side.v == 0) return
69
+ let coeff = Math.abs(side.v / max)
70
+ if(scale) coeff = scale(coeff)
71
+ if ((side.v < 0 && side.or === 'h') || (side.v > 0 && side.or === 'v'))
72
+ return 'rgba(' + colorTopLeft + ',' + coeff + ')'
73
+ return 'rgba(' + colorBottomRight + ',' + coeff + ')'
74
+ }
75
+
76
+ // 2 pixels, and at most a third of the resolution (a bitwise OR here truncated the width to an integer number of geographical units)
77
+ this.width = (_, r, z) => opts.width || Math.min(2 * z, r / 3)
78
+ this.diamond = opts.diamond
79
+ }
80
+ }
@@ -23,6 +23,13 @@ export class ShapeColorSizeStyle extends Style {
23
23
 
24
24
  /** @type {(function(import("../core/Dataset.js").Cell,number, number,object):import("../core/Style.js").Shape) | string} */
25
25
  this.shape = opts.shape || 'square'
26
+
27
+ /**
28
+ * For the donut shape, the outer diameter of the donut, in geographical unit (the resolution by default, so that the donut fills the cell).
29
+ * The size of the donut is then the part of this diameter it fills: the donut is a full disk when its size equals its outer diameter, and a thin ring when its size is small.
30
+ * With a smaller outer diameter, a donut can be a ring around another symbol, a pie chart for example, or a part of a symbol with several rings.
31
+ * @type {(function(import('../core/Dataset.js').Cell, number, number, object):number) | number | undefined} */
32
+ this.donutOuterSize = opts.donutOuterSize
26
33
  }
27
34
 
28
35
  /**
@@ -98,10 +105,19 @@ export class ShapeColorSizeStyle extends Style {
98
105
  //draw donut
99
106
  const xc = c.x + r2 + offset.dx,
100
107
  yc = c.y + r2 + offset.dy
108
+ // outer diameter: the resolution, unless specified
109
+ const outer =
110
+ this.donutOuterSize === undefined
111
+ ? resolution
112
+ : typeof this.donutOuterSize === 'function'
113
+ ? this.donutOuterSize(c, resolution, z, viewScale)
114
+ : this.donutOuterSize
115
+ if (!outer) continue
116
+ const R = outer * 0.5
101
117
  ctx.beginPath()
102
118
  ctx.moveTo(xc, yc)
103
- ctx.arc(xc, yc, r2, 0, 2 * Math.PI)
104
- ctx.arc(xc, yc, (1 - size / resolution) * r2, 0, 2 * Math.PI, true)
119
+ ctx.arc(xc, yc, R, 0, 2 * Math.PI)
120
+ ctx.arc(xc, yc, Math.max(0, 1 - size / outer) * R, 0, 2 * Math.PI, true)
105
121
  ctx.closePath()
106
122
  ctx.fill()
107
123
  } else if (shape === 'diamond') {
@@ -107,6 +107,6 @@ export class SideCategoryStyle extends SideStyle {
107
107
  }
108
108
 
109
109
  //update legends
110
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
110
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale, cells: cells })
111
111
  }
112
112
  }
@@ -112,7 +112,7 @@ export class SideStyle extends Style {
112
112
  }
113
113
 
114
114
  //update legends
115
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
115
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale, cells: cells })
116
116
  }
117
117
 
118
118
  /**
@@ -148,7 +148,7 @@ export class SideTanakaStyle extends Style {
148
148
  }
149
149
 
150
150
  //update legends
151
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
151
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale, cells: cells })
152
152
  }
153
153
 
154
154
  }