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
@@ -1,125 +1,127 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Legend } from '../core/Legend.js'
5
-
6
- /**
7
- * A legend element for color categrories.
8
- *
9
- * @module legend
10
- * @author Joseph Davies, Julien Gaffuri
11
- */
12
- export class ColorCategoryLegend extends Legend {
13
- /** @param {Object} opts */
14
- constructor(opts) {
15
- super(opts)
16
- opts = opts || {}
17
-
18
- //col/categories array, in display order
19
- /**
20
- * @private
21
- * @type {Array.<[string,string]>} */
22
- this.colorLabel = opts.colorLabel || [['gray', '-']]
23
-
24
- /**
25
- * @private
26
- * @type {import("../core/Style.js").Shape} */
27
- this.shape = opts.shape || 'circle'
28
- this.dimension = opts.dimension || { r: 8 }
29
- this.strokeColor = opts.strokeColor || 'gray'
30
- this.strokeWidth = opts.strokeWidth || 1
31
- this.setType('category')
32
- }
33
-
34
- /**
35
- */
36
- update() {
37
- //clear
38
- this.div.selectAll('*').remove()
39
-
40
- //title
41
- this.makeTitle()
42
-
43
- //categories
44
- const nb = this.colorLabel.length
45
- if (nb == 0) return
46
-
47
- for (let i = 0; i < nb; i++) {
48
- const cat = this.colorLabel[i]
49
-
50
- //make div for category
51
- const d = this.div.append('div').classed('gridviz-legend-category', true)
52
- // hovering a category shows only its cells on the map
53
- this.bindHover(d, cat[0], {
54
- enter: () => d.classed('gridviz-legend-category--active', true).select('svg').select('rect, circle').style('stroke', 'red'),
55
- leave: () => d.classed('gridviz-legend-category--active', false).select('svg').select('rect, circle').style('stroke', this.strokeColor),
56
- })
57
- //to enable vertical centering
58
- //.style("position", "relative")
59
-
60
- const sw = this.strokeWidth
61
-
62
- //draw graphic element: box / circle
63
- if (this.shape === 'square') {
64
- const h = this.dimension.h || 15
65
- const w = this.dimension.w || 20
66
- d.append('div')
67
- .classed('gridviz-legend-symbol-wrapper', true)
68
- .style('display', 'inline')
69
-
70
- .append('svg')
71
- .classed('gridviz-legend-graphic', true)
72
- .attr('width', w + 2 * sw)
73
- .attr('height', h + 2 * sw)
74
-
75
- .append('rect')
76
- .classed('gridviz-legend-swatch', true)
77
- .attr('x', sw)
78
- .attr('y', sw)
79
- .attr('width', w)
80
- .attr('height', h)
81
- .style('fill', cat[0])
82
- .style('stroke', this.strokeColor)
83
- .style('stroke-width', this.strokeWidth)
84
- } else if (this.shape === 'circle') {
85
- const r = this.dimension.r || 8
86
- const h = 2 * r + 2 * sw
87
- d.append('div')
88
- .classed('gridviz-legend-symbol-wrapper', true)
89
- .style('display', 'inline')
90
-
91
- .append('svg')
92
- .classed('gridviz-legend-graphic', true)
93
- .attr('width', h)
94
- .attr('height', h)
95
-
96
- .append('circle')
97
- .classed('gridviz-legend-swatch', true)
98
- .attr('cx', r + sw)
99
- .attr('cy', r + sw)
100
- .attr('r', r)
101
- .style('fill', cat[0])
102
- .style('stroke', this.strokeColor)
103
- .style('stroke-width', this.strokeWidth)
104
- } else {
105
- throw new Error('Unexpected shape:' + this.shape)
106
- }
107
-
108
- //write label text
109
- this.setText(
110
- d
111
- .append('div')
112
- //show on right of graphic
113
- .style('display', 'inline')
114
-
115
- //center vertically
116
- //.style("position", "absolute").style("top", "0").style("bottom", "0")
117
-
118
- .classed('gridviz-legend-label', true)
119
- .style('padding-left', '5px')
120
- .style('font-size', this.labelFontSizeCSS()),
121
- cat[1]
122
- )
123
- }
124
- }
125
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Legend } from '../core/Legend.js'
5
+
6
+ /**
7
+ * A legend element for color categrories.
8
+ *
9
+ * @module legend
10
+ * @author Joseph Davies, Julien Gaffuri
11
+ */
12
+ export class ColorCategoryLegend extends Legend {
13
+ /** @param {Object} opts */
14
+ constructor(opts) {
15
+ super(opts)
16
+ opts = opts || {}
17
+
18
+ //col/categories array, in display order
19
+ /**
20
+ * @private
21
+ * @type {Array.<[string,string]>} */
22
+ this.colorLabel = opts.colorLabel || [['gray', '-']]
23
+
24
+ /**
25
+ * @private
26
+ * @type {import("../core/Style.js").Shape} */
27
+ this.shape = opts.shape || 'circle'
28
+ this.dimension = opts.dimension || { r: 8 }
29
+ this.strokeColor = opts.strokeColor || 'gray'
30
+ this.strokeWidth = opts.strokeWidth || 1
31
+ this.setType('category')
32
+ }
33
+
34
+ /**
35
+ */
36
+ update() {
37
+ //clear
38
+ this.div.selectAll('*').remove()
39
+
40
+ //title
41
+ this.makeTitle()
42
+
43
+ //categories
44
+ const nb = this.colorLabel.length
45
+ if (nb == 0) return
46
+
47
+ for (let i = 0; i < nb; i++) {
48
+ const cat = this.colorLabel[i]
49
+
50
+ //make div for category
51
+ const d = this.div.append('div').classed('gridviz-legend-category', true)
52
+ // hovering a category shows only its cells on the map
53
+ this.bindHover(d, cat[0], {
54
+ enter: () => d.classed('gridviz-legend-category--active', true).select('svg').select('rect, circle').style('stroke', 'red'),
55
+ leave: () => d.classed('gridviz-legend-category--active', false).select('svg').select('rect, circle').style('stroke', this.strokeColor),
56
+ })
57
+ //to enable vertical centering
58
+ //.style("position", "relative")
59
+
60
+ const sw = this.strokeWidth
61
+
62
+ //draw graphic element: box / circle
63
+ if (this.shape === 'square') {
64
+ const h = this.dimension.h || 15
65
+ const w = this.dimension.w || 20
66
+ d.append('div')
67
+ .classed('gridviz-legend-symbol-wrapper', true)
68
+ .style('display', 'inline')
69
+
70
+ .append('svg')
71
+ .classed('gridviz-legend-graphic', true)
72
+ .attr('width', w + 2 * sw)
73
+ .attr('height', h + 2 * sw)
74
+
75
+ .append('rect')
76
+ .classed('gridviz-legend-swatch', true)
77
+ .attr('x', sw)
78
+ .attr('y', sw)
79
+ .attr('width', w)
80
+ .attr('height', h)
81
+ .style('fill', cat[0])
82
+ .style('stroke', this.strokeColor)
83
+ .style('stroke-width', this.strokeWidth)
84
+ } else if (this.shape === 'circle') {
85
+ const r = this.dimension.r || 8
86
+ const h = 2 * r + 2 * sw
87
+ d.append('div')
88
+ .classed('gridviz-legend-symbol-wrapper', true)
89
+ .style('display', 'inline')
90
+
91
+ .append('svg')
92
+ .classed('gridviz-legend-graphic', true)
93
+ .attr('width', h)
94
+ .attr('height', h)
95
+
96
+ .append('circle')
97
+ .classed('gridviz-legend-swatch', true)
98
+ .attr('cx', r + sw)
99
+ .attr('cy', r + sw)
100
+ .attr('r', r)
101
+ .style('fill', cat[0])
102
+ .style('stroke', this.strokeColor)
103
+ .style('stroke-width', this.strokeWidth)
104
+ } else {
105
+ throw new Error('Unexpected shape:' + this.shape)
106
+ }
107
+
108
+ //write label text
109
+ this.setText(
110
+ d
111
+ .append('div')
112
+ //show on right of graphic
113
+ .style('display', 'inline')
114
+
115
+ //center vertically
116
+ //.style("position", "absolute").style("top", "0").style("bottom", "0")
117
+
118
+ .classed('gridviz-legend-label', true)
119
+ .style('padding-left', '5px')
120
+ .style('font-size', this.labelFontSizeCSS())
121
+ .style('fill', this.labelColorCSS())
122
+ .style('color', this.labelColorCSS()),
123
+ cat[1]
124
+ )
125
+ }
126
+ }
127
+ }
@@ -1,114 +1,116 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Legend } from '../core/Legend.js'
5
-
6
- /**
7
- * A legend element for discrete color style.
8
- * Inspiration: https://observablehq.com/@d3/color-legend
9
- *
10
- * @module legend
11
- * @author Julien Gaffuri
12
- */
13
- export class ColorDiscreteLegend extends Legend {
14
- /** @param {Object} opts */
15
- constructor(opts) {
16
- super(opts)
17
- opts = opts || {}
18
-
19
- /** @private @type {function(import('../core/Style').ViewScale):Array.<string>} */
20
- this.colors = opts.colors
21
- /** @private @type {function(import('../core/Style').ViewScale):Array.<number>} */
22
- this.breaks = opts.breaks
23
-
24
- // a number of pixels, or 'fill' for the width of the container
25
- this.width = opts.width === 'fill' ? 300 : opts.width || 300
26
- this.height = opts.height || 15
27
- this.setType('discrete')
28
-
29
- this.tickSize = opts.tickSize || 3
30
-
31
- //label
32
- this.invert = opts.invert
33
- }
34
-
35
- /**
36
- * @param {{viewScale:import('../core/Style').ViewScale} } opts
37
- */
38
- update(opts) {
39
- //clear
40
- this.div.selectAll('*').remove()
41
-
42
- //title
43
- this.makeTitle()
44
-
45
- //get colors and breaks
46
- const colors = this.colors(opts.viewScale)
47
- const breaks = this.breaks(opts.viewScale)
48
- if (!breaks) return
49
-
50
- //classes
51
- const nb = colors.length
52
- if (nb == 0) return
53
- const width = this.availableWidth(this.width)
54
- const w = width / nb
55
-
56
- //make svg element
57
- const svg = this.div
58
- .append('svg')
59
- .classed('gridviz-legend-graphic', true)
60
- .attr('width', width)
61
- .attr('height', this.height + this.tickSize + 2 + 10)
62
-
63
- //draw graphic elements
64
- for (let i = 0; i < nb; i++) {
65
- const rect = svg
66
- .append('rect')
67
- .classed('gridviz-legend-swatch', true)
68
- .attr('x', i * w)
69
- .attr('y', 0)
70
- .attr('width', w)
71
- .attr('height', this.height)
72
- .style('fill', colors[i])
73
- // hovering a class shows only its cells on the map
74
- this.bindHover(rect, colors[i], {
75
- // a presentation attribute, so that a stylesheet can restyle the active swatch
76
- enter: () => rect.classed('gridviz-legend-swatch--active', true).attr('stroke', 'red'),
77
- leave: () => rect.classed('gridviz-legend-swatch--active', false).attr('stroke', null),
78
- })
79
- }
80
-
81
- //tick line
82
- for (let i = 1; i < nb; i++) {
83
- svg.append('line')
84
- .classed('gridviz-legend-tick', true)
85
- .attr('x1', w * i)
86
- .attr('y1', 0)
87
- .attr('x2', w * i)
88
- .attr('y2', this.height + this.tickSize)
89
- .style('stroke', 'black')
90
- }
91
-
92
- //labels
93
- for (let i = 1; i < nb; i++) {
94
- let label = breaks[i - 1]
95
- if (isNaN(label) || label == undefined) continue
96
- if (this.labelFormat) label = this.labelFormat(label, i)
97
-
98
- //label
99
- svg.append('text')
100
- .classed('gridviz-legend-label', true)
101
- .attr('id', 'ticklabel_' + i)
102
- .attr('x', w * i)
103
- .attr('y', this.height + this.tickSize + 2)
104
- .style('font-size', this.labelFontSizeCSS())
105
- //.style("font-weight", "bold")
106
- //.style("font-family", "Arial")
107
- .style('text-anchor', 'middle')
108
- .style('alignment-baseline', 'top')
109
- .style('dominant-baseline', 'hanging')
110
- .style('pointer-events', 'none')
111
- .text(label)
112
- }
113
- }
114
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Legend } from '../core/Legend.js'
5
+
6
+ /**
7
+ * A legend element for discrete color style.
8
+ * Inspiration: https://observablehq.com/@d3/color-legend
9
+ *
10
+ * @module legend
11
+ * @author Julien Gaffuri
12
+ */
13
+ export class ColorDiscreteLegend extends Legend {
14
+ /** @param {Object} opts */
15
+ constructor(opts) {
16
+ super(opts)
17
+ opts = opts || {}
18
+
19
+ /** @private @type {function(import('../core/Style').ViewScale):Array.<string>} */
20
+ this.colors = opts.colors
21
+ /** @private @type {function(import('../core/Style').ViewScale):Array.<number>} */
22
+ this.breaks = opts.breaks
23
+
24
+ // a number of pixels, or 'fill' for the width of the container
25
+ this.width = opts.width === 'fill' ? 300 : opts.width || 300
26
+ this.height = opts.height || 15
27
+ this.setType('discrete')
28
+
29
+ this.tickSize = opts.tickSize || 3
30
+
31
+ //label
32
+ this.invert = opts.invert
33
+ }
34
+
35
+ /**
36
+ * @param {{viewScale:import('../core/Style').ViewScale} } opts
37
+ */
38
+ update(opts) {
39
+ //clear
40
+ this.div.selectAll('*').remove()
41
+
42
+ //title
43
+ this.makeTitle()
44
+
45
+ //get colors and breaks
46
+ const colors = this.colors(opts.viewScale)
47
+ const breaks = this.breaks(opts.viewScale)
48
+ if (!breaks) return
49
+
50
+ //classes
51
+ const nb = colors.length
52
+ if (nb == 0) return
53
+ const width = this.availableWidth(this.width)
54
+ const w = width / nb
55
+
56
+ //make svg element
57
+ const svg = this.div
58
+ .append('svg')
59
+ .classed('gridviz-legend-graphic', true)
60
+ .attr('width', width)
61
+ .attr('height', this.height + this.tickSize + 2 + 10)
62
+
63
+ //draw graphic elements
64
+ for (let i = 0; i < nb; i++) {
65
+ const rect = svg
66
+ .append('rect')
67
+ .classed('gridviz-legend-swatch', true)
68
+ .attr('x', i * w)
69
+ .attr('y', 0)
70
+ .attr('width', w)
71
+ .attr('height', this.height)
72
+ .style('fill', colors[i])
73
+ // hovering a class shows only its cells on the map
74
+ this.bindHover(rect, colors[i], {
75
+ // a presentation attribute, so that a stylesheet can restyle the active swatch
76
+ enter: () => rect.classed('gridviz-legend-swatch--active', true).attr('stroke', 'red'),
77
+ leave: () => rect.classed('gridviz-legend-swatch--active', false).attr('stroke', null),
78
+ })
79
+ }
80
+
81
+ //tick line
82
+ for (let i = 1; i < nb; i++) {
83
+ svg.append('line')
84
+ .classed('gridviz-legend-tick', true)
85
+ .attr('x1', w * i)
86
+ .attr('y1', 0)
87
+ .attr('x2', w * i)
88
+ .attr('y2', this.height + this.tickSize)
89
+ .style('stroke', 'black')
90
+ }
91
+
92
+ //labels
93
+ for (let i = 1; i < nb; i++) {
94
+ let label = breaks[i - 1]
95
+ if (isNaN(label) || label == undefined) continue
96
+ if (this.labelFormat) label = this.labelFormat(label, i)
97
+
98
+ //label
99
+ svg.append('text')
100
+ .classed('gridviz-legend-label', true)
101
+ .attr('id', 'ticklabel_' + i)
102
+ .attr('x', w * i)
103
+ .attr('y', this.height + this.tickSize + 2)
104
+ .style('font-size', this.labelFontSizeCSS())
105
+ .style('fill', this.labelColorCSS())
106
+ .style('color', this.labelColorCSS())
107
+ //.style("font-weight", "bold")
108
+ //.style("font-family", "Arial")
109
+ .style('text-anchor', 'middle')
110
+ .style('alignment-baseline', 'top')
111
+ .style('dominant-baseline', 'hanging')
112
+ .style('pointer-events', 'none')
113
+ .text(label)
114
+ }
115
+ }
116
+ }
@@ -26,21 +26,39 @@ export class ColorLegend extends Legend {
26
26
 
27
27
  this.margin = opts.margin || 5
28
28
 
29
+ // a number of pixels, or 'fill' for the width of the container
30
+ this.width = opts.width === 'fill' ? 300 : opts.width || 300
31
+ this.height = opts.height || 15
32
+
29
33
  //replace with labels ?
30
34
  this.tickSize = opts.tickSize || 6
31
- this.ticks = opts.ticks || Math.floor(this.width / 50)
35
+ /** The number of ticks. By default one for each 50 pixels of the width the legend is drawn at, at least 2.
36
+ * @type {number} */
37
+ this.ticks = opts.ticks || Math.max(2, Math.floor(this.width / 50))
38
+ /** The default number of ticks, when no number is given: it follows the width the legend is drawn at (@see update)
39
+ * @private */
40
+ this._defaultTicks = opts.ticks ? undefined : this.ticks
32
41
  this.tickFormat = opts.tickFormat
33
42
  this.tickUnit = opts.tickUnit
34
43
 
35
- this.fontSize = opts.fontSize || '0.8em'
44
+ /** The font size of the tick labels. By default, the one of the legend labels (labelFontSize).
45
+ * @type {string|undefined} */
46
+ this.fontSize = opts.fontSize
36
47
  this.invert = opts.invert
37
48
 
38
- // a number of pixels, or 'fill' for the width of the container
39
- this.width = opts.width === 'fill' ? 300 : opts.width || 300
40
- this.height = opts.height || 15
41
49
  this.setType('color')
42
50
  }
43
51
 
52
+ /**
53
+ * The number of ticks of the bar, for a width of it: the one given, or one for each 50 pixels (at least two: the two ends).
54
+ * @param {number} width The width the bar is drawn at, in pixels.
55
+ * @returns {number}
56
+ */
57
+ tickCount(width) {
58
+ if (this._defaultTicks !== undefined && this.ticks === this._defaultTicks) return Math.max(2, Math.floor(width / 50))
59
+ return Math.max(2, this.ticks)
60
+ }
61
+
44
62
  /**
45
63
  * @param {{viewScale:import('../core/Style').ViewScale} } opts
46
64
  */
@@ -52,6 +70,9 @@ export class ColorLegend extends Legend {
52
70
  this.makeTitle()
53
71
 
54
72
  const width = this.availableWidth(this.width)
73
+ // without a given number of ticks: one for each 50 pixels of the width the legend is drawn at (the one of its container
74
+ // with width:'fill'). At least two: the two ends.
75
+ const nbTicks = this.tickCount(width)
55
76
  const svgW = width + 2 * this.margin
56
77
  const svgH = this.height + this.margin + this.tickSize + 10
57
78
  const svg = this.div.append('svg').classed('gridviz-legend-graphic', true).attr('width', svgW).attr('height', svgH)
@@ -75,8 +96,8 @@ export class ColorLegend extends Legend {
75
96
  .style('fill', this.colorScale(t, opts.viewScale))
76
97
  }
77
98
 
78
- for (let i = 0; i < this.ticks; i++) {
79
- let t = i / (this.ticks - 1)
99
+ for (let i = 0; i < nbTicks; i++) {
100
+ let t = i / (nbTicks - 1)
80
101
 
81
102
  //tick line
82
103
  g.append('line')
@@ -93,10 +114,11 @@ export class ColorLegend extends Legend {
93
114
  .attr('id', 'ticklabel_' + i)
94
115
  .attr('x', w * t)
95
116
  .attr('y', h + this.tickSize + 2)
96
- .style('font-size', this.fontSize)
117
+ .style('font-size', this.fontSize || this.labelFontSizeCSS())
118
+ .style('fill', this.labelColorCSS())
97
119
  //.style("font-weight", "bold")
98
120
  //.style("font-family", "Arial")
99
- .style('text-anchor', i == 0 ? 'start' : i == this.ticks - 1 ? 'end' : 'middle')
121
+ .style('text-anchor', i == 0 ? 'start' : i == nbTicks - 1 ? 'end' : 'middle')
100
122
  .style('alignment-baseline', 'top')
101
123
  .style('dominant-baseline', 'hanging')
102
124
  .style('pointer-events', 'none')
@@ -107,8 +129,8 @@ export class ColorLegend extends Legend {
107
129
 
108
130
  //label text format
109
131
  const f = this.tickFormat && this.tickFormat != 'text' ? this.tickFormat : (v) => v
110
- for (let i = 0; i < this.ticks; i++) {
111
- let t = i / (this.ticks - 1)
132
+ for (let i = 0; i < nbTicks; i++) {
133
+ let t = i / (nbTicks - 1)
112
134
 
113
135
  const v = this.textScale(t, opts.viewScale)
114
136
  const text = (v ? f(v) : '0') + (this.tickUnit ? this.tickUnit : '')