gridviz 2.0.40 → 2.0.42

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.
Files changed (55) hide show
  1. package/README.md +119 -119
  2. package/dist/gridviz.js +15722 -33305
  3. package/dist/gridviz.min.js +2 -2
  4. package/package.json +76 -77
  5. package/src/App.js +642 -698
  6. package/src/BackgroundLayer.js +182 -182
  7. package/src/BackgroundLayerWMS.js +131 -131
  8. package/src/Dataset.js +76 -76
  9. package/src/DatasetComponent.js +101 -103
  10. package/src/GeoCanvas.js +420 -419
  11. package/src/LabelLayer.js +190 -190
  12. package/src/Layer.js +92 -92
  13. package/src/Legend.js +86 -86
  14. package/src/LineLayer.js +150 -150
  15. package/src/Style.js +114 -114
  16. package/src/Tooltip.js +168 -168
  17. package/src/dataset/COGeo.js +24 -24
  18. package/src/dataset/CSVGrid.js +104 -104
  19. package/src/dataset/GeoTIFF.js +127 -127
  20. package/src/dataset/GridTile.js +41 -41
  21. package/src/dataset/TiledGrid.js +264 -296
  22. package/src/index.js +176 -174
  23. package/src/legend/ColorCategoryLegend.js +124 -124
  24. package/src/legend/ColorDiscreteLegend.js +103 -105
  25. package/src/legend/ColorLegend.js +124 -125
  26. package/src/legend/SegmentOrientationLegend.js +87 -87
  27. package/src/legend/SegmentWidthLegend.js +97 -97
  28. package/src/legend/SizeLegend.js +141 -141
  29. package/src/style/CompositionStyle.js +300 -300
  30. package/src/style/ContourStyle.js +54 -54
  31. package/src/style/DotDensityStyle.js +156 -156
  32. package/src/style/JoyPlotStyle.js +135 -135
  33. package/src/style/LegoStyle.js +112 -112
  34. package/src/style/MosaicStyle.js +107 -107
  35. package/src/style/NinjaStarStyle.js +124 -124
  36. package/src/style/PillarStyle.js +230 -230
  37. package/src/style/SegmentStyle.js +142 -142
  38. package/src/style/ShapeColorSizeStyle.js +126 -126
  39. package/src/style/SideCatStyle.js +172 -172
  40. package/src/style/SideStyle.js +218 -218
  41. package/src/style/SquareColorCatWGLStyle.js +120 -120
  42. package/src/style/SquareColorWGLStyle.js +146 -146
  43. package/src/style/StrokeStyle.js +131 -131
  44. package/src/style/TanakaStyle.js +160 -160
  45. package/src/style/TextStyle.js +132 -132
  46. package/src/utils/Utils.js +35 -35
  47. package/src/utils/WebGLRectangleColoring.js +106 -106
  48. package/src/utils/WebGLSquareColoring.js +118 -118
  49. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  50. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  51. package/src/utils/WebGLSquareColoringKS.js +153 -153
  52. package/src/utils/stretching.js +131 -131
  53. package/src/utils/webGLUtils.js +71 -71
  54. package/src/utils/zoomUtils.js +142 -142
  55. package/src/dataset/ParquetGrid.js +0 -122
@@ -1,131 +1,131 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../Style.js'
5
-
6
- /**
7
- *
8
- * @author Julien Gaffuri
9
- */
10
- export class StrokeStyle extends Style {
11
- /** @param {object} opts */
12
- constructor(opts) {
13
- super(opts)
14
- opts = opts || {}
15
-
16
- /** The name of the column/attribute of the tabular data where to retrieve the variable for color.
17
- * @type {string} */
18
- this.strokeColorCol = opts.strokeColorCol
19
-
20
- /** A function returning the color of the stroke.
21
- * @type {function(number,number,import("../Style").Stat|undefined):string} */
22
- this.strokeColor = opts.strokeColor || (() => '#666')
23
-
24
- /** The name of the column/attribute of the tabular data where to retrieve the variable for size.
25
- * @type {string} */
26
- this.sizeCol = opts.sizeCol
27
-
28
- /** A function returning the size of a cell in geographical unit.
29
- * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
30
- this.size = opts.size
31
-
32
- /** The stroke line width, in pixels.
33
- * @type {string} */
34
- this.strokeWidthCol = opts.strokeWidthCol
35
-
36
- /** The stroke line width in geographical unit.
37
- * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
38
- this.strokeWidth = opts.strokeWidth // (v,r,s,z)=>...
39
-
40
- /** A function returning the shape of a cell.
41
- * @type {function(import("../Dataset").Cell):import("../Style").Shape} */
42
- this.shape = opts.shape || (() => 'square')
43
- }
44
-
45
- /**
46
- * Draw cells as squares, with various colors and size.
47
- *
48
- * @param {Array.<import("../Dataset").Cell>} cells
49
- * @param {number} r
50
- * @param {import("../GeoCanvas").GeoCanvas} cg
51
- */
52
- draw(cells, r, cg) {
53
- //filter
54
- if (this.filter) cells = cells.filter(this.filter)
55
-
56
- //zoom factor
57
- const zf = cg.getZf()
58
-
59
- let statColor
60
- if (this.strokeColorCol) statColor = Style.getStatistics(cells, (c) => c[this.strokeColorCol], true)
61
-
62
- let statSize
63
- if (this.sizeCol) statSize = Style.getStatistics(cells, (c) => c[this.sizeCol], true)
64
-
65
- let statWidth
66
- if (this.strokeWidthCol) statWidth = Style.getStatistics(cells, (c) => c[this.strokeWidthCol], true)
67
-
68
- //draw with HTML canvas
69
- //in geo coordinates
70
- cg.setCanvasTransform()
71
-
72
- const r2 = r * 0.5
73
- for (let cell of cells) {
74
- //color
75
- const col = this.strokeColor
76
- ? this.strokeColor(cell[this.strokeColorCol], r, statColor)
77
- : undefined
78
- if (!col || col === 'none') continue
79
- cg.ctx.strokeStyle = col
80
-
81
- //size
82
- /** @type {function(number,number,import("../Style").Stat|undefined,number):number} */
83
- let s_ = this.size || (() => r)
84
- //size - in geo unit
85
- const sG = s_(cell[this.sizeCol], r, statSize, zf)
86
-
87
- //width
88
- const wi = this.strokeWidth
89
- ? this.strokeWidth(cell[this.strokeWidthCol], r, statWidth, zf)
90
- : 1 * zf
91
- if (!wi || wi <= 0) continue
92
- cg.ctx.lineWidth = wi
93
-
94
- //shape
95
- const shape = this.shape ? this.shape(cell) : 'square'
96
- if (shape === 'none') continue
97
-
98
- //get offset
99
- const offset = this.offset(cell, r, zf)
100
-
101
- if (shape === 'square') {
102
- //draw square
103
- const d = r * (1 - sG / r) * 0.5
104
- cg.ctx.beginPath()
105
- cg.ctx.rect(cell.x + d + offset.dx, cell.y + d + offset.dy, sG, sG)
106
- cg.ctx.stroke()
107
- } else if (shape === 'circle') {
108
- //draw circle
109
- cg.ctx.beginPath()
110
- cg.ctx.arc(cell.x + r2 + offset.dx, cell.y + r2 + offset.dy, sG * 0.5, 0, 2 * Math.PI, false)
111
- cg.ctx.stroke()
112
- } else if (shape === 'diamond') {
113
- const s2 = sG * 0.5
114
- cg.ctx.beginPath()
115
- cg.ctx.moveTo(cell.x + r2 - s2, cell.y + r2)
116
- cg.ctx.lineTo(cell.x + r2, cell.y + r2 + s2)
117
- cg.ctx.lineTo(cell.x + r2 + s2, cell.y + r2)
118
- cg.ctx.lineTo(cell.x + r2, cell.y + r2 - s2)
119
- cg.ctx.lineTo(cell.x + r2 - s2, cell.y + r2)
120
- cg.ctx.stroke()
121
- } else if (shape === 'donut') {
122
- console.error('Not implemented')
123
- } else {
124
- throw new Error('Unexpected shape:' + shape)
125
- }
126
- }
127
-
128
- //update legends
129
- //this.updateLegends({ style: this, r: resolution, zf: zf, sSize: statSize, sColor: statColor });
130
- }
131
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../Style.js'
5
+
6
+ /**
7
+ *
8
+ * @author Julien Gaffuri
9
+ */
10
+ export class StrokeStyle extends Style {
11
+ /** @param {object} opts */
12
+ constructor(opts) {
13
+ super(opts)
14
+ opts = opts || {}
15
+
16
+ /** The name of the column/attribute of the tabular data where to retrieve the variable for color.
17
+ * @type {string} */
18
+ this.strokeColorCol = opts.strokeColorCol
19
+
20
+ /** A function returning the color of the stroke.
21
+ * @type {function(number,number,import("../Style").Stat|undefined):string} */
22
+ this.strokeColor = opts.strokeColor || (() => '#666')
23
+
24
+ /** The name of the column/attribute of the tabular data where to retrieve the variable for size.
25
+ * @type {string} */
26
+ this.sizeCol = opts.sizeCol
27
+
28
+ /** A function returning the size of a cell in geographical unit.
29
+ * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
30
+ this.size = opts.size
31
+
32
+ /** The stroke line width, in pixels.
33
+ * @type {string} */
34
+ this.strokeWidthCol = opts.strokeWidthCol
35
+
36
+ /** The stroke line width in geographical unit.
37
+ * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
38
+ this.strokeWidth = opts.strokeWidth // (v,r,s,z)=>...
39
+
40
+ /** A function returning the shape of a cell.
41
+ * @type {function(import("../Dataset").Cell):import("../Style").Shape} */
42
+ this.shape = opts.shape || (() => 'square')
43
+ }
44
+
45
+ /**
46
+ * Draw cells as squares, with various colors and size.
47
+ *
48
+ * @param {Array.<import("../Dataset").Cell>} cells
49
+ * @param {number} r
50
+ * @param {import("../GeoCanvas").GeoCanvas} cg
51
+ */
52
+ draw(cells, r, cg) {
53
+ //filter
54
+ if (this.filter) cells = cells.filter(this.filter)
55
+
56
+ //zoom factor
57
+ const zf = cg.getZf()
58
+
59
+ let statColor
60
+ if (this.strokeColorCol) statColor = Style.getStatistics(cells, (c) => c[this.strokeColorCol], true)
61
+
62
+ let statSize
63
+ if (this.sizeCol) statSize = Style.getStatistics(cells, (c) => c[this.sizeCol], true)
64
+
65
+ let statWidth
66
+ if (this.strokeWidthCol) statWidth = Style.getStatistics(cells, (c) => c[this.strokeWidthCol], true)
67
+
68
+ //draw with HTML canvas
69
+ //in geo coordinates
70
+ cg.setCanvasTransform()
71
+
72
+ const r2 = r * 0.5
73
+ for (let cell of cells) {
74
+ //color
75
+ const col = this.strokeColor
76
+ ? this.strokeColor(cell[this.strokeColorCol], r, statColor)
77
+ : undefined
78
+ if (!col || col === 'none') continue
79
+ cg.ctx.strokeStyle = col
80
+
81
+ //size
82
+ /** @type {function(number,number,import("../Style").Stat|undefined,number):number} */
83
+ let s_ = this.size || (() => r)
84
+ //size - in geo unit
85
+ const sG = s_(cell[this.sizeCol], r, statSize, zf)
86
+
87
+ //width
88
+ const wi = this.strokeWidth
89
+ ? this.strokeWidth(cell[this.strokeWidthCol], r, statWidth, zf)
90
+ : 1 * zf
91
+ if (!wi || wi <= 0) continue
92
+ cg.ctx.lineWidth = wi
93
+
94
+ //shape
95
+ const shape = this.shape ? this.shape(cell) : 'square'
96
+ if (shape === 'none') continue
97
+
98
+ //get offset
99
+ const offset = this.offset(cell, r, zf)
100
+
101
+ if (shape === 'square') {
102
+ //draw square
103
+ const d = r * (1 - sG / r) * 0.5
104
+ cg.ctx.beginPath()
105
+ cg.ctx.rect(cell.x + d + offset.dx, cell.y + d + offset.dy, sG, sG)
106
+ cg.ctx.stroke()
107
+ } else if (shape === 'circle') {
108
+ //draw circle
109
+ cg.ctx.beginPath()
110
+ cg.ctx.arc(cell.x + r2 + offset.dx, cell.y + r2 + offset.dy, sG * 0.5, 0, 2 * Math.PI, false)
111
+ cg.ctx.stroke()
112
+ } else if (shape === 'diamond') {
113
+ const s2 = sG * 0.5
114
+ cg.ctx.beginPath()
115
+ cg.ctx.moveTo(cell.x + r2 - s2, cell.y + r2)
116
+ cg.ctx.lineTo(cell.x + r2, cell.y + r2 + s2)
117
+ cg.ctx.lineTo(cell.x + r2 + s2, cell.y + r2)
118
+ cg.ctx.lineTo(cell.x + r2, cell.y + r2 - s2)
119
+ cg.ctx.lineTo(cell.x + r2 - s2, cell.y + r2)
120
+ cg.ctx.stroke()
121
+ } else if (shape === 'donut') {
122
+ console.error('Not implemented')
123
+ } else {
124
+ throw new Error('Unexpected shape:' + shape)
125
+ }
126
+ }
127
+
128
+ //update legends
129
+ //this.updateLegends({ style: this, r: resolution, zf: zf, sSize: statSize, sColor: statColor });
130
+ }
131
+ }
@@ -1,160 +1,160 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { SquareColorWGLStyle } from './SquareColorWGLStyle.js'
5
- import { SideStyle } from './SideStyle.js'
6
-
7
- /**
8
- *
9
- * @see https://manifold.net/doc/mfd9/example__tanaka_contours.htm
10
- *
11
- * @author Julien Gaffuri
12
- */
13
- export class TanakaStyle {
14
- /**
15
- * @param {string} col
16
- * @param {object} opts
17
- * @returns {Array.<import("../Style").Style>}
18
- */
19
- static get(col, opts) {
20
- opts = opts || {}
21
-
22
- //get colors from d3 ramps, if 'nb' is specified
23
- if (opts.nb != undefined) {
24
- if (opts.nb < 2) {
25
- console.error('unexpected number of colors in tanaka (<2): ' + opts.nb)
26
- opts.nb = 2
27
- }
28
- if (!opts.color) {
29
- console.error('color function not defined in tanaka')
30
- opts.color = () => 'gray'
31
- }
32
- opts.colors = []
33
- for (let i = 0; i < opts.nb; i++) opts.colors.push(opts.color(i / (opts.nb - 1)))
34
- }
35
-
36
- /**
37
- * The colors.
38
- * @type {Array.<string>} */
39
- opts.colors = opts.colors || ['#a9bb9e', '#c9dcaa', '#fde89f', '#f9a579', '#eb444b']
40
- const nb = opts.colors.length
41
-
42
- /** A function to compute 't' from the value v
43
- * @type {function(number,number,import("../Style").Stat):number} */
44
- opts.tFun = opts.tFun || ((v, r, s) => (v - s.min) / (s.max - s.min))
45
-
46
- //shadow colors
47
- opts.colDark = opts.colDark || '#111'
48
- opts.colBright = opts.colBright || '#ddd'
49
-
50
- //width of the segment (share of the resolution)
51
- opts.widthFactor = opts.widthFactor || 0.08
52
-
53
- //shading
54
- opts.newShading = opts.newShading
55
- opts.newShadingWidthPix = opts.newShadingWidthPix || 2
56
- //transparency value, within [0,1]
57
- opts.newShadingTr =
58
- opts.newShadingTr ||
59
- ((sideValue, sideStat) =>
60
- Math.abs(sideValue) / Math.max(Math.abs(sideStat.min), Math.abs(sideStat.max)))
61
-
62
- /**
63
- * @param {number} t A cell t value, within [0,1].
64
- * @returns the class number for the value
65
- */
66
- const getClass = (t) => {
67
- if (isNaN(t) || t == undefined) {
68
- console.error('Unexpected t value 1: ' + t)
69
- return -9
70
- }
71
- for (let i = 0; i < nb; i++) if (t <= (i + 1) / nb) return i
72
- console.error('Unexpected t value 2: ' + t)
73
- return -9
74
- }
75
-
76
- const colStyle = new SquareColorWGLStyle({
77
- colorCol: col,
78
- colors: opts.colors,
79
- tFun: (v, r, s) => {
80
- const t = opts.tFun(v, r, s)
81
- const c = getClass(t)
82
- return c / (nb - 1)
83
- },
84
- //stretching: { fun: "expRev", alpha: -7 },
85
- size: (r, zf) => r + 0.5 * zf, //that is to ensure no gap between same class cells is visible
86
- filter: opts.filter,
87
- })
88
-
89
- /*
90
- if no web gl:
91
- const colStyle = new ShapeColorSizeStyle({
92
- colorCol: col,
93
- //the color corresponding to the class
94
- color: (v, r, s, zf) => {
95
- if (v == 0 && opts.tFun && isNaN(opts.tFun(v, r, s)))
96
- return undefined
97
- return opts.colors[getClass(opts.tFun ? opts.tFun(v, r, s) : v)]
98
- },
99
- shape: () => "square",
100
- size: (v, r, s, zf) => r + 0.5 * zf, //that is to ensure no gap between same class cells is visible
101
- })
102
- */
103
-
104
- /** The side style, for the shadow effect */
105
- const sideStyle = new SideStyle({
106
- valueCol: col,
107
- value: (v1, v2, r, s, zf) => {
108
- //compute the number of classes of difference
109
- if (v1 === undefined && v2 === undefined) return 0
110
- else if (v2 === undefined) {
111
- const t = opts.tFun(v1, r, s)
112
- if (t == undefined || isNaN(t)) throw new Error('Unexpected value: ' + v1 + ' - ' + t)
113
- const c = getClass(t)
114
- return c + 1
115
- } else if (v1 === undefined) {
116
- const t = opts.tFun(v2, r, s)
117
- if (t == undefined || isNaN(t)) throw new Error('Unexpected value: ' + v2 + ' - ' + t)
118
- const c = getClass(t)
119
- return -c - 1
120
- }
121
- const t1 = opts.tFun(v1, r, s)
122
- if (t1 == undefined || isNaN(t1)) throw new Error('Unexpected value: ' + v1 + ' - ' + t1)
123
- const t2 = opts.tFun(v2, r, s)
124
- if (t2 == undefined || isNaN(t2)) throw new Error('Unexpected value: ' + v2 + ' - ' + t2)
125
- const c1 = getClass(t1)
126
- const c2 = getClass(t2)
127
- return -c2 + c1
128
- },
129
-
130
- color: opts.newShading
131
- ? //black with transparency depending on difference
132
- (side, r, s, z) => {
133
- const tr = opts.newShadingTr(side.value, s)
134
- return (side.value > 0 && side.or === 'h') || (side.value < 0 && side.or === 'v')
135
- ? 'rgba(255,255,100,' + tr + ')'
136
- : 'rgba(0,0,0,' + tr + ')'
137
- }
138
- : //white or black, depending on orientation and value
139
- (side, r, s, z) => {
140
- if (side.value === 0) return
141
- //return "gray"
142
- if (side.or === 'v') return side.value < 0 ? opts.colBright : opts.colDark
143
- return side.value < 0 ? opts.colDark : opts.colBright
144
- },
145
-
146
- width: opts.newShading
147
- ? //fill size
148
- (side, r, s, z) => {
149
- return opts.newShadingWidthPix * z
150
- }
151
- : //width depends on the value, that is the number of classes of difference
152
- (side, r, s, z) =>
153
- opts.widthFactor * r * Math.abs(side.value) * (side.or === 'v' ? 0.5 : 1),
154
-
155
- filter: opts.filter,
156
- })
157
-
158
- return [colStyle, sideStyle]
159
- }
160
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { SquareColorWGLStyle } from './SquareColorWGLStyle.js'
5
+ import { SideStyle } from './SideStyle.js'
6
+
7
+ /**
8
+ *
9
+ * @see https://manifold.net/doc/mfd9/example__tanaka_contours.htm
10
+ *
11
+ * @author Julien Gaffuri
12
+ */
13
+ export class TanakaStyle {
14
+ /**
15
+ * @param {string} col
16
+ * @param {object} opts
17
+ * @returns {Array.<import("../Style").Style>}
18
+ */
19
+ static get(col, opts) {
20
+ opts = opts || {}
21
+
22
+ //get colors from d3 ramps, if 'nb' is specified
23
+ if (opts.nb != undefined) {
24
+ if (opts.nb < 2) {
25
+ console.error('unexpected number of colors in tanaka (<2): ' + opts.nb)
26
+ opts.nb = 2
27
+ }
28
+ if (!opts.color) {
29
+ console.error('color function not defined in tanaka')
30
+ opts.color = () => 'gray'
31
+ }
32
+ opts.colors = []
33
+ for (let i = 0; i < opts.nb; i++) opts.colors.push(opts.color(i / (opts.nb - 1)))
34
+ }
35
+
36
+ /**
37
+ * The colors.
38
+ * @type {Array.<string>} */
39
+ opts.colors = opts.colors || ['#a9bb9e', '#c9dcaa', '#fde89f', '#f9a579', '#eb444b']
40
+ const nb = opts.colors.length
41
+
42
+ /** A function to compute 't' from the value v
43
+ * @type {function(number,number,import("../Style").Stat):number} */
44
+ opts.tFun = opts.tFun || ((v, r, s) => (v - s.min) / (s.max - s.min))
45
+
46
+ //shadow colors
47
+ opts.colDark = opts.colDark || '#111'
48
+ opts.colBright = opts.colBright || '#ddd'
49
+
50
+ //width of the segment (share of the resolution)
51
+ opts.widthFactor = opts.widthFactor || 0.08
52
+
53
+ //shading
54
+ opts.newShading = opts.newShading
55
+ opts.newShadingWidthPix = opts.newShadingWidthPix || 2
56
+ //transparency value, within [0,1]
57
+ opts.newShadingTr =
58
+ opts.newShadingTr ||
59
+ ((sideValue, sideStat) =>
60
+ Math.abs(sideValue) / Math.max(Math.abs(sideStat.min), Math.abs(sideStat.max)))
61
+
62
+ /**
63
+ * @param {number} t A cell t value, within [0,1].
64
+ * @returns the class number for the value
65
+ */
66
+ const getClass = (t) => {
67
+ if (isNaN(t) || t == undefined) {
68
+ console.error('Unexpected t value 1: ' + t)
69
+ return -9
70
+ }
71
+ for (let i = 0; i < nb; i++) if (t <= (i + 1) / nb) return i
72
+ console.error('Unexpected t value 2: ' + t)
73
+ return -9
74
+ }
75
+
76
+ const colStyle = new SquareColorWGLStyle({
77
+ colorCol: col,
78
+ colors: opts.colors,
79
+ tFun: (v, r, s) => {
80
+ const t = opts.tFun(v, r, s)
81
+ const c = getClass(t)
82
+ return c / (nb - 1)
83
+ },
84
+ //stretching: { fun: "expRev", alpha: -7 },
85
+ size: (r, zf) => r + 0.5 * zf, //that is to ensure no gap between same class cells is visible
86
+ filter: opts.filter,
87
+ })
88
+
89
+ /*
90
+ if no web gl:
91
+ const colStyle = new ShapeColorSizeStyle({
92
+ colorCol: col,
93
+ //the color corresponding to the class
94
+ color: (v, r, s, zf) => {
95
+ if (v == 0 && opts.tFun && isNaN(opts.tFun(v, r, s)))
96
+ return undefined
97
+ return opts.colors[getClass(opts.tFun ? opts.tFun(v, r, s) : v)]
98
+ },
99
+ shape: () => "square",
100
+ size: (v, r, s, zf) => r + 0.5 * zf, //that is to ensure no gap between same class cells is visible
101
+ })
102
+ */
103
+
104
+ /** The side style, for the shadow effect */
105
+ const sideStyle = new SideStyle({
106
+ valueCol: col,
107
+ value: (v1, v2, r, s, zf) => {
108
+ //compute the number of classes of difference
109
+ if (v1 === undefined && v2 === undefined) return 0
110
+ else if (v2 === undefined) {
111
+ const t = opts.tFun(v1, r, s)
112
+ if (t == undefined || isNaN(t)) throw new Error('Unexpected value: ' + v1 + ' - ' + t)
113
+ const c = getClass(t)
114
+ return c + 1
115
+ } else if (v1 === undefined) {
116
+ const t = opts.tFun(v2, r, s)
117
+ if (t == undefined || isNaN(t)) throw new Error('Unexpected value: ' + v2 + ' - ' + t)
118
+ const c = getClass(t)
119
+ return -c - 1
120
+ }
121
+ const t1 = opts.tFun(v1, r, s)
122
+ if (t1 == undefined || isNaN(t1)) throw new Error('Unexpected value: ' + v1 + ' - ' + t1)
123
+ const t2 = opts.tFun(v2, r, s)
124
+ if (t2 == undefined || isNaN(t2)) throw new Error('Unexpected value: ' + v2 + ' - ' + t2)
125
+ const c1 = getClass(t1)
126
+ const c2 = getClass(t2)
127
+ return -c2 + c1
128
+ },
129
+
130
+ color: opts.newShading
131
+ ? //black with transparency depending on difference
132
+ (side, r, s, z) => {
133
+ const tr = opts.newShadingTr(side.value, s)
134
+ return (side.value > 0 && side.or === 'h') || (side.value < 0 && side.or === 'v')
135
+ ? 'rgba(255,255,100,' + tr + ')'
136
+ : 'rgba(0,0,0,' + tr + ')'
137
+ }
138
+ : //white or black, depending on orientation and value
139
+ (side, r, s, z) => {
140
+ if (side.value === 0) return
141
+ //return "gray"
142
+ if (side.or === 'v') return side.value < 0 ? opts.colBright : opts.colDark
143
+ return side.value < 0 ? opts.colDark : opts.colBright
144
+ },
145
+
146
+ width: opts.newShading
147
+ ? //fill size
148
+ (side, r, s, z) => {
149
+ return opts.newShadingWidthPix * z
150
+ }
151
+ : //width depends on the value, that is the number of classes of difference
152
+ (side, r, s, z) =>
153
+ opts.widthFactor * r * Math.abs(side.value) * (side.or === 'v' ? 0.5 : 1),
154
+
155
+ filter: opts.filter,
156
+ })
157
+
158
+ return [colStyle, sideStyle]
159
+ }
160
+ }