gridviz 3.0.28 → 3.0.30

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.28",
3
+ "version": "3.0.30",
4
4
  "description": "Visualization tool for gridded statistics",
5
5
  "keywords": [
6
6
  "statistics",
package/src/index.js CHANGED
@@ -24,10 +24,9 @@ export { TextStyle } from './style/TextStyle.js'
24
24
  export { PillarStyle } from './style/PillarStyle.js'
25
25
  export { SideStyle } from './style/SideStyle.js'
26
26
  export { ShadingStyle } from './style/ShadingStyle.js'
27
- //export { ContourStyle } from './style/ContourStyle.js'
28
27
  export { SideCategoryStyle } from './style/SideCategoryStyle.js'
29
28
  export { DotDensityStyle } from './style/DotDensityStyle.js'
30
- export { TanakaStyle } from './style/TanakaStyle.js'
29
+ export { SideTanakaStyle } from './style/SideTanakaStyle.js'
31
30
  export { LegoStyle } from './style/LegoStyle.js'
32
31
  export { SquareColorWebGLStyle } from './style/SquareColorWebGLStyle.js'
33
32
  export { SquareColorCategoryWebGLStyle } from './style/SquareColorCategoryWebGLStyle.js'
@@ -1,10 +1,14 @@
1
1
  //@ts-check
2
2
  'use strict'
3
3
 
4
- import { TanakaStyle } from './TanakaStyle.js'
4
+ //import { TanakaStyle } from './SideTanakaStyle___OLD.js'
5
5
  import { StrokeStyle } from './StrokeStyle.js'
6
6
  import { SquareColorCategoryWebGLStyle } from './SquareColorCategoryWebGLStyle.js'
7
7
  import { Style } from '../core/Style.js'
8
+ //import { SideStyle } from './SideStyle.js'
9
+ import { classifier as clFun, colorClassifier as cclFun } from '../utils/scale.js'
10
+ import { SideTanakaStyle } from './SideTanakaStyle.js'
11
+
8
12
 
9
13
  /**
10
14
  * @module style
@@ -30,12 +34,30 @@ export class LegoStyle {
30
34
  //"#eee" //whithe
31
35
  ]*/
32
36
 
33
- opts.colDark = opts.colDark || '#333'
34
- opts.colBright = opts.colBright || '#aaa'
35
- opts.widthFactor = opts.widthFactor || 0.12
37
+ opts.colorDark = opts.colorDark || '#333'
38
+ opts.colorBright = opts.colorBright || '#aaa'
39
+
40
+ //make classifier
41
+ const classifier = clFun(breaks)
42
+ const classifier2 = cell => classifier(value(cell))
43
+ //make colors table
44
+ const colorsDict = {}
45
+ for (let i = 0; i < colors.length; i++) colorsDict[i + ''] = colors[i]
46
+
47
+ //make cell fill style
48
+ const cellStyle = new SquareColorCategoryWebGLStyle({
49
+ code: classifier2,
50
+ color: colorsDict,
51
+ })
52
+
53
+ //make tanaka side style
54
+ const tanakaStyle = new SideTanakaStyle({
55
+ classifier: () => classifier2,
56
+ colorDark : opts.colorDark,
57
+ colorBright : opts.colorBright,
58
+ diamond: opts.diamond,
59
+ })
36
60
 
37
- //reuse tanaka as basis
38
- const ts = TanakaStyle.get(value, breaks, colors, opts)
39
61
  //style to show limits between pieces
40
62
  const sst = new StrokeStyle({
41
63
  strokeColor: () => '#666',
@@ -44,9 +66,9 @@ export class LegoStyle {
44
66
  })
45
67
 
46
68
  return [
47
- ts[0],
69
+ cellStyle,
48
70
  sst,
49
- ts[1],
71
+ tanakaStyle,
50
72
  new LegoTopStyle({ colDark: opts.colDark, colBright: opts.colBright, filter: opts.filter }),
51
73
  ]
52
74
  }
@@ -3,7 +3,9 @@
3
3
 
4
4
  import { SideStyle } from './SideStyle.js'
5
5
  import { max } from 'd3-array'
6
- import { exponentialScale } from '../utils/stretching.js'
6
+
7
+ /** @typedef {{ x:number, y:number, or:"v"|"h", c1:(import('../core/Dataset.js').Cell)|undefined, c2:(import('../core/Dataset.js').Cell)|undefined }} Side */
8
+
7
9
 
8
10
  /**
9
11
  * @module style
@@ -28,7 +30,7 @@ export class ShadingStyle extends SideStyle {
28
30
  const elevation = opts.elevation
29
31
 
30
32
  // compute side value as elevation difference and attach to side
31
- const sideValue = (side) => {
33
+ const sideValue = (/** @type {Side} */ side) => {
32
34
  if (!side.c1) side.v = 0
33
35
  else if (!side.c2) side.v = 0
34
36
  else if (!side.c1[elevation]) side.v = 0
@@ -55,7 +57,5 @@ export class ShadingStyle extends SideStyle {
55
57
 
56
58
  this.width = (_, r, z) => opts.width | Math.min(2 * z, r / 3)
57
59
  this.diamond = opts.diamond
58
-
59
60
  }
60
-
61
61
  }
@@ -0,0 +1,152 @@
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../core/Style.js'
5
+ import { SideStyle } from './SideStyle.js'
6
+
7
+ /** @typedef {{ x:number, y:number, or:"v"|"h", c1:(import('../core/Dataset.js').Cell)|undefined, c2:(import('../core/Dataset.js').Cell)|undefined }} Side */
8
+
9
+ /**
10
+ * @typedef {function(Array.<Side>,number, number):*} SideViewScale */
11
+
12
+ /**
13
+ * @module style
14
+ * @author Julien Gaffuri
15
+ */
16
+ export class SideTanakaStyle extends Style {
17
+ /** @param {object} opts */
18
+ constructor(opts = {}) {
19
+ super(opts)
20
+
21
+ /** A function returning the cells classifier.
22
+ * The cell classifier is a function that for each cell returns its class number (int).
23
+ */
24
+ this.classifier = opts.classifier || ((cells, resolution, z) => c => 1)
25
+
26
+ /** A function returning the width of a cell side, in geo unit
27
+ * @type {function(Side, number, number, number, object):number} */
28
+ this.width = opts.width || ((side, sideValue, resolution, z, sidesScale) => Math.abs(sideValue) * Math.min(2 * z, resolution / 3))
29
+
30
+ /** A function returning the length of a cell side, in geo unit
31
+ * @type {function(Side, number, number, object):number} */
32
+ this.length = opts.length || ((side, resolution, z, sidesScale) => resolution)
33
+
34
+ // the dark color: for side facing away from light (coming from NW)
35
+ this.colorDark = opts.colorDark || '#111'
36
+ // the bright color: for side facing the light (coming from NW)
37
+ this.colorBright = opts.colorBright || '#ddd'
38
+ //
39
+ this.revert = opts.revert == undefined? false : opts.revert
40
+
41
+ /** Set to A or true so that the side is drawn as a diamond */
42
+ this.diamond = opts.diamond
43
+
44
+ /* Determines what to do for limit sides, between a cell with value and one with no value
45
+ * steep: the cell value absence is equivalent to 0. It shows potentially a steep limit then.
46
+ * skip: no side is drawn
47
+ * step: a side with a 1 step */
48
+ this.limit = opts.limit || "steep"
49
+ }
50
+
51
+ /**
52
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
53
+ * @param {number} resolution
54
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
55
+ */
56
+ draw(cells, geoCanvas, resolution) {
57
+ //filter
58
+ if (this.filter) cells = cells.filter(this.filter)
59
+
60
+ //
61
+ const z = geoCanvas.view.z
62
+ const ctx = geoCanvas.offscreenCtx
63
+
64
+ //get cell classifier
65
+ const classifier = this.classifier(cells, resolution, z)
66
+
67
+ //get side value: class change difference
68
+ const getSideValue = (/** @type {{ c1: Side; c2: Side; }} */ side) => {
69
+ const cl1 = side.c1 ? classifier(side.c1) : undefined
70
+ const cl2 = side.c2 ? classifier(side.c2) : undefined
71
+ if (cl1 === undefined && cl2 === undefined) return undefined
72
+ if (cl1 === undefined) return this.limit=="none"? undefined : this.limit=="steep"? cl2 : Math.sign(cl2)
73
+ if (cl2 === undefined) return this.limit=="none"? undefined : this.limit=="steep"? -cl1 : Math.sign(-cl1)
74
+ return cl2 - cl1
75
+ }
76
+
77
+ //build sides
78
+ //TODO build only those with different codes ?
79
+ /** @type {Array.<Side>} */
80
+ const sides = SideStyle.buildSides(cells, resolution)
81
+ if (sides.length == 0) return
82
+
83
+ //get side view scale
84
+ const viewScale = this.viewScale ? this.viewScale(sides, resolution, z) : undefined
85
+
86
+ //draw sides
87
+ ctx.lineCap = 'butt'
88
+ const r2 = resolution * 0.5
89
+ const cd = this.revert? this.colorBright : this.colorDark
90
+ const cb = this.revert? this.colorDark : this.colorBright
91
+ for (let side of sides) {
92
+
93
+ //get side value
94
+ const v = getSideValue(side)
95
+ if (v === undefined || v === 0) continue
96
+
97
+ //color
98
+ /** @type {string|undefined} */
99
+ const col = ((v < 0 && side.or === 'h') || (v > 0 && side.or === 'v')) ? cb : cd
100
+ if (!col || col == 'none') continue
101
+
102
+ if (this.diamond) {
103
+ //set color
104
+ ctx.fillStyle = col
105
+
106
+ //draw diamond
107
+ const x = side.x,
108
+ y = side.y
109
+ ctx.beginPath()
110
+ ctx.moveTo(x - r2, y)
111
+ ctx.lineTo(x, y + r2)
112
+ ctx.lineTo(x + r2, y)
113
+ ctx.lineTo(x, y - r2)
114
+ ctx.closePath()
115
+ ctx.fill()
116
+ } else {
117
+ //width
118
+ /** @type {number|undefined} */
119
+ const wG = this.width ? this.width(side, v, resolution, z, viewScale) : undefined
120
+ if (!wG || wG <= 0) continue
121
+
122
+ //length
123
+ /** @type {number|undefined} */
124
+ const lG = this.length ? this.length(side, resolution, z, viewScale) : undefined
125
+ if (!lG || lG <= 0) continue
126
+ const lG2 = lG * 0.5
127
+
128
+ //set width
129
+ ctx.lineWidth = wG
130
+ //set color
131
+ ctx.strokeStyle = col
132
+
133
+ //draw segment with correct orientation
134
+ const x = side.x,
135
+ y = side.y
136
+ ctx.beginPath()
137
+ if (side.or === 'v') {
138
+ ctx.moveTo(x, y - lG2)
139
+ ctx.lineTo(x, y + lG2)
140
+ } else {
141
+ ctx.moveTo(x - lG2, y)
142
+ ctx.lineTo(x + lG2, y)
143
+ }
144
+ ctx.stroke()
145
+ }
146
+ }
147
+
148
+ //update legends
149
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
150
+ }
151
+
152
+ }
@@ -1,9 +1,6 @@
1
1
  //@ts-check
2
2
  'use strict'
3
3
 
4
- import { SideStyle } from './SideStyle.js'
5
- import { SquareColorCategoryWebGLStyle } from './SquareColorCategoryWebGLStyle.js'
6
- import { classifier as clFun, colorClassifier as cclFun } from '../utils/scale.js'
7
4
 
8
5
  /**
9
6
  * @see https://manifold.net/doc/mfd9/example__tanaka_contours.htm
@@ -17,7 +14,7 @@ export class TanakaStyle {
17
14
  * @param {Array.<number>} breaks The break values
18
15
  * @param {Array.<string>} colors The colors, one more than the break values
19
16
  * @param {object} opts
20
- * @returns {Array.<import("../core/Style").Style>}
17
+ * @returns {Array.<import("../core/Style.js").Style>}
21
18
  */
22
19
  static get(value, breaks, colors, opts = {}) {
23
20
  //shadow colors
@@ -168,6 +168,7 @@ export const viewScaleCombination = (obj) => {
168
168
  }
169
169
  }
170
170
 
171
+
171
172
  /**
172
173
  * Return a classifier function from break values.
173
174
  * The classifier function returns the class id (from 0 to breaks.length) from a value to classifiy.
@@ -188,6 +189,20 @@ export function classifier(breaks) {
188
189
  return classifier
189
190
  }
190
191
 
192
+ /**
193
+ * @param {number} min
194
+ * @param {number} max
195
+ * @param {number} nbClass
196
+ */
197
+ export function classifierMinMax(min, max, nbClass) {
198
+ const breaks = []
199
+ const step = (max - min) / nbClass
200
+ for (let i = 1; i < nbClass; i++) breaks.push(min + i * step)
201
+ return classifier(breaks)
202
+ }
203
+
204
+
205
+
191
206
  /**
192
207
  * Return a color classifier function from break values.
193
208
  * The classifier function returns the color from a value to classifiy.
@@ -1,21 +0,0 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { SideStyle } from './SideStyle.js'
5
-
6
- /** @typedef {{x:number,y:number,or:"v"|"h",value:number}} Side */
7
-
8
- /**
9
- *
10
- * @module style
11
- * @author Julien Gaffuri
12
- */
13
- export class ContourStyle extends SideStyle {
14
- /** @param {object} opts */
15
- constructor(opts) {
16
- super(opts)
17
- //opts = opts || {}
18
-
19
- //TODO
20
- }
21
- }