gridviz 2.0.51 → 2.1.0
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/README.md +1 -0
- package/dist/gridviz.js +317 -2407
- package/dist/gridviz.min.js +1 -1
- package/package.json +1 -2
- package/src/App.js +16 -0
- package/src/dataset/LGrid.js +54 -0
- package/src/index.js +1 -109
- package/src/style/TimeSeriesStyle.js +48 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gridviz",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Visualization tool for gridded statistics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"statistics",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"d3-color": "^3.1.0",
|
|
53
53
|
"d3-fetch": "^3.0.1",
|
|
54
54
|
"d3-format": "^3.1.0",
|
|
55
|
-
"d3-geo": "^3.0.1",
|
|
56
55
|
"d3-random": "^3.0.1",
|
|
57
56
|
"d3-selection": "^3.0.0",
|
|
58
57
|
"d3-zoom": "^3.0.0"
|
package/src/App.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Layer } from './Layer.js'
|
|
|
7
7
|
import { Dataset } from './Dataset.js'
|
|
8
8
|
import { Tooltip } from './Tooltip.js'
|
|
9
9
|
import { CSVGrid } from './dataset/CSVGrid.js'
|
|
10
|
+
import { LGrid } from './dataset/LGrid.js'
|
|
10
11
|
import { TiledGrid } from './dataset/TiledGrid.js'
|
|
11
12
|
import { BackgroundLayer } from './BackgroundLayer.js'
|
|
12
13
|
import { BackgroundLayerWMS } from './BackgroundLayerWMS.js'
|
|
@@ -448,6 +449,21 @@ export class App {
|
|
|
448
449
|
|
|
449
450
|
//dataset creation
|
|
450
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Make a local grid dataset.
|
|
454
|
+
*
|
|
455
|
+
* @param {number} resolution The dataset resolution in geographical unit.
|
|
456
|
+
* @param {Array} cells The cells.
|
|
457
|
+
* @param {object=} opts The parameters of the dataset.
|
|
458
|
+
* @returns {Dataset}
|
|
459
|
+
*/
|
|
460
|
+
makeLGridDataset(resolution, cells, opts) {
|
|
461
|
+
return new Dataset([new LGrid(resolution, cells),],
|
|
462
|
+
[],
|
|
463
|
+
opts
|
|
464
|
+
)
|
|
465
|
+
}
|
|
466
|
+
|
|
451
467
|
/**
|
|
452
468
|
* Make a CSV grid dataset.
|
|
453
469
|
*
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/** @typedef {{ dims: object, crs: string, tileSizeCell: number, originPoint: {x:number,y:number}, resolutionGeo: number, tilingBounds:import("../Dataset.js").Envelope }} GridInfo */
|
|
5
|
+
|
|
6
|
+
import { DatasetComponent } from '../DatasetComponent.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A dataset composed of a single CSV file (not tiled).
|
|
10
|
+
*
|
|
11
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
12
|
+
*/
|
|
13
|
+
export class LGrid extends DatasetComponent {
|
|
14
|
+
/**
|
|
15
|
+
* @param {number} resolution The dataset resolution in geographical unit.
|
|
16
|
+
* @param {Array.<Object>} cells The cells.
|
|
17
|
+
*/
|
|
18
|
+
constructor(resolution, cells) {
|
|
19
|
+
super("", resolution)
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @private
|
|
23
|
+
* @type {Array.<import("../Dataset.js").Cell>} */
|
|
24
|
+
this.cells = cells || []
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Request data within a geographic envelope.
|
|
29
|
+
*
|
|
30
|
+
* @param {import("../Dataset.js").Envelope|undefined} e
|
|
31
|
+
* @param {function():void} redraw
|
|
32
|
+
*/
|
|
33
|
+
getData(e, redraw) { return this }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Fill the view cache with all cells which are within a geographical envelope.
|
|
37
|
+
*
|
|
38
|
+
* @param {import("../Dataset.js").Envelope} extGeo
|
|
39
|
+
* @returns {void}
|
|
40
|
+
*/
|
|
41
|
+
updateViewCache(extGeo) {
|
|
42
|
+
//data not loaded yet
|
|
43
|
+
if (!this.cells) return
|
|
44
|
+
|
|
45
|
+
this.cellsViewCache = []
|
|
46
|
+
for (const cell of this.cells) {
|
|
47
|
+
if (+cell.x + this.resolution < extGeo.xMin) continue
|
|
48
|
+
if (+cell.x - this.resolution > extGeo.xMax) continue
|
|
49
|
+
if (+cell.y + this.resolution < extGeo.yMin) continue
|
|
50
|
+
if (+cell.y - this.resolution > extGeo.yMax) continue
|
|
51
|
+
this.cellsViewCache.push(cell)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { DatasetComponent } from './DatasetComponent.js'
|
|
|
13
13
|
export { TiledGrid } from './dataset/TiledGrid.js'
|
|
14
14
|
export { GridTile } from './dataset/GridTile.js'
|
|
15
15
|
export { CSVGrid } from './dataset/CSVGrid.js'
|
|
16
|
+
export { LGrid } from './dataset/LGrid.js'
|
|
16
17
|
//export { GeoTIFF } from "./dataset/GeoTIFF"
|
|
17
18
|
|
|
18
19
|
// export styles
|
|
@@ -56,116 +57,7 @@ export { getClass } from './utils/Utils.js'
|
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
|
|
60
60
|
import { GeoCanvas } from './GeoCanvas.js'
|
|
61
|
-
import { geoAzimuthalEqualArea } from 'd3-geo'
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Returns label layer from Eurostat, for ETRS89-LAEA grids.
|
|
65
|
-
* From Euronym data: https://github.com/eurostat/euronym
|
|
66
|
-
*
|
|
67
|
-
* @returns {object}
|
|
68
|
-
*/
|
|
69
|
-
export const getEuronymeLabelLayer = function (cc = 'EUR', res = 50, opts) {
|
|
70
|
-
opts = opts || {}
|
|
71
|
-
const ex = opts.ex || 1.2
|
|
72
|
-
const fontFamily = opts.fontFamily || 'Arial'
|
|
73
|
-
const exSize = opts.exSize || 1
|
|
74
|
-
opts.style =
|
|
75
|
-
opts.style ||
|
|
76
|
-
((lb, zf) => {
|
|
77
|
-
if (lb.rs < ex * zf) return
|
|
78
|
-
if (lb.r1 < ex * zf) return exSize + 'em ' + fontFamily
|
|
79
|
-
return exSize * 1.5 + 'em ' + fontFamily
|
|
80
|
-
})
|
|
81
|
-
//ETRS89-LAEA projection
|
|
82
|
-
opts.proj =
|
|
83
|
-
opts.proj ||
|
|
84
|
-
geoAzimuthalEqualArea()
|
|
85
|
-
.rotate([-10, -52])
|
|
86
|
-
.reflectX(false)
|
|
87
|
-
.reflectY(true)
|
|
88
|
-
.scale(6378137)
|
|
89
|
-
.translate([4321000, 3210000])
|
|
90
|
-
opts.preprocess = (lb) => {
|
|
91
|
-
//exclude countries
|
|
92
|
-
//if(opts.ccOut && lb.cc && opts.ccOut.includes(lb.cc)) return false;
|
|
93
|
-
if (opts.ccIn && lb.cc && !(opts.ccIn.indexOf(lb.cc) >= 0)) return false
|
|
94
|
-
|
|
95
|
-
//project from geo coordinates to ETRS89-LAEA
|
|
96
|
-
const p = opts.proj([lb.lon, lb.lat])
|
|
97
|
-
lb.x = p[0]
|
|
98
|
-
lb.y = p[1]
|
|
99
|
-
delete lb.lon
|
|
100
|
-
delete lb.lat
|
|
101
|
-
}
|
|
102
|
-
opts.baseURL = opts.baseURL || 'https://raw.githubusercontent.com/eurostat/euronym/main/pub/v2/UTF/'
|
|
103
|
-
opts.url = opts.baseURL + res + '/' + cc + '.csv'
|
|
104
|
-
return opts
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @returns {object}
|
|
109
|
-
*/
|
|
110
|
-
export const getEurostatBoundariesLayer = function (opts) {
|
|
111
|
-
opts = opts || {}
|
|
112
|
-
const nutsYear = opts.nutsYear || '2021'
|
|
113
|
-
const crs = opts.crs || '3035'
|
|
114
|
-
const scale = opts.scale || '03M'
|
|
115
|
-
const nutsLevel = opts.nutsLevel || '3'
|
|
116
|
-
const col = opts.col || '#888'
|
|
117
|
-
const colKosovo = opts.colKosovo || '#bcbcbc'
|
|
118
|
-
const showOth = opts.showOth == undefined ? true : opts.showOth
|
|
119
|
-
|
|
120
|
-
opts.color =
|
|
121
|
-
opts.color ||
|
|
122
|
-
((f, zf) => {
|
|
123
|
-
const p = f.properties
|
|
124
|
-
if (!showOth /*&& p.co == "F"*/ && p.eu != 'T' && p.cc != 'T' && p.efta != 'T' && p.oth === 'T')
|
|
125
|
-
return
|
|
126
|
-
if (p.id >= 100000) return colKosovo
|
|
127
|
-
if (p.co === 'T') return col
|
|
128
|
-
if (zf < 400) return col
|
|
129
|
-
else if (zf < 1000) return p.lvl >= 3 ? '' : col
|
|
130
|
-
else if (zf < 2000) return p.lvl >= 2 ? '' : col
|
|
131
|
-
else return p.lvl >= 1 ? '' : col
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
opts.width =
|
|
135
|
-
opts.width ||
|
|
136
|
-
((f, zf) => {
|
|
137
|
-
const p = f.properties
|
|
138
|
-
if (p.co === 'T') return 0.5
|
|
139
|
-
if (zf < 400) return p.lvl == 3 ? 2.2 : p.lvl == 2 ? 2.2 : p.lvl == 1 ? 2.2 : 4
|
|
140
|
-
else if (zf < 1000) return p.lvl == 2 ? 1.8 : p.lvl == 1 ? 1.8 : 2.5
|
|
141
|
-
else if (zf < 2000) return p.lvl == 1 ? 1.8 : 2.5
|
|
142
|
-
else return 1.2
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
opts.lineDash =
|
|
146
|
-
opts.lineDash ||
|
|
147
|
-
((f, zf) => {
|
|
148
|
-
const p = f.properties
|
|
149
|
-
if (p.co === 'T') return []
|
|
150
|
-
if (zf < 400)
|
|
151
|
-
return p.lvl == 3
|
|
152
|
-
? [2 * zf, 2 * zf]
|
|
153
|
-
: p.lvl == 2
|
|
154
|
-
? [5 * zf, 2 * zf]
|
|
155
|
-
: p.lvl == 1
|
|
156
|
-
? [5 * zf, 2 * zf]
|
|
157
|
-
: [10 * zf, 3 * zf]
|
|
158
|
-
else if (zf < 1000)
|
|
159
|
-
return p.lvl == 2 ? [5 * zf, 2 * zf] : p.lvl == 1 ? [5 * zf, 2 * zf] : [10 * zf, 3 * zf]
|
|
160
|
-
else if (zf < 2000) return p.lvl == 1 ? [5 * zf, 2 * zf] : [10 * zf, 3 * zf]
|
|
161
|
-
else return [10 * zf, 3 * zf]
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
opts.baseURL = opts.baseURL || 'https://raw.githubusercontent.com/eurostat/Nuts2json/master/pub/v2/'
|
|
165
|
-
opts.url = opts.baseURL + nutsYear + '/' + crs + '/' + scale + '/nutsbn_' + nutsLevel + '.json'
|
|
166
|
-
return opts
|
|
167
|
-
}
|
|
168
|
-
|
|
169
61
|
export const getParameterByName = GeoCanvas.getParameterByName
|
|
170
62
|
|
|
171
63
|
// set default d3 locale
|
|
@@ -21,6 +21,10 @@ export class TimeSeriesStyle extends Style {
|
|
|
21
21
|
* @type {Array.<string>} */
|
|
22
22
|
this.ts = opts.ts
|
|
23
23
|
|
|
24
|
+
/** A function specifying when a value should be considered as "no data" and thus not ignored. The line will have a break at these values.
|
|
25
|
+
* @type {function(string):boolean} */
|
|
26
|
+
this.noData = opts.noData || ((v) => v === undefined || v == "" || v === null || isNaN(+v))
|
|
27
|
+
|
|
24
28
|
//x
|
|
25
29
|
/** in geo unit
|
|
26
30
|
* @type {function(import("../Dataset.js").Cell,number,number):number} */
|
|
@@ -112,7 +116,7 @@ export class TimeSeriesStyle extends Style {
|
|
|
112
116
|
//in geo coordinates
|
|
113
117
|
cg.setCanvasTransform()
|
|
114
118
|
|
|
115
|
-
cg.ctx.lineCap =
|
|
119
|
+
cg.ctx.lineCap = "butt"
|
|
116
120
|
for (let c of cells) {
|
|
117
121
|
|
|
118
122
|
//line width
|
|
@@ -185,23 +189,62 @@ export class TimeSeriesStyle extends Style {
|
|
|
185
189
|
continue;
|
|
186
190
|
}
|
|
187
191
|
|
|
192
|
+
/*/draw line
|
|
188
193
|
if (val0 == undefined || isNaN(val0)) continue
|
|
189
|
-
|
|
190
|
-
//draw line
|
|
191
194
|
cg.ctx.beginPath()
|
|
192
195
|
const sX = w / (nb - 1)
|
|
193
196
|
for (let i = 0; i < nb; i++) {
|
|
194
197
|
const val = c[this.ts[i]]
|
|
195
|
-
if (val == undefined) break
|
|
198
|
+
if (val == undefined || isNaN(val)) break
|
|
196
199
|
if (i == 0)
|
|
197
200
|
cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
|
|
198
201
|
else
|
|
199
202
|
cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (val - val0) * h / ampMax + offY)
|
|
200
203
|
}
|
|
204
|
+
cg.ctx.stroke()*/
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
//draw line, segment by segment
|
|
208
|
+
const sX = w / (nb - 1)
|
|
209
|
+
|
|
210
|
+
//handle first point
|
|
211
|
+
let v0 = c[this.ts[0]]
|
|
212
|
+
if (!this.noData(v0)) {
|
|
213
|
+
cg.ctx.beginPath()
|
|
214
|
+
cg.ctx.moveTo(c.x + offX, c.y + y0 + (v0 - val0) * h / ampMax + offY)
|
|
215
|
+
}
|
|
216
|
+
//console.log(v0, isNaN(v0))
|
|
217
|
+
|
|
218
|
+
let v1
|
|
219
|
+
for (let i = 1; i < nb; i++) {
|
|
220
|
+
v1 = c[this.ts[i]]
|
|
201
221
|
|
|
202
|
-
|
|
222
|
+
//draw segment from v0 to v1
|
|
223
|
+
|
|
224
|
+
//both points 'no data'
|
|
225
|
+
if (this.noData(v0) && this.noData(v1)) {
|
|
226
|
+
|
|
227
|
+
//second point 'no data'
|
|
228
|
+
} else if (!this.noData(v0) && this.noData(v1)) {
|
|
229
|
+
cg.ctx.stroke()
|
|
230
|
+
|
|
231
|
+
//first point 'no data'
|
|
232
|
+
} else if (this.noData(v0) && !this.noData(v1)) {
|
|
233
|
+
cg.ctx.beginPath()
|
|
234
|
+
cg.ctx.moveTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
|
|
235
|
+
|
|
236
|
+
//both points have data: trace line
|
|
237
|
+
} else {
|
|
238
|
+
cg.ctx.lineTo(c.x + i * sX + offX, c.y + y0 + (v1 - val0) * h / ampMax + offY)
|
|
239
|
+
//if it is the last point, stroke
|
|
240
|
+
if (i == nb - 1) cg.ctx.stroke()
|
|
241
|
+
}
|
|
242
|
+
v0 = v1
|
|
243
|
+
}
|
|
203
244
|
|
|
204
245
|
}
|
|
205
246
|
|
|
206
247
|
}
|
|
248
|
+
|
|
207
249
|
}
|
|
250
|
+
|