gridviz 2.0.45 → 2.0.46

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 (53) hide show
  1. package/README.md +119 -119
  2. package/dist/gridviz.js +6937 -6937
  3. package/package.json +76 -76
  4. package/src/App.js +668 -668
  5. package/src/BackgroundLayer.js +182 -182
  6. package/src/BackgroundLayerWMS.js +131 -131
  7. package/src/Dataset.js +76 -76
  8. package/src/DatasetComponent.js +101 -101
  9. package/src/GeoCanvas.js +420 -420
  10. package/src/LabelLayer.js +190 -190
  11. package/src/Layer.js +92 -92
  12. package/src/Legend.js +86 -86
  13. package/src/LineLayer.js +150 -150
  14. package/src/Style.js +114 -114
  15. package/src/Tooltip.js +172 -172
  16. package/src/dataset/COGeo.js +24 -24
  17. package/src/dataset/CSVGrid.js +104 -104
  18. package/src/dataset/GeoTIFF.js +127 -127
  19. package/src/dataset/GridTile.js +41 -41
  20. package/src/dataset/TiledGrid.js +264 -264
  21. package/src/index.js +177 -176
  22. package/src/legend/ColorCategoryLegend.js +124 -124
  23. package/src/legend/ColorDiscreteLegend.js +103 -103
  24. package/src/legend/ColorLegend.js +124 -124
  25. package/src/legend/SegmentOrientationLegend.js +87 -87
  26. package/src/legend/SegmentWidthLegend.js +97 -97
  27. package/src/legend/SizeLegend.js +141 -141
  28. package/src/style/CompositionStyle.js +300 -300
  29. package/src/style/ContourStyle.js +54 -54
  30. package/src/style/DotDensityStyle.js +156 -156
  31. package/src/style/JoyPlotStyle.js +135 -135
  32. package/src/style/LegoStyle.js +112 -112
  33. package/src/style/MosaicStyle.js +107 -107
  34. package/src/style/NinjaStarStyle.js +124 -124
  35. package/src/style/PillarStyle.js +230 -230
  36. package/src/style/SegmentStyle.js +142 -142
  37. package/src/style/ShapeColorSizeStyle.js +126 -126
  38. package/src/style/SideCatStyle.js +172 -172
  39. package/src/style/SideStyle.js +218 -218
  40. package/src/style/SquareColorCatWGLStyle.js +120 -120
  41. package/src/style/SquareColorWGLStyle.js +146 -146
  42. package/src/style/StrokeStyle.js +131 -131
  43. package/src/style/TanakaStyle.js +160 -160
  44. package/src/style/TextStyle.js +132 -132
  45. package/src/utils/Utils.js +35 -35
  46. package/src/utils/WebGLRectangleColoring.js +106 -106
  47. package/src/utils/WebGLSquareColoring.js +118 -118
  48. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  49. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  50. package/src/utils/WebGLSquareColoringKS.js +153 -153
  51. package/src/utils/stretching.js +131 -131
  52. package/src/utils/webGLUtils.js +71 -71
  53. package/src/utils/zoomUtils.js +142 -142
@@ -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
+ }