gridviz 2.1.14 → 2.1.16
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.
- package/dist/gridviz.js +721 -169
- package/dist/gridviz.min.js +1 -1
- package/package.json +1 -1
- package/src/App.js +17 -15
- package/src/Tooltip.js +11 -9
- package/src/button/Button.js +36 -24
- package/src/button/FullscreenButton.js +26 -4
- package/src/button/ZoomButtons.js +50 -27
- package/src/index.js +2 -0
- package/src/style/CompositionStyle_.js +293 -0
- package/src/style/ShapeColorSizeStyle_.js +108 -0
- package/src/utils/stretching.js +59 -18
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../Style.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A very generic style that shows grid cells with specific color, size and shape.
|
|
8
|
+
* It can be used to show variables as cell colors, cell size, cell shape, or any combination of the three visual variables.
|
|
9
|
+
*
|
|
10
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
11
|
+
*/
|
|
12
|
+
export class ShapeColorSizeStyle_ extends Style {
|
|
13
|
+
/** @param {object} opts */
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super(opts)
|
|
16
|
+
opts = opts || {}
|
|
17
|
+
|
|
18
|
+
/** A function returning the view scale.
|
|
19
|
+
* @type {function(Array.<import('../Dataset.js').Cell>,number, number):object} */
|
|
20
|
+
this.viewScale = opts.viewScale //(cells,r,z) => {}
|
|
21
|
+
|
|
22
|
+
/** A function returning the color of the cell.
|
|
23
|
+
* @type {function(import('../Dataset.js').Cell,number, number,object):string} */
|
|
24
|
+
this.color = opts.color //(c,r,z,o) => {}
|
|
25
|
+
|
|
26
|
+
/** A function returning the size of a cell in geographical unit.
|
|
27
|
+
* @type {function(import('../Dataset.js').Cell,number, number,object):number} */
|
|
28
|
+
this.size = opts.size //(c,r,z,o) => {}
|
|
29
|
+
|
|
30
|
+
/** A function returning the shape of a cell.
|
|
31
|
+
* @type {function(import("../Dataset.js").Cell,number, number,object):import("../Style.js").Shape} */
|
|
32
|
+
this.shape = opts.shape //(c,r,z,o) => {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Draw cells as squares, with various colors and sizes.
|
|
37
|
+
*
|
|
38
|
+
* @param {Array.<import("../Dataset.js").Cell>} cells
|
|
39
|
+
* @param {number} r
|
|
40
|
+
* @param {import("../GeoCanvas.js").GeoCanvas} cg
|
|
41
|
+
*/
|
|
42
|
+
draw(cells, r, cg) {
|
|
43
|
+
//filter
|
|
44
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
45
|
+
|
|
46
|
+
//zoom factor
|
|
47
|
+
const zf = cg.getZf()
|
|
48
|
+
|
|
49
|
+
//get view scale
|
|
50
|
+
const vc = this.viewScale ? this.viewScale(cells, r, zf) : undefined
|
|
51
|
+
|
|
52
|
+
//draw with HTML canvas in geo coordinates
|
|
53
|
+
cg.setCanvasTransform()
|
|
54
|
+
|
|
55
|
+
const r2 = r * 0.5
|
|
56
|
+
for (let c of cells) {
|
|
57
|
+
//color
|
|
58
|
+
let col = this.color ? this.color(c, r, zf, vc) : "black"
|
|
59
|
+
if (!col || col === 'none') continue
|
|
60
|
+
|
|
61
|
+
//size
|
|
62
|
+
const size = this.size ? this.size(c, r, zf, vc) : r
|
|
63
|
+
if (!size) continue
|
|
64
|
+
|
|
65
|
+
//shape
|
|
66
|
+
const shape = this.shape ? this.shape(c, r, zf, vc) : 'square'
|
|
67
|
+
if (shape === 'none') continue
|
|
68
|
+
|
|
69
|
+
//get offset
|
|
70
|
+
const offset = this.offset(c, r, zf)
|
|
71
|
+
|
|
72
|
+
cg.ctx.fillStyle = col
|
|
73
|
+
if (shape === 'square') {
|
|
74
|
+
//draw square
|
|
75
|
+
const d = r * (1 - size / r) * 0.5
|
|
76
|
+
cg.ctx.fillRect(c.x + d + offset.dx, c.y + d + offset.dy, size, size)
|
|
77
|
+
} else if (shape === 'circle') {
|
|
78
|
+
//draw circle
|
|
79
|
+
cg.ctx.beginPath()
|
|
80
|
+
cg.ctx.arc(c.x + r2 + offset.dx, c.y + r2 + offset.dy, size * 0.5, 0, 2 * Math.PI, false)
|
|
81
|
+
cg.ctx.fill()
|
|
82
|
+
} else if (shape === 'donut') {
|
|
83
|
+
//draw donut
|
|
84
|
+
const xc = c.x + r2 + offset.dx,
|
|
85
|
+
yc = c.y + r2 + offset.dy
|
|
86
|
+
cg.ctx.beginPath()
|
|
87
|
+
cg.ctx.moveTo(xc, yc)
|
|
88
|
+
cg.ctx.arc(xc, yc, r2, 0, 2 * Math.PI)
|
|
89
|
+
cg.ctx.arc(xc, yc, (1 - size / r) * r2, 0, 2 * Math.PI, true)
|
|
90
|
+
cg.ctx.closePath()
|
|
91
|
+
cg.ctx.fill()
|
|
92
|
+
} else if (shape === 'diamond') {
|
|
93
|
+
const s2 = size * 0.5
|
|
94
|
+
cg.ctx.beginPath()
|
|
95
|
+
cg.ctx.moveTo(c.x + r2 - s2, c.y + r2)
|
|
96
|
+
cg.ctx.lineTo(c.x + r2, c.y + r2 + s2)
|
|
97
|
+
cg.ctx.lineTo(c.x + r2 + s2, c.y + r2)
|
|
98
|
+
cg.ctx.lineTo(c.x + r2, c.y + r2 - s2)
|
|
99
|
+
cg.ctx.fill()
|
|
100
|
+
} else {
|
|
101
|
+
throw new Error('Unexpected shape:' + shape)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//update legends
|
|
106
|
+
this.updateLegends({ style: this, r: r, zf: zf, viewScale: vc })
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/utils/stretching.js
CHANGED
|
@@ -1,52 +1,89 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
/**
|
|
5
6
|
* Some function [0,1]->[0,1] to stretch range of values.
|
|
6
7
|
* @see https://github.com/eurostat/gridviz/blob/master/docs/reference.md#stretching
|
|
7
8
|
* @see https://observablehq.com/@jgaffuri/stretching
|
|
8
9
|
*/
|
|
9
10
|
|
|
11
|
+
|
|
12
|
+
export const powerScale = (exponent = 3) => t => Math.pow(t, exponent)
|
|
13
|
+
export const powerInverseScale = (exponent = 3) => t => 1 - Math.pow(1 - t, 1 / exponent)
|
|
14
|
+
export const exponentialScale = (base = 3) => {
|
|
15
|
+
if (base == 0) return t => t
|
|
16
|
+
const a = (Math.exp(base) - 1)
|
|
17
|
+
return t => (Math.exp(t * base) - 1) / a
|
|
18
|
+
}
|
|
19
|
+
export const logarithmicScale = (base = 3) => {
|
|
20
|
+
if (base == 0) return t => t
|
|
21
|
+
return t => 1 - (1 / base) * Math.log(Math.exp(base) * (1 - t) + t)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const circularScale = (alpha = 0.8) => {
|
|
25
|
+
if (alpha == 0) return t => t
|
|
26
|
+
if (alpha == 1) return t => Math.sqrt(t * (2 - t))
|
|
27
|
+
else {
|
|
28
|
+
const a = alpha / (1 - alpha)
|
|
29
|
+
return t => Math.sqrt(1 / (a * a) + t * (2 / a + 2 - t)) - 1 / a
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export const circularInverseScale = (alpha = 0.8) => {
|
|
33
|
+
const f = circularScale(alpha)
|
|
34
|
+
return t => 1 - f(1 - t)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// deprecated
|
|
45
|
+
|
|
46
|
+
|
|
10
47
|
/**
|
|
11
48
|
* Function [0,1]->[0,1] to stretch range of values.
|
|
12
49
|
* Polynomial
|
|
13
50
|
*
|
|
14
51
|
* @param {number} t The value to stretch, within [0,1]
|
|
15
|
-
* @param {number}
|
|
52
|
+
* @param {number} exponent 1: no stretching. <1: show low values. >1: show high values.
|
|
16
53
|
* @returns {number} The stretched value, within [0,1]
|
|
17
54
|
*/
|
|
18
|
-
export const sPow = (t,
|
|
55
|
+
export const sPow = (t, exponent = 3) => Math.pow(t, exponent)
|
|
19
56
|
|
|
20
57
|
/**
|
|
21
58
|
* Function [0,1]->[0,1] to stretch range of values.
|
|
22
59
|
* Polynomial (reverse)
|
|
23
60
|
*
|
|
24
61
|
* @param {number} t The value to stretch, within [0,1]
|
|
25
|
-
* @param {number}
|
|
62
|
+
* @param {number} exponent 1: no stretching. <1: show low values. >1: show high values.
|
|
26
63
|
* @returns {number} The stretched value, within [0,1]
|
|
27
64
|
*/
|
|
28
|
-
export const sPowRev = (t,
|
|
65
|
+
export const sPowRev = (t, exponent = 3) => 1 - Math.pow(1 - t, 1 / exponent)
|
|
29
66
|
|
|
30
67
|
/**
|
|
31
68
|
* Function [0,1]->[0,1] to stretch range of values.
|
|
32
69
|
* Exponential
|
|
33
70
|
*
|
|
34
71
|
* @param {number} t The value to stretch, within [0,1]
|
|
35
|
-
* @param {number}
|
|
72
|
+
* @param {number} base 0: no stretching. -Inf: show low values. Inf: show high values.
|
|
36
73
|
* @returns {number} The stretched value, within [0,1]
|
|
37
74
|
*/
|
|
38
|
-
export const sExp = (t,
|
|
75
|
+
export const sExp = (t, base = 3) => (base == 0 ? t : (Math.exp(t * base) - 1) / (Math.exp(base) - 1))
|
|
39
76
|
|
|
40
77
|
/**
|
|
41
78
|
* Function [0,1]->[0,1] to stretch range of values.
|
|
42
79
|
* Exponential (reverse)
|
|
43
80
|
*
|
|
44
81
|
* @param {number} t The value to stretch, within [0,1]
|
|
45
|
-
* @param {number}
|
|
82
|
+
* @param {number} base 0: no stretching. -Inf: show low values. Inf: show high values.
|
|
46
83
|
* @returns {number} The stretched value, within [0,1]
|
|
47
84
|
*/
|
|
48
|
-
export const sExpRev = (t,
|
|
49
|
-
|
|
85
|
+
export const sExpRev = (t, base = 3) =>
|
|
86
|
+
base == 0 ? t : 1 - (1 / base) * Math.log(Math.exp(base) * (1 - t) + t)
|
|
50
87
|
|
|
51
88
|
/**
|
|
52
89
|
* Function [0,1]->[0,1] to stretch range of values.
|
|
@@ -82,36 +119,40 @@ export const sCircleHigh = (t, alpha = 0.8) => 1 - sCircleLow(1 - t, alpha)
|
|
|
82
119
|
/**
|
|
83
120
|
* Inverse function of sExp
|
|
84
121
|
* @param {number} y
|
|
85
|
-
* @param {number}
|
|
122
|
+
* @param {number} base
|
|
86
123
|
* @returns {number}
|
|
87
124
|
*/
|
|
88
|
-
export const sExpInverse = (y,
|
|
89
|
-
|
|
125
|
+
export const sExpInverse = (y, base = 3) =>
|
|
126
|
+
base == 0 ? y : (1 / base) * Math.log(1 - y + y * Math.exp(base))
|
|
90
127
|
|
|
91
128
|
/**
|
|
92
129
|
* Inverse function of sExpRev
|
|
93
130
|
* @param {number} y
|
|
94
|
-
* @param {number}
|
|
131
|
+
* @param {number} base
|
|
95
132
|
* @returns {number}
|
|
96
133
|
*/
|
|
97
|
-
export const sExpRevInverse = (y,
|
|
134
|
+
export const sExpRevInverse = (y, base = 3) => (Math.exp(-base * y) - 1) / (Math.exp(-base) - 1)
|
|
98
135
|
|
|
99
136
|
/**
|
|
100
137
|
* Inverse function of sPow
|
|
101
138
|
* @param {number} y
|
|
102
|
-
* @param {number}
|
|
139
|
+
* @param {number} exponent
|
|
103
140
|
* @returns {number}
|
|
104
141
|
*/
|
|
105
142
|
|
|
106
|
-
export const sPowInverse = (y,
|
|
143
|
+
export const sPowInverse = (y, exponent = 3) => Math.pow(y, 1 / exponent)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
107
148
|
|
|
108
149
|
/**
|
|
109
150
|
* Inverse function of sPowRev
|
|
110
151
|
* @param {number} y
|
|
111
|
-
* @param {number}
|
|
152
|
+
* @param {number} exponent
|
|
112
153
|
* @returns {number}
|
|
113
154
|
*/
|
|
114
|
-
export const sPowRevInverse = (y,
|
|
155
|
+
export const sPowRevInverse = (y, exponent = 3) => 1 - Math.pow(1 - y, exponent)
|
|
115
156
|
|
|
116
157
|
//test code
|
|
117
158
|
/*
|