gridviz 3.0.3 → 3.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gridviz",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "Visualization tool for gridded statistics",
5
5
  "keywords": [
6
6
  "statistics",
@@ -17,7 +17,7 @@ export class Dataset {
17
17
  * @param {import("./Map.js").Map} map The map.
18
18
  * @param {string} url The URL of the dataset.
19
19
  * @param {number} resolution The dataset resolution, in the CRS geographical unit.
20
- * @param {{preprocess?:function(Cell):boolean}} opts
20
+ * @param {{preprocess?:function(Cell):boolean, mixedResolution?:function(Cell):number}} opts
21
21
  * @abstract
22
22
  */
23
23
  constructor(map, url, resolution, opts = {}) {
@@ -40,6 +40,13 @@ export class Dataset {
40
40
  * @type {number} */
41
41
  this.resolution = resolution
42
42
 
43
+ /**
44
+ * In case the dataset is a dataset with cells having different resolution,
45
+ * this is the function returning the resolution of each cell.
46
+ * @protected
47
+ * @type {(function(Cell):number )| undefined } */
48
+ this.mixedResolution = opts.mixedResolution
49
+
43
50
  /**
44
51
  * A preprocess to run on each cell after loading. It can be used to apply some specific treatment before or compute a new column. And also to determine which cells to keep after loading.
45
52
  * @type {(function(Cell):boolean )| undefined } */
@@ -96,6 +103,22 @@ export class Dataset {
96
103
  }
97
104
  return undefined*/
98
105
 
106
+ //rare case of mixed resolution dataset
107
+ if (this.mixedResolution) {
108
+ for (const c of cells) {
109
+ /** @type {number} */
110
+ const r = this.mixedResolution(c)
111
+ if (posGeo.x < c.x) continue
112
+ else if (c.x + r < posGeo.x) continue
113
+ else if (posGeo.y < c.y) continue
114
+ else if (c.y + r < posGeo.y) continue
115
+ else return c
116
+ }
117
+ return undefined
118
+ }
119
+
120
+ //common case
121
+
99
122
  /** @type {number} */
100
123
  const r = this.getResolution()
101
124
  for (const cell of cells) {
package/src/core/Map.js CHANGED
@@ -171,7 +171,8 @@ export class Map {
171
171
 
172
172
  //set layer alpha and blend mode
173
173
  this.geoCanvas.ctx.globalAlpha = layer.alpha ? layer.alpha(z) : 1.0
174
- this.geoCanvas.ctx.globalCompositeOperation = layer.blendOperation(z)
174
+ if (layer.blendOperation)
175
+ this.geoCanvas.ctx.globalCompositeOperation = layer.blendOperation(z)
175
176
 
176
177
  //set affin transform to draw with geographical coordinates
177
178
  this.geoCanvas.setCanvasTransform()
@@ -300,6 +301,15 @@ export class Map {
300
301
  const cell = dsc.getCellFromPosition(posGeo, dsc.getViewCache())
301
302
  //console.log(cell, dsc.resolution)
302
303
  if (!cell) return undefined
304
+
305
+ //rare case for a dataset with mixed resolutions
306
+ if (dsc.mixedResolution) {
307
+ const r = dsc.mixedResolution(cell)
308
+ const html = layer.cellInfoHTML(cell, r)
309
+ if (!html) return undefined
310
+ return { cell: cell, html: html, resolution: r }
311
+ }
312
+
303
313
  const html = layer.cellInfoHTML(cell, dsc.getResolution())
304
314
  if (!html) return undefined
305
315
  return { cell: cell, html: html, resolution: dsc.getResolution() }
package/src/core/Style.js CHANGED
@@ -78,10 +78,16 @@ export class Style extends Drawable {
78
78
  * @param {object} opts
79
79
  * @returns {this} */
80
80
  updateLegends(opts) {
81
- for (const lg of this.legends) lg.update(opts)
81
+ Style.updateLegendsRecursive(this.legends, opts)
82
82
  return this
83
83
  }
84
84
 
85
+ /** @private */
86
+ static updateLegendsRecursive(lg, opts) {
87
+ if (Array.isArray(lg)) for (const lg_ of lg) this.updateLegendsRecursive(lg_, opts)
88
+ else lg.update(opts)
89
+ }
90
+
85
91
  /**
86
92
  * @param {Array.<import("./Legend").Legend>} legends
87
93
  * @returns {this} */
@@ -68,7 +68,8 @@ export class GridLayer extends Layer {
68
68
  //set style alpha and blend mode
69
69
  //TODO: multiply by layer alpha ?
70
70
  geoCanvas.ctx.globalAlpha = s.alpha ? s.alpha(z) : 1.0
71
- geoCanvas.ctx.globalCompositeOperation = s.blendOperation(z)
71
+ if (s.blendOperation)
72
+ geoCanvas.ctx.globalCompositeOperation = s.blendOperation(z)
72
73
 
73
74
  //set affin transform to draw with geographical coordinates
74
75
  geoCanvas.setCanvasTransform()
@@ -86,24 +87,14 @@ export class GridLayer extends Layer {
86
87
  for (const s of this.styles) {
87
88
  //check if style is visible
88
89
  if (s.visible && !s.visible(z)) continue
89
- for (const lg of s.legends) {
90
- //console.log(s, lg)
91
- //this.legend.append(lg.div)
92
- //s1.node().appendChild(s2.node())
93
- legend.node().append(lg.div.node())
94
- }
90
+ GridLayer.addLegends(legend, s.legends)
95
91
 
96
92
  //case for styles of styles, like kernel smoothing
97
93
  //TODO do better
98
94
  if (s['styles']) {
99
95
  for (const s2 of s['styles']) {
100
96
  if (s2.visible && !s2.visible(z)) continue
101
- for (const lg of s2.legends) {
102
- //console.log(s, lg)
103
- //this.legend.append(lg.div)
104
- //s1.node().appendChild(s2.node())
105
- legend.node().append(lg.div.node())
106
- }
97
+ GridLayer.addLegends(legend, s2.legends)
107
98
  }
108
99
  }
109
100
  }
@@ -111,6 +102,11 @@ export class GridLayer extends Layer {
111
102
 
112
103
  }
113
104
 
105
+ /** @private */
106
+ static addLegends(legendComp, lg) {
107
+ if (Array.isArray(lg)) for (const lg_ of lg) this.addLegends(legendComp, lg_)
108
+ else legendComp.node().append(lg.div.node())
109
+ }
114
110
 
115
111
 
116
112
  /**
@@ -17,12 +17,12 @@ export class SizeLegend extends Legend {
17
17
  super(opts)
18
18
  opts = opts || {}
19
19
 
20
- /** A function returning the text label
21
- * @type { function(object, Array.<import('../core/Dataset.js').Cell>):(number|string) } */
20
+ /** A function returning the text label, from the view scale and list of cells, resolution and zoom
21
+ * @type { function(object, Array.<import('../core/Dataset.js').Cell>, number, number):(number|string) } */
22
22
  this.label = opts.label || undefined
23
23
 
24
- /** A function returning the size of the legend symbol
25
- * @type { function(object):number } */
24
+ /** A function returning the size of the legend symbol, in geo UoM, from the viewscale, resolution and zoom
25
+ * @type { function(object, number, number):number } */
26
26
  this.size = opts.size || undefined
27
27
 
28
28
  //symbol
@@ -52,12 +52,12 @@ export class SizeLegend extends Legend {
52
52
  this.makeTitle()
53
53
 
54
54
  //get label. May not be a number (!)
55
- let label = this.label(opts.viewScale, opts.cells)
55
+ let label = this.label(opts.viewScale, opts.cells, opts.resolution, opts.z)
56
56
 
57
57
  //compute size of symbol, in pix
58
58
  let sizePix
59
59
  if (this.size)
60
- sizePix = this.size(opts.viewScale) / opts.z
60
+ sizePix = this.size(opts.viewScale, opts.resolution, opts.z) / opts.z
61
61
  else
62
62
  sizePix = opts.viewScale(+label) / opts.z
63
63
  if (!sizePix) return
@@ -3,7 +3,16 @@
3
3
 
4
4
  import { loadImage } from '../utils/utils.js'
5
5
 
6
- //load chernoff images
6
+ //
7
+
8
+ /**
9
+ * Load chernoff images
10
+ * See for example: https://github.com/jgaffuri/chernoff-faces
11
+ * @param {object} out
12
+ * @param {string} baseURL
13
+ * @param {function|undefined} callback
14
+ * @returns
15
+ */
7
16
  export async function loadChernoffFacesImages(out, baseURL, callback = undefined) {
8
17
  out = out || {}
9
18
  for (let s of ["f", "m"])
@@ -11,4 +20,5 @@ export async function loadChernoffFacesImages(out, baseURL, callback = undefined
11
20
  for (let i = 0; i <= 2; i++)
12
21
  out[s + a + i] = await loadImage(baseURL + (s + a + i) + ".png")
13
22
  if (callback) callback()
23
+ return out
14
24
  }