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
package/src/index.js CHANGED
@@ -1,79 +1,82 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- // the application
5
- export { Map } from './core/Map.js'
6
- export { GeoCanvas } from './core/GeoCanvas.js'
7
- export { Style } from './core/Style.js'
8
- export { Layer } from './core/Layer.js'
9
- export { Dataset } from './core/Dataset.js'
10
- export { MultiResolutionDataset } from './core/MultiResolutionDataset.js'
11
-
12
- // export dataset types
13
- export { TiledGrid } from './dataset/TiledGrid.js'
14
- export { CSVGrid } from './dataset/CSVGrid.js'
15
- export { JSGrid } from './dataset/JSGrid.js'
16
-
17
- // export styles
18
- export { ShapeColorSizeStyle } from './style/ShapeColorSizeStyle.js'
19
- export { StrokeStyle } from './style/StrokeStyle.js'
20
- export { JoyPlotStyle } from './style/JoyPlotStyle.js'
21
- export { CompositionStyle } from './style/CompositionStyle.js'
22
- export { SegmentStyle } from './style/SegmentStyle.js'
23
- export { TextStyle } from './style/TextStyle.js'
24
- export { PillarStyle } from './style/PillarStyle.js'
25
- export { SideStyle } from './style/SideStyle.js'
26
- export { ShadingRayStyle } from './style/ShadingRayStyle.js'
27
- export { ShadingStyle } from './style/ShadingStyle.js'
28
- export { SideCategoryStyle } from './style/SideCategoryStyle.js'
29
- export { DotDensityStyle } from './style/DotDensityStyle.js'
30
- export { SideTanakaStyle } from './style/SideTanakaStyle.js'
31
- export { LegoStyle } from './style/LegoStyle.js'
32
- export { SquareColorWebGLStyle } from './style/SquareColorWebGLStyle.js'
33
- export { SquareColorCategoryWebGLStyle } from './style/SquareColorCategoryWebGLStyle.js'
34
- export { MosaicStyle } from './style/MosaicStyle.js'
35
- export { NinjaStarStyle } from './style/NinjaStarStyle.js'
36
- export { TimeSeriesStyle } from './style/TimeSeriesStyle.js'
37
- export { IsoFenceStyle } from './style/IsoFenceStyle.js'
38
- export { ImageStyle } from './style/ImageStyle.js'
39
- export { Interpolator } from './style/Interpolator.js'
40
-
41
- // export additional layers
42
- export { GridLayer } from './layer/GridLayer.js'
43
- export { BackgroundLayer } from './layer/BackgroundLayer.js'
44
- export { BackgroundLayerWMS } from './layer/BackgroundLayerWMS.js'
45
- export { BackgroundLayerImage } from './layer/BackgroundLayerImage.js'
46
- export { LabelLayer } from './layer/LabelLayer.js'
47
- export { GeoJSONLayer } from './layer/GeoJSONLayer.js'
48
-
49
- // export legends
50
- export { ColorLegend } from './legend/ColorLegend.js'
51
- export { ColorDiscreteLegend } from './legend/ColorDiscreteLegend.js'
52
- export { ColorCategoryLegend } from './legend/ColorCategoryLegend.js'
53
- export {
54
- SizeLegend,
55
- sizeLegend,
56
- sizeLegendViewScale,
57
- sizeDiscreteLegend,
58
- sizeDiscreteViewScaleLegend,
59
- } from './legend/SizeLegend.js'
60
- export { OrientationLegend, orientationLegend } from './legend/OrientationLegend.js'
61
- export { TernaryLegend } from './legend/TernaryLegend.js'
62
-
63
- // export { goToStraight, zoomTo } from "./utils/zoomUtils"
64
- export * from './utils/stretching.js'
65
- export * from './utils/scale.js'
66
- export * from './utils/ternary.js'
67
- export { nice, cellsToMatrix } from './utils/utils.js'
68
-
69
- import { GeoCanvas } from './core/GeoCanvas.js'
70
- export const getParameterByName = GeoCanvas.getParameterByName
71
-
72
- // set default d3 locale
73
- import { formatDefaultLocale } from 'd3-format'
74
- formatDefaultLocale({
75
- decimal: '.',
76
- thousands: ' ',
77
- grouping: [3],
78
- currency: ['', '€'],
79
- })
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ // the application
5
+ export { Map } from './core/Map.js'
6
+ export { GeoCanvas } from './core/GeoCanvas.js'
7
+ export { Style } from './core/Style.js'
8
+ export { Layer } from './core/Layer.js'
9
+ export { Dataset } from './core/Dataset.js'
10
+ export { MultiResolutionDataset } from './core/MultiResolutionDataset.js'
11
+
12
+ // export dataset types
13
+ export { TiledGrid } from './dataset/TiledGrid.js'
14
+ export { CSVGrid } from './dataset/CSVGrid.js'
15
+ export { JSGrid } from './dataset/JSGrid.js'
16
+
17
+ // export styles
18
+ export { ShapeColorSizeStyle } from './style/ShapeColorSizeStyle.js'
19
+ export { StrokeStyle } from './style/StrokeStyle.js'
20
+ export { JoyPlotStyle } from './style/JoyPlotStyle.js'
21
+ export { CompositionStyle } from './style/CompositionStyle.js'
22
+ export { SegmentStyle } from './style/SegmentStyle.js'
23
+ export { TextStyle } from './style/TextStyle.js'
24
+ export { PillarStyle } from './style/PillarStyle.js'
25
+ export { SideStyle } from './style/SideStyle.js'
26
+ export { ShadingRayStyle } from './style/ShadingRayStyle.js'
27
+ export { ShadingStyle } from './style/ShadingStyle.js'
28
+ export { SideCategoryStyle } from './style/SideCategoryStyle.js'
29
+ export { DotDensityStyle } from './style/DotDensityStyle.js'
30
+ export { SideTanakaStyle } from './style/SideTanakaStyle.js'
31
+ export { LegoStyle } from './style/LegoStyle.js'
32
+ export { SquareColorWebGLStyle } from './style/SquareColorWebGLStyle.js'
33
+ export { SquareColorCategoryWebGLStyle } from './style/SquareColorCategoryWebGLStyle.js'
34
+ export { CircleColorSizeWebGLStyle } from './style/CircleColorSizeWebGLStyle.js'
35
+ export { MosaicStyle } from './style/MosaicStyle.js'
36
+ export { NinjaStarStyle } from './style/NinjaStarStyle.js'
37
+ export { TimeSeriesStyle } from './style/TimeSeriesStyle.js'
38
+ export { IsoFenceStyle } from './style/IsoFenceStyle.js'
39
+ export { ImageStyle } from './style/ImageStyle.js'
40
+ export { Interpolator } from './style/Interpolator.js'
41
+ export { RandomWalkInterpolator } from './style/RandomWalkInterpolator.js'
42
+
43
+ // export additional layers
44
+ export { GridLayer } from './layer/GridLayer.js'
45
+ export { BackgroundLayer } from './layer/BackgroundLayer.js'
46
+ export { BackgroundLayerWMS } from './layer/BackgroundLayerWMS.js'
47
+ export { BackgroundLayerImage } from './layer/BackgroundLayerImage.js'
48
+ export { LabelLayer } from './layer/LabelLayer.js'
49
+ export { GeoJSONLayer } from './layer/GeoJSONLayer.js'
50
+
51
+ // export legends
52
+ export { ColorLegend } from './legend/ColorLegend.js'
53
+ export { ColorDiscreteLegend } from './legend/ColorDiscreteLegend.js'
54
+ export { ColorCategoryLegend } from './legend/ColorCategoryLegend.js'
55
+ export {
56
+ SizeLegend,
57
+ sizeLegend,
58
+ sizeLegendViewScale,
59
+ sizeDiscreteLegend,
60
+ sizeDiscreteViewScaleLegend,
61
+ } from './legend/SizeLegend.js'
62
+ export { OrientationLegend, orientationLegend } from './legend/OrientationLegend.js'
63
+ export { TernaryLegend } from './legend/TernaryLegend.js'
64
+ export { VennLegend } from './legend/VennLegend.js'
65
+
66
+ // export { goToStraight, zoomTo } from "./utils/zoomUtils"
67
+ export * from './utils/stretching.js'
68
+ export * from './utils/scale.js'
69
+ export * from './utils/ternary.js'
70
+ export { nice, cellsToMatrix } from './utils/utils.js'
71
+
72
+ import { GeoCanvas } from './core/GeoCanvas.js'
73
+ export const getParameterByName = GeoCanvas.getParameterByName
74
+
75
+ // set default d3 locale
76
+ import { formatDefaultLocale } from 'd3-format'
77
+ formatDefaultLocale({
78
+ decimal: '.',
79
+ thousands: ' ',
80
+ grouping: [3],
81
+ currency: ['', '€'],
82
+ })
@@ -1,194 +1,196 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Layer } from '../core/Layer.js'
5
-
6
- /**
7
- * A layer, which specifies a dataset to be shown with specified styles.
8
- *
9
- * @module layer
10
- * @author Joseph Davies, Julien Gaffuri
11
- */
12
- export class GridLayer extends Layer {
13
- /**
14
- * @param {import("../core/Dataset").Dataset|import("../core/MultiResolutionDataset").MultiResolutionDataset} dataset The dataset to show.
15
- * @param {Array.<import("../core/Style").Style>} styles The styles, ordered in drawing order.
16
- * @param {{visible?:function(number):boolean,alpha?:function(number):number,blendOperation?:function(number):GlobalCompositeOperation,minPixelsPerCell?:number,cellInfoHTML?:'none'|function(import("../core/Dataset").Cell):string}} opts
17
- */
18
- constructor(dataset, styles, opts = {}) {
19
- super(opts)
20
- opts = opts || {}
21
-
22
- /** @type {import("../core/Dataset").Dataset|import("../core/MultiResolutionDataset").MultiResolutionDataset} */
23
- this.dataset = dataset
24
-
25
- /** @type {Array.<import("../core/Style").Style>} */
26
- this.styles = styles
27
-
28
- /**
29
- * This parameter is used when the dataset is a MultiResolutionDataset.
30
- * It defines the minimum number of pixels a grid cell should have to select the dataset to display based on its resolution.
31
- * A low value, means that the map will be more detailled (smaller cells).
32
- * A high value, means that the map will be less detailled (larger cells).
33
- * This value should be higher than 1, otherwise it means a grid cell is smaller than the screen resolution.
34
- * For more complex cell representations that require some more map space, this value should be higher.
35
- * @type {number} */
36
- this.minPixelsPerCell = opts.minPixelsPerCell || 3
37
-
38
- /**
39
- * The function returning cell information as HTML.
40
- * This is typically used for tooltip information.
41
- * Set to 'none' to disable cell info.
42
- * @type {'none'|function(import("../core/Dataset").Cell, number):string} */
43
- this.cellInfoHTML = opts.cellInfoHTML || GridLayer.defaultCellInfoHTML
44
- }
45
-
46
- /** */
47
- draw(geoCanvas, legend) {
48
- //get zoom level
49
- const z = geoCanvas.view.z
50
- const ctx = geoCanvas.offscreenCtx
51
-
52
- //get layer dataset component
53
- /** @type {import('../core/Dataset.js').Dataset|undefined} */
54
- const dsc = this.getDataset(z)
55
- if (!dsc) return
56
-
57
- //launch data download, if necessary
58
- dsc.getData(geoCanvas.extGeo)
59
-
60
- //update dataset view cache
61
- dsc.updateViewCache(geoCanvas.extGeo)
62
-
63
-
64
- //set layer alpha and blend mode
65
- if (this.alpha || this.blendOperation) {
66
- ctx.save()
67
- if (this.alpha) ctx.globalAlpha = this.alpha(z)
68
- if (this.blendOperation) ctx.globalCompositeOperation = this.blendOperation(z)
69
- }
70
-
71
- // tell the legends where they are drawn, so that they can fit it (width:'fill')
72
- if (legend) for (const s of this.styles) GridLayer.setLegendContainer(legend.node(), s.legends, s['styles'])
73
-
74
- //draw cells, style by style
75
- for (const s of this.styles) {
76
- //check if style is visible
77
- if (s.visible && !s.visible(z)) continue
78
-
79
- // set style alpha and blend mode
80
- //TODO: multiply style alpha by layer alpha ?
81
- if (s.alpha || s.blendOperation) {
82
- ctx.save()
83
- if (s.alpha) ctx.globalAlpha = s.alpha(z)
84
- if (s.blendOperation) ctx.globalCompositeOperation = s.blendOperation(z)
85
- }
86
-
87
- //set affin transform to draw with geographical coordinates
88
- geoCanvas.setCanvasTransform()
89
-
90
- //draw with style
91
- s.draw(dsc.getViewCache(), geoCanvas, dsc.getResolution())
92
-
93
- //draw style filter
94
- if (s.filterColor) s.drawFilter(geoCanvas)
95
-
96
- //restore default alpha and blend operation - before style change
97
- if (s.alpha || s.blendOperation) ctx.restore()
98
- }
99
-
100
- //restore default alpha and blend operation - before layer change
101
- if (this.alpha || this.blendOperation) ctx.restore()
102
-
103
- //add legend element
104
- if (legend) {
105
- for (const s of this.styles) {
106
- //check if style is visible
107
- if (s.visible && !s.visible(z)) continue
108
- GridLayer.addLegends(legend, s.legends, s, geoCanvas)
109
-
110
- //case for styles of styles, like kernel smoothing
111
- //TODO do better
112
- if (s['styles']) {
113
- for (const s2 of s['styles']) {
114
- if (s2.visible && !s2.visible(z)) continue
115
- GridLayer.addLegends(legend, s2.legends, s2, geoCanvas)
116
- }
117
- }
118
- }
119
- }
120
- }
121
-
122
- /** @private */
123
- static setLegendContainer(container, legends, subStyles) {
124
- // legends can be nested in arrays, like in Style.updateLegendsRecursive
125
- const set = (lg) => {
126
- if (Array.isArray(lg)) lg.forEach(set)
127
- else if (lg) lg.container = container
128
- }
129
- set(legends)
130
- for (const s2 of subStyles || []) GridLayer.setLegendContainer(container, s2.legends, undefined)
131
- }
132
-
133
- /** @private */
134
- static addLegends(legendComp, lg, style, geoCanvas) {
135
- if (Array.isArray(lg)) for (const lg_ of lg) this.addLegends(legendComp, lg_, style, geoCanvas)
136
- else {
137
- // so that hovering a swatch can highlight the cells of the style on the map
138
- lg.style_ = style
139
- lg.redraw = () => (geoCanvas.redraw ? geoCanvas.redraw() : undefined)
140
- // The legends go in the order they are drawn, after the one placed before them. A hovered legend is
141
- // still in the container (see Map.redrawNow) and is left where it is: moving it would lose its mouseleave,
142
- // and appending the others after it would put it above the legends that come before it.
143
- const container = legendComp.node()
144
- const el = lg.div.node()
145
- const previous = container._gridvizLegendCursor
146
- if (previous) {
147
- if (el.previousSibling !== previous) previous.after(el)
148
- } else if (container.firstChild !== el) container.prepend(el)
149
- container._gridvizLegendCursor = el
150
- }
151
- }
152
-
153
- /**
154
- * Return the relevant dataset component for a specified zoom.
155
- *
156
- * @param {number} z
157
- * @returns {import("../core/Dataset").Dataset|undefined}
158
- * */
159
- getDataset(z) {
160
- return this.dataset.getDataset(z, this.minPixelsPerCell)
161
- }
162
-
163
- /**
164
- * Set/get style stack.
165
- *
166
- * @param {undefined|import("../core/Style").Style|Array.<import("../core/Style").Style>} styles
167
- * @returns { this | Array.<import("../core/Style").Style> }
168
- */
169
- styles_(styles) {
170
- if (arguments.length === 0) return this.styles
171
- if (arguments.length === 1)
172
- if (Array.isArray(styles)) this.styles = styles
173
- else this.styles = [styles]
174
- else this.styles = arguments
175
- return this
176
- }
177
-
178
- /**
179
- * The default function returning cell information as HTML.
180
- * This is typically used for tooltip information.
181
- *
182
- * @param {import("../core/Dataset").Cell} cell
183
- * @returns {string}
184
- */
185
- static defaultCellInfoHTML(cell) {
186
- const buf = []
187
- for (const key of Object.keys(cell)) {
188
- if (key === 'x') continue
189
- if (key === 'y') continue
190
- buf.push('<b>', key, '</b>', ' : ', cell[key], '<br>')
191
- }
192
- return buf.join('')
193
- }
194
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Layer } from '../core/Layer.js'
5
+ import { isVisibleAt } from '../core/Drawable.js'
6
+
7
+ /**
8
+ * A layer, which specifies a dataset to be shown with specified styles.
9
+ *
10
+ * @module layer
11
+ * @author Joseph Davies, Julien Gaffuri
12
+ */
13
+ export class GridLayer extends Layer {
14
+ /**
15
+ * @param {import("../core/Dataset").Dataset|import("../core/MultiResolutionDataset").MultiResolutionDataset} dataset The dataset to show.
16
+ * @param {Array.<import("../core/Style").Style>} styles The styles, ordered in drawing order.
17
+ * @param {{visible?:function(number):boolean,alpha?:function(number):number,blendOperation?:function(number):GlobalCompositeOperation,minPixelsPerCell?:number,cellInfoHTML?:'none'|function(import("../core/Dataset").Cell):string}} opts
18
+ */
19
+ constructor(dataset, styles, opts = {}) {
20
+ super(opts)
21
+ opts = opts || {}
22
+
23
+ /** @type {import("../core/Dataset").Dataset|import("../core/MultiResolutionDataset").MultiResolutionDataset} */
24
+ this.dataset = dataset
25
+
26
+ /** @type {Array.<import("../core/Style").Style>} */
27
+ this.styles = styles
28
+
29
+ /**
30
+ * This parameter is used when the dataset is a MultiResolutionDataset.
31
+ * It defines the minimum number of pixels a grid cell should have to select the dataset to display based on its resolution.
32
+ * A low value, means that the map will be more detailled (smaller cells).
33
+ * A high value, means that the map will be less detailled (larger cells).
34
+ * This value should be higher than 1, otherwise it means a grid cell is smaller than the screen resolution.
35
+ * For more complex cell representations that require some more map space, this value should be higher.
36
+ * @type {number} */
37
+ this.minPixelsPerCell = opts.minPixelsPerCell || 3
38
+
39
+ /**
40
+ * The function returning cell information as HTML.
41
+ * This is typically used for tooltip information.
42
+ * Set to 'none' to disable cell info.
43
+ * @type {'none'|function(import("../core/Dataset").Cell, number):string} */
44
+ this.cellInfoHTML = opts.cellInfoHTML || GridLayer.defaultCellInfoHTML
45
+ }
46
+
47
+ /** */
48
+ draw(geoCanvas, legend) {
49
+ //get zoom level
50
+ const z = geoCanvas.view.z
51
+ const ctx = geoCanvas.offscreenCtx
52
+
53
+ //get layer dataset component
54
+ /** @type {import('../core/Dataset.js').Dataset|undefined} */
55
+ const dsc = this.getDataset(z)
56
+ if (!dsc) return
57
+
58
+ //launch data download, if necessary
59
+ dsc.getData(geoCanvas.extGeo)
60
+
61
+ //update dataset view cache
62
+ dsc.updateViewCache(geoCanvas.extGeo)
63
+
64
+
65
+ //set layer alpha and blend mode
66
+ if (this.alpha || this.blendOperation) {
67
+ ctx.save()
68
+ if (this.alpha) ctx.globalAlpha = this.alpha(z)
69
+ if (this.blendOperation) ctx.globalCompositeOperation = this.blendOperation(z)
70
+ }
71
+
72
+ // tell the legends where they are drawn, so that they can fit it (width:'fill')
73
+ if (legend) for (const s of this.styles) GridLayer.setLegendContainer(legend.node(), s.legends, s['styles'])
74
+
75
+ //draw cells, style by style
76
+ for (const s of this.styles) {
77
+ //check if style is visible
78
+ if (!isVisibleAt(s, z)) continue
79
+
80
+ // set style alpha and blend mode
81
+ //TODO: multiply style alpha by layer alpha ?
82
+ if (s.alpha || s.blendOperation) {
83
+ ctx.save()
84
+ if (s.alpha) ctx.globalAlpha = s.alpha(z)
85
+ if (s.blendOperation) ctx.globalCompositeOperation = s.blendOperation(z)
86
+ }
87
+
88
+ //set affin transform to draw with geographical coordinates
89
+ geoCanvas.setCanvasTransform()
90
+
91
+ //draw with style
92
+ s.draw(dsc.getViewCache(), geoCanvas, dsc.getResolution())
93
+
94
+ //draw style filter
95
+ if (s.filterColor) s.drawFilter(geoCanvas)
96
+
97
+ //restore default alpha and blend operation - before style change
98
+ if (s.alpha || s.blendOperation) ctx.restore()
99
+ }
100
+
101
+ //restore default alpha and blend operation - before layer change
102
+ if (this.alpha || this.blendOperation) ctx.restore()
103
+
104
+ //add legend element
105
+ if (legend) {
106
+ for (const s of this.styles) {
107
+ //check if style is visible
108
+ if (!isVisibleAt(s, z)) continue
109
+ GridLayer.addLegends(legend, s.legends, s, geoCanvas, this.styles)
110
+
111
+ //case for styles of styles, like kernel smoothing
112
+ //TODO do better
113
+ if (s['styles']) {
114
+ for (const s2 of s['styles']) {
115
+ if (!isVisibleAt(s2, z)) continue
116
+ GridLayer.addLegends(legend, s2.legends, s2, geoCanvas)
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ /** @private */
124
+ static setLegendContainer(container, legends, subStyles) {
125
+ // legends can be nested in arrays, like in Style.updateLegendsRecursive
126
+ const set = (lg) => {
127
+ if (Array.isArray(lg)) lg.forEach(set)
128
+ else if (lg) lg.container = container
129
+ }
130
+ set(legends)
131
+ for (const s2 of subStyles || []) GridLayer.setLegendContainer(container, s2.legends, undefined)
132
+ }
133
+
134
+ /** @private */
135
+ static addLegends(legendComp, lg, style, geoCanvas, layerStyles) {
136
+ if (Array.isArray(lg)) for (const lg_ of lg) this.addLegends(legendComp, lg_, style, geoCanvas, layerStyles)
137
+ else {
138
+ // so that hovering a swatch can highlight the cells of the style on the map
139
+ lg.style_ = style
140
+ lg.layerStyles = layerStyles
141
+ lg.redraw = () => (geoCanvas.redraw ? geoCanvas.redraw() : undefined)
142
+ // The legends go in the order they are drawn, after the one placed before them. A hovered legend is
143
+ // still in the container (see Map.redrawNow) and is left where it is: moving it would lose its mouseleave,
144
+ // and appending the others after it would put it above the legends that come before it.
145
+ const container = legendComp.node()
146
+ const el = lg.div.node()
147
+ const previous = container._gridvizLegendCursor
148
+ if (previous) {
149
+ if (el.previousSibling !== previous) previous.after(el)
150
+ } else if (container.firstChild !== el) container.prepend(el)
151
+ container._gridvizLegendCursor = el
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Return the relevant dataset component for a specified zoom.
157
+ *
158
+ * @param {number} z
159
+ * @returns {import("../core/Dataset").Dataset|undefined}
160
+ * */
161
+ getDataset(z) {
162
+ return this.dataset.getDataset(z, this.minPixelsPerCell)
163
+ }
164
+
165
+ /**
166
+ * Set/get style stack.
167
+ *
168
+ * @param {undefined|import("../core/Style").Style|Array.<import("../core/Style").Style>} styles
169
+ * @returns { this | Array.<import("../core/Style").Style> }
170
+ */
171
+ styles_(styles) {
172
+ if (arguments.length === 0) return this.styles
173
+ if (arguments.length === 1)
174
+ if (Array.isArray(styles)) this.styles = styles
175
+ else this.styles = [styles]
176
+ else this.styles = arguments
177
+ return this
178
+ }
179
+
180
+ /**
181
+ * The default function returning cell information as HTML.
182
+ * This is typically used for tooltip information.
183
+ *
184
+ * @param {import("../core/Dataset").Cell} cell
185
+ * @returns {string}
186
+ */
187
+ static defaultCellInfoHTML(cell) {
188
+ const buf = []
189
+ for (const key of Object.keys(cell)) {
190
+ if (key === 'x') continue
191
+ if (key === 'y') continue
192
+ buf.push('<b>', key, '</b>', ' : ', cell[key], '<br>')
193
+ }
194
+ return buf.join('')
195
+ }
196
+ }
@@ -110,14 +110,17 @@ export class LabelLayer extends Layer {
110
110
  geoCanvas.initCanvasTransform()
111
111
 
112
112
  //draw labels, one by one
113
+ //The font, the colors... are not set again when they do not change from a label to the next one: the browser parses
114
+ //them at each assignment, which is slow.
115
+ let font
113
116
  for (const lb of this.labels) {
117
+ //check label within the view, to be drawn. First: there are many labels (180000 for Europe), a few are in the view.
118
+ if (!geoCanvas.toDraw(lb)) continue
119
+
114
120
  //get label style
115
121
  const st = this.style(lb, z)
116
122
  if (!st) continue
117
- ctx.font = st
118
-
119
- //check label within the view, to be drawn
120
- if (!geoCanvas.toDraw(lb)) continue
123
+ if (st !== font) ctx.font = font = st
121
124
 
122
125
  //position
123
126
  const xP = geoCanvas.geoToPixX(lb.x) + this.offsetPix[0]