gridviz 2.0.46 → 2.0.48
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 +682 -446
- package/dist/gridviz.min.js +1 -1
- package/package.json +4 -2
- package/src/index.js +1 -0
- package/src/style/NinjaStarStyle.js +2 -1
- package/src/style/TimeSeriesStyle.js +207 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gridviz",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.48",
|
|
4
4
|
"description": "Visualization tool for gridded statistics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"statistics",
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"WebGL",
|
|
15
15
|
"d3",
|
|
16
16
|
"cartography",
|
|
17
|
-
"bertin"
|
|
17
|
+
"bertin",
|
|
18
|
+
"geospatial",
|
|
19
|
+
"mapping"
|
|
18
20
|
],
|
|
19
21
|
"homepage": "https://github.com/eurostat/gridviz",
|
|
20
22
|
"author": "Joseph Davies, Julien Gaffuri",
|
package/src/index.js
CHANGED
|
@@ -33,6 +33,7 @@ export { SquareColorWGLStyle } from './style/SquareColorWGLStyle.js'
|
|
|
33
33
|
export { SquareColorCatWGLStyle } from './style/SquareColorCatWGLStyle.js'
|
|
34
34
|
export { MosaicStyle } from './style/MosaicStyle.js'
|
|
35
35
|
export { NinjaStarStyle } from './style/NinjaStarStyle.js'
|
|
36
|
+
export { TimeSeriesStyle } from './style/TimeSeriesStyle.js'
|
|
36
37
|
|
|
37
38
|
// export additional layers
|
|
38
39
|
export { BackgroundLayer } from './BackgroundLayer.js'
|
|
@@ -85,7 +85,8 @@ export class NinjaStarStyle extends Style {
|
|
|
85
85
|
const sG2 = s_(cell[this.sizeCol], r, statSize, zf) * r2
|
|
86
86
|
|
|
87
87
|
//get offset
|
|
88
|
-
|
|
88
|
+
//TODO use
|
|
89
|
+
//const offset = this.offset(cell, r, zf)
|
|
89
90
|
|
|
90
91
|
//center position
|
|
91
92
|
const cx = cell.x + r2
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../Style.js'
|
|
5
|
+
|
|
6
|
+
/** @typedef {"first"|"bottom"|"center"|"top"|"last"} AnchorModeYEnum */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Show cell as timeseries chart
|
|
10
|
+
* Can be used for sparkline map of https://datagistips.hypotheses.org/488
|
|
11
|
+
*
|
|
12
|
+
* @author Julien Gaffuri
|
|
13
|
+
*/
|
|
14
|
+
export class TimeSeriesStyle extends Style {
|
|
15
|
+
/** @param {object} opts */
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
super(opts)
|
|
18
|
+
opts = opts || {}
|
|
19
|
+
|
|
20
|
+
/** The columns of the time series, ordered in chronological order.
|
|
21
|
+
* @type {Array.<string>} */
|
|
22
|
+
this.ts = opts.ts
|
|
23
|
+
|
|
24
|
+
//x
|
|
25
|
+
/** in geo unit
|
|
26
|
+
* @type {function(import("../Dataset.js").Cell,number,number):number} */
|
|
27
|
+
this.offsetX = opts.offsetX || ((c, r, zf) => 0)
|
|
28
|
+
/** @type {function(import("../Dataset.js").Cell,number,number):number} */
|
|
29
|
+
this.width = opts.width || ((c, r, zf) => r)
|
|
30
|
+
|
|
31
|
+
//y
|
|
32
|
+
/** in geo unit
|
|
33
|
+
* @type {function(import("../Dataset.js").Cell,number,number):number} */
|
|
34
|
+
this.offsetY = opts.offsetY || ((c, r, zf) => 0)
|
|
35
|
+
/** @type {function(import("../Dataset.js").Cell,number,number):number} */
|
|
36
|
+
this.height = opts.height || ((c, r, zf) => r)
|
|
37
|
+
/** @type {function(import("../Dataset.js").Cell,number,number):AnchorModeYEnum} */
|
|
38
|
+
this.anchorModeY = opts.anchorModeY || ((c, r, zf) => "center")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @type {string} */
|
|
43
|
+
this.lineWidthCol = opts.lineWidthCol
|
|
44
|
+
|
|
45
|
+
/** A function returning the width of the line, in geo unit
|
|
46
|
+
* @type {function(number,number,import("../Style.js").Stat|undefined,number):number} */
|
|
47
|
+
this.lineWidth = opts.lineWidth || ((v, r, s, zf) => 1.5 * zf)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @type {string} */
|
|
52
|
+
this.colorCol = opts.colorCol
|
|
53
|
+
|
|
54
|
+
/** A function returning the color of the cell.
|
|
55
|
+
* @type {function(number,number,import("../Style.js").Stat|undefined,number):string} */
|
|
56
|
+
this.color = opts.color || ((v, r, s, zf) => 'black')
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Draw cells as text.
|
|
62
|
+
*
|
|
63
|
+
* @param {Array.<import("../Dataset.js").Cell>} cells
|
|
64
|
+
* @param {number} r
|
|
65
|
+
* @param {import("../GeoCanvas.js").GeoCanvas} cg
|
|
66
|
+
*/
|
|
67
|
+
draw(cells, r, cg) {
|
|
68
|
+
|
|
69
|
+
//filter
|
|
70
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
71
|
+
|
|
72
|
+
//zoom factor
|
|
73
|
+
const zf = cg.getZf()
|
|
74
|
+
|
|
75
|
+
let statWidth
|
|
76
|
+
if (this.lineWidthCol) {
|
|
77
|
+
//and compute size variable statistics
|
|
78
|
+
statWidth = Style.getStatistics(cells, (c) => c[this.lineWidthCol], true)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let statColor
|
|
82
|
+
if (this.colorCol) {
|
|
83
|
+
//compute color variable statistics
|
|
84
|
+
statColor = Style.getStatistics(cells, (c) => c[this.colorCol], true)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//compute cell amplitude
|
|
88
|
+
const getAmplitude = c => {
|
|
89
|
+
let min, max
|
|
90
|
+
for (let t of this.ts) {
|
|
91
|
+
const val = c[t];
|
|
92
|
+
if (val == undefined) continue
|
|
93
|
+
if (min == undefined || val < min) min = val
|
|
94
|
+
if (max == undefined || val > max) max = val
|
|
95
|
+
}
|
|
96
|
+
if (min == undefined) return undefined
|
|
97
|
+
return max - min
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//compute max amplitude
|
|
101
|
+
let ampMax
|
|
102
|
+
for (let c of cells) {
|
|
103
|
+
const amp = getAmplitude(c)
|
|
104
|
+
if (amp == undefined) continue
|
|
105
|
+
if (ampMax == undefined || amp > ampMax) ampMax = amp
|
|
106
|
+
}
|
|
107
|
+
if (!ampMax) return
|
|
108
|
+
|
|
109
|
+
const nb = this.ts.length
|
|
110
|
+
|
|
111
|
+
//draw with HTML canvas
|
|
112
|
+
//in geo coordinates
|
|
113
|
+
cg.setCanvasTransform()
|
|
114
|
+
|
|
115
|
+
cg.ctx.lineCap = 'butt'
|
|
116
|
+
for (let c of cells) {
|
|
117
|
+
|
|
118
|
+
//line width
|
|
119
|
+
/** @type {number|undefined} */
|
|
120
|
+
const wG = this.lineWidth ? this.lineWidth(c[this.lineWidthCol], r, statWidth, zf) : undefined
|
|
121
|
+
if (!wG || wG < 0) continue
|
|
122
|
+
|
|
123
|
+
//line color
|
|
124
|
+
/** @type {string|undefined} */
|
|
125
|
+
const col = this.color ? this.color(c[this.colorCol], r, statColor, zf) : undefined
|
|
126
|
+
if (!col) continue
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
//x
|
|
130
|
+
const offX = this.offsetX ? this.offsetX(c, r, zf) : 0
|
|
131
|
+
if (offX == undefined || isNaN(offX)) continue
|
|
132
|
+
const w = this.width ? this.width(c, r, zf) : r
|
|
133
|
+
if (w == undefined || isNaN(w)) continue
|
|
134
|
+
|
|
135
|
+
//y
|
|
136
|
+
const offY = this.offsetY ? this.offsetY(c, r, zf) : 0
|
|
137
|
+
if (offY == undefined || isNaN(offY)) continue
|
|
138
|
+
const h = this.height ? this.height(c, r, zf) : r
|
|
139
|
+
if (h == undefined || isNaN(h)) continue
|
|
140
|
+
const anchY = this.anchorModeY ? this.anchorModeY(c, r, zf) : "center"
|
|
141
|
+
if (!anchY) continue
|
|
142
|
+
|
|
143
|
+
cg.ctx.lineWidth = wG
|
|
144
|
+
cg.ctx.strokeStyle = col
|
|
145
|
+
|
|
146
|
+
//compute anchor Y figures
|
|
147
|
+
let val0, y0
|
|
148
|
+
if (anchY === "first") {
|
|
149
|
+
//get first value
|
|
150
|
+
val0 = c[this.ts[0]]
|
|
151
|
+
y0 = 0
|
|
152
|
+
} else if (anchY === "last") {
|
|
153
|
+
//get last value
|
|
154
|
+
val0 = c[this.ts[this.ts.length - 1]]
|
|
155
|
+
y0 = 0
|
|
156
|
+
} else if (anchY === "bottom") {
|
|
157
|
+
//get min
|
|
158
|
+
for (let t of this.ts) {
|
|
159
|
+
const val = +c[t];
|
|
160
|
+
if (val == undefined) continue
|
|
161
|
+
if (val0 == undefined || val < val0) val0 = val
|
|
162
|
+
}
|
|
163
|
+
y0 = 0
|
|
164
|
+
} else if (anchY === "top") {
|
|
165
|
+
//get max
|
|
166
|
+
for (let t of this.ts) {
|
|
167
|
+
const val = +c[t];
|
|
168
|
+
if (val == undefined) continue
|
|
169
|
+
if (val0 == undefined || val > val0) val0 = val
|
|
170
|
+
}
|
|
171
|
+
y0 = r
|
|
172
|
+
} else if (anchY === "center") {
|
|
173
|
+
//get min and max
|
|
174
|
+
let min, max
|
|
175
|
+
for (let t of this.ts) {
|
|
176
|
+
const val = c[t];
|
|
177
|
+
if (val == undefined) continue
|
|
178
|
+
if (min == undefined || val < min) min = val
|
|
179
|
+
if (max == undefined || val > max) max = val
|
|
180
|
+
}
|
|
181
|
+
val0 = (+max + +min) * 0.5
|
|
182
|
+
y0 = r / 2
|
|
183
|
+
} else {
|
|
184
|
+
console.log("Unexpected anchorModeY: " + anchY)
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (val0 == undefined || isNaN(val0)) continue
|
|
189
|
+
|
|
190
|
+
//draw line
|
|
191
|
+
cg.ctx.beginPath()
|
|
192
|
+
const sX = w / (nb - 1)
|
|
193
|
+
for (let i = 0; i < nb; i++) {
|
|
194
|
+
const val = c[this.ts[i]]
|
|
195
|
+
if (val == undefined) break
|
|
196
|
+
if (i == 0)
|
|
197
|
+
cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
|
|
198
|
+
else
|
|
199
|
+
cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
cg.ctx.stroke()
|
|
203
|
+
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
}
|