gridviz 2.1.10 → 2.1.12

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": "2.1.10",
3
+ "version": "2.1.12",
4
4
  "description": "Visualization tool for gridded statistics",
5
5
  "keywords": [
6
6
  "statistics",
@@ -28,7 +28,7 @@ export class IsoFenceStyle extends Style {
28
28
  * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
29
29
  this.height = opts.height || ((v, r, s, zf) => r * 0.4)
30
30
 
31
- /** The perspective angle.
31
+ /** The perspective angle, in degree, within [-180,180], from [O,x] axis.
32
32
  * @type {number} */
33
33
  this.angle = opts.angle != undefined ? opts.angle : 50
34
34
 
@@ -76,9 +76,6 @@ export class IsoFenceStyle extends Style {
76
76
  //nb categories - used for radar and agepyramid
77
77
  const cats = Object.keys(this.color)
78
78
 
79
- //draw in geo coordinates
80
- cg.setCanvasTransform()
81
-
82
79
  //half resolution
83
80
  const r2 = r / 2
84
81
 
@@ -146,32 +143,46 @@ export class IsoFenceStyle extends Style {
146
143
  //angle in radians
147
144
  const aRad = this.angle * Math.PI / 180, cos = Math.cos(aRad), sin = Math.sin(aRad)
148
145
 
146
+ //sort sides so that the back ones are drawn first. This depends on the angle.
147
+ //depending on distance to the reference corner point
148
+ const xCorner = Math.abs(this.angle) < 90 ? cg.extGeo.xMin : cg.extGeo.xMax
149
+ const yCorner = this.angle < 0 ? cg.extGeo.yMax : cg.extGeo.yMin
150
+ sides.sort((s1, s2) => (Math.hypot(s2.x - xCorner, s2.y - yCorner) - Math.hypot(s1.x - xCorner, s1.y - yCorner)))
151
+
152
+ //prepare function to draw corner line for a cell *c*
153
+ const drawCornerLine = (c) => {
154
+
155
+ if (!c) return
156
+ //line style
157
+ const lw = this.cornerLineWidth ? this.cornerLineWidth(c, r, zf, this.angle) : 0.8 * zf
158
+ if (lw == 0) return
159
+ cg.ctx.strokeStyle = this.cornerLineStrokeColor ? this.cornerLineStrokeColor(c, r, zf, this.angle) : "#333"
160
+ cg.ctx.lineWidth = lw
161
+
162
+ //height - in geo
163
+ const hG = h_(c[this.heightCol], r, stat, zf)
164
+
165
+ //draw line
166
+ cg.ctx.beginPath()
167
+ cg.ctx.moveTo(c.x + r2 + dx, c.y + r2 + dy)
168
+ cg.ctx.lineTo(c.x + r2 + hG * cos + dx, c.y + r2 + hG * sin + dy)
169
+ cg.ctx.stroke()
170
+ }
171
+
149
172
  //draw in geo coordinates
150
173
  cg.setCanvasTransform()
151
174
 
152
- //sort sides so that the back ones are drawn first. This depends on the angle
153
- if (Math.abs(this.angle) <= 90)
154
- //north east ones are drown first
155
- sides.sort((s1, s2) => (Math.hypot(s2.x, s2.y) - Math.hypot(s1.x, s1.y)))
156
- else if (this.angle > 90)
157
- //north west ones are drown first
158
- sides.sort((s1, s2) => (Math.hypot(s2.x - cg.extGeo.xMax, s2.y) - Math.hypot(s1.x - cg.extGeo.xMax, s1.y)))
159
- else if (this.angle < 90)
160
- //south west ones are drown first
161
- sides.sort((s1, s2) => (Math.hypot(s2.x - cg.extGeo.xMax, s2.y - cg.extGeo.yMax) - Math.hypot(s1.x - cg.extGeo.xMax, s1.y - cg.extGeo.yMax)))
162
-
163
175
  //draw sides
176
+ cg.ctx.lineCap = "round";
164
177
  for (let s of sides) {
165
178
 
166
179
  //heights - in geo
167
- /** @type {number} */
168
- const hG1 = s.c1 ? h_(s.c1[this.heightCol], r, stat, zf) : 0
169
- /** @type {number} */
170
- const hG2 = s.c2 ? h_(s.c2[this.heightCol], r, stat, zf) : 0
180
+ const hG1 = s.c1 ? h_(s.c1[this.heightCol], r, stat, zf) : 0,
181
+ hG2 = s.c2 ? h_(s.c2[this.heightCol], r, stat, zf) : 0
171
182
 
172
183
  //compute totals for both cells
173
- const total1 = computeTotal(s.c1, cats)
174
- const total2 = computeTotal(s.c2, cats)
184
+ const total1 = computeTotal(s.c1, cats),
185
+ total2 = computeTotal(s.c2, cats)
175
186
  if (total1 == 0 && total2 == 0) continue
176
187
 
177
188
  let cumul1 = 0, cumul2 = 0
@@ -184,10 +195,10 @@ export class IsoFenceStyle extends Style {
184
195
  if (v1 == 0 && v2 == 0) continue
185
196
 
186
197
  //compute heights
187
- const h1 = total1 > 0 ? hG1 * cumul1 / total1 : 0
188
- const h1n = total1 > 0 ? hG1 * (cumul1 + v1) / total1 : 0
189
- const h2 = total2 > 0 ? hG2 * cumul2 / total2 : 0
190
- const h2n = total2 > 0 ? hG2 * (cumul2 + v2) / total2 : 0
198
+ const h1 = hG1 * cumul1 / total1 || 0
199
+ const h1n = hG1 * (cumul1 + v1) / total1 || 0
200
+ const h2 = hG2 * cumul2 / total2 || 0
201
+ const h2n = hG2 * (cumul2 + v2) / total2 || 0
191
202
 
192
203
  //make path
193
204
  cg.ctx.beginPath()
@@ -212,7 +223,7 @@ export class IsoFenceStyle extends Style {
212
223
  //top left
213
224
  cg.ctx.lineTo(s.x - r2 + h1n * cos + dx, s.y + h1n * sin + dy)
214
225
  }
215
- cg.ctx.closePath()
226
+ //cg.ctx.closePath()
216
227
 
217
228
  //fill
218
229
  cg.ctx.fillStyle = color
@@ -220,27 +231,16 @@ export class IsoFenceStyle extends Style {
220
231
 
221
232
  cumul1 += v1
222
233
  cumul2 += v2
223
- //break
224
- }
225
- }
226
-
227
- //draw corner lines
228
- for (let c of cells) {
229
-
230
- //line style
231
- const lw = this.cornerLineWidth ? this.cornerLineWidth(c, r, zf, this.angle) : 0.8 * zf
232
- if (lw == 0) continue
233
- cg.ctx.strokeStyle = this.cornerLineStrokeColor ? this.cornerLineStrokeColor(c, r, zf, this.angle) : "#333"
234
- cg.ctx.lineWidth = lw
235
234
 
236
- //height - in geo
237
- const hG = h_(c[this.heightCol], r, stat, zf)
238
-
239
- cg.ctx.beginPath()
240
- cg.ctx.moveTo(c.x + r2 + dx, c.y + r2 + dy)
241
- cg.ctx.lineTo(c.x + r2 + hG * cos + dx, c.y + r2 + hG * sin + dy)
242
- cg.ctx.closePath()
243
- cg.ctx.stroke()
235
+ //TODO draw only one line
236
+ //draw corner line
237
+ //if (s.or == "h") {
238
+ drawCornerLine(s.c1)
239
+ drawCornerLine(s.c2)
240
+ //if (this.angle > 0 && s.or == "h") drawCornerLine(s.c2)
241
+ //else drawCornerLine(s.c2)
242
+ //}
243
+ }
244
244
  }
245
245
 
246
246
  //update legends
@@ -2,6 +2,7 @@
2
2
  'use strict'
3
3
 
4
4
  import { Style } from '../Style.js'
5
+ import { color } from 'd3-color'
5
6
 
6
7
  /**
7
8
  * A very generic style that shows grid cells with specific color, size and shape.
@@ -34,6 +35,14 @@ export class ShapeColorSizeStyle extends Style {
34
35
  /** A function returning the shape of a cell.
35
36
  * @type {function(import("../Dataset").Cell):import("../Style").Shape} */
36
37
  this.shape = opts.shape || (() => 'square')
38
+
39
+ /** The name of the column/attribute of the tabular data where to retrieve the variable for color alpha.
40
+ * @type {string} */
41
+ this.alphaCol = opts.alphaCol
42
+
43
+ /** A function returning the color alpha of the cell.
44
+ * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
45
+ this.alphaF = opts.alphaF
37
46
  }
38
47
 
39
48
  /**
@@ -64,6 +73,12 @@ export class ShapeColorSizeStyle extends Style {
64
73
  statColor = Style.getStatistics(cells, (c) => c[this.colorCol], true)
65
74
  }
66
75
 
76
+ let statAlpha
77
+ if (this.alphaCol) {
78
+ //compute color alpha variable statistics
79
+ statAlpha = Style.getStatistics(cells, (c) => c[this.alphaCol], true)
80
+ }
81
+
67
82
  //draw with HTML canvas
68
83
  //in geo coordinates
69
84
  cg.setCanvasTransform()
@@ -71,9 +86,19 @@ export class ShapeColorSizeStyle extends Style {
71
86
  const r2 = r * 0.5
72
87
  for (let cell of cells) {
73
88
  //color
74
- const col = this.color ? this.color(cell[this.colorCol], r, statColor, zf) : undefined
89
+ let col = this.color ? this.color(cell[this.colorCol], r, statColor, zf) : undefined
75
90
  if (!col || col === 'none') continue
76
- cg.ctx.fillStyle = col
91
+
92
+ //alpha
93
+ if (this.alphaCol && this.alphaF) {
94
+ //get alpha
95
+ const alpha = this.alphaF(cell[this.alphaCol], r, statAlpha, zf)
96
+ if (alpha == 0) continue
97
+ //apply alpha to color col
98
+ const col_ = color(col);
99
+ if (col_) col = `rgba(${col_.r}, ${col_.g}, ${col_.b}, ${alpha})`;
100
+ else console.warn("Could not decode color " + col + " in ShapeColorSizeStyle")
101
+ }
77
102
 
78
103
  //shape
79
104
  const shape = this.shape ? this.shape(cell) : 'square'
@@ -88,6 +113,7 @@ export class ShapeColorSizeStyle extends Style {
88
113
  //get offset
89
114
  const offset = this.offset(cell, r, zf)
90
115
 
116
+ cg.ctx.fillStyle = col
91
117
  if (shape === 'square') {
92
118
  //draw square
93
119
  const d = r * (1 - sG / r) * 0.5