gridviz 2.1.7 → 2.1.9
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/README.md +125 -124
- package/dist/gridviz.js +8021 -7991
- package/dist/gridviz.min.js +1 -1
- package/package.json +77 -77
- package/src/App.js +705 -705
- package/src/BackgroundLayer.js +182 -182
- package/src/BackgroundLayerWMS.js +131 -131
- package/src/Dataset.js +76 -76
- package/src/DatasetComponent.js +101 -101
- package/src/GeoCanvas.js +420 -420
- package/src/LabelLayer.js +190 -190
- package/src/Layer.js +103 -103
- package/src/Legend.js +86 -86
- package/src/LineLayer.js +150 -150
- package/src/Style.js +129 -129
- package/src/Tooltip.js +180 -172
- package/src/dataset/COGeo.js +24 -24
- package/src/dataset/CSVGrid.js +104 -104
- package/src/dataset/GeoTIFF.js +127 -127
- package/src/dataset/GridTile.js +41 -41
- package/src/dataset/LGrid.js +54 -54
- package/src/dataset/TiledGrid.js +264 -264
- package/src/index.js +71 -71
- package/src/legend/ColorCategoryLegend.js +124 -124
- package/src/legend/ColorDiscreteLegend.js +103 -103
- package/src/legend/ColorLegend.js +124 -124
- package/src/legend/SegmentOrientationLegend.js +87 -87
- package/src/legend/SegmentWidthLegend.js +97 -97
- package/src/legend/SizeLegend.js +141 -141
- package/src/style/CompositionStyle.js +300 -300
- package/src/style/ContourStyle.js +54 -54
- package/src/style/DotDensityStyle.js +156 -156
- package/src/style/IsoFenceStyle.js +262 -240
- package/src/style/JoyPlotStyle.js +135 -135
- package/src/style/LegoStyle.js +112 -112
- package/src/style/MosaicStyle.js +107 -107
- package/src/style/NinjaStarStyle.js +125 -125
- package/src/style/PillarStyle.js +230 -230
- package/src/style/SegmentStyle.js +142 -142
- package/src/style/ShapeColorSizeStyle.js +126 -126
- package/src/style/SideCatStyle.js +172 -172
- package/src/style/SideStyle.js +216 -216
- package/src/style/SquareColorCatWGLStyle.js +120 -120
- package/src/style/SquareColorWGLStyle.js +146 -146
- package/src/style/StrokeStyle.js +131 -131
- package/src/style/TanakaStyle.js +160 -160
- package/src/style/TextStyle.js +132 -132
- package/src/style/TimeSeriesStyle.js +250 -250
- package/src/utils/Utils.js +35 -35
- package/src/utils/WebGLRectangleColoring.js +106 -106
- package/src/utils/WebGLSquareColoring.js +118 -118
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
- package/src/utils/WebGLSquareColoringKS.js +153 -153
- package/src/utils/stretching.js +131 -131
- package/src/utils/webGLUtils.js +71 -71
- package/src/utils/zoomUtils.js +142 -142
|
@@ -1,240 +1,262 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Style } from '../Style.js'
|
|
5
|
-
|
|
6
|
-
/** @typedef {{x:number,y:number,or:"v"|"h",c1:import('../Dataset.js').Cell|undefined,c2:import('../Dataset.js').Cell|undefined}} Side */
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @author Julien Gaffuri
|
|
10
|
-
*/
|
|
11
|
-
export class IsoFenceStyle extends Style {
|
|
12
|
-
|
|
13
|
-
/** @param {object} opts */
|
|
14
|
-
constructor(opts) {
|
|
15
|
-
super(opts)
|
|
16
|
-
opts = opts || {}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* The dictionary (string -> color) which give the color of each category.
|
|
20
|
-
* @type {object} */
|
|
21
|
-
this.color = opts.color
|
|
22
|
-
|
|
23
|
-
/** The column where to get the height values.
|
|
24
|
-
* @type {string} */
|
|
25
|
-
this.heightCol = opts.heightCol
|
|
26
|
-
|
|
27
|
-
/** A function returning the height of a cell.
|
|
28
|
-
* @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
29
|
-
this.height = opts.height || ((v, r, s, zf) => r * 0.4)
|
|
30
|
-
|
|
31
|
-
/** The perspective angle.
|
|
32
|
-
* @type {number} */
|
|
33
|
-
this.angle = opts.angle != undefined ? opts.angle :
|
|
34
|
-
|
|
35
|
-
/** A function returning the corner line stroke style.
|
|
36
|
-
* @type {function(import('../Dataset.js').Cell,number,number,number):string} */
|
|
37
|
-
this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r, zf, angle) => "#999")
|
|
38
|
-
|
|
39
|
-
/** A function returning the corner line width.
|
|
40
|
-
* @type {function(import('../Dataset.js').Cell,number,number,number):number} */
|
|
41
|
-
this.cornerLineWidth = opts.cornerLineWidth || ((c, r, zf, angle) => (angle % 90 == 0 ? 0 : 0.8 * zf))
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
c1 =
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../Style.js'
|
|
5
|
+
|
|
6
|
+
/** @typedef {{x:number,y:number,or:"v"|"h",c1:import('../Dataset.js').Cell|undefined,c2:import('../Dataset.js').Cell|undefined}} Side */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @author Julien Gaffuri
|
|
10
|
+
*/
|
|
11
|
+
export class IsoFenceStyle extends Style {
|
|
12
|
+
|
|
13
|
+
/** @param {object} opts */
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super(opts)
|
|
16
|
+
opts = opts || {}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The dictionary (string -> color) which give the color of each category.
|
|
20
|
+
* @type {object} */
|
|
21
|
+
this.color = opts.color
|
|
22
|
+
|
|
23
|
+
/** The column where to get the height values.
|
|
24
|
+
* @type {string} */
|
|
25
|
+
this.heightCol = opts.heightCol
|
|
26
|
+
|
|
27
|
+
/** A function returning the height of a cell.
|
|
28
|
+
* @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
29
|
+
this.height = opts.height || ((v, r, s, zf) => r * 0.4)
|
|
30
|
+
|
|
31
|
+
/** The perspective angle.
|
|
32
|
+
* @type {number} */
|
|
33
|
+
this.angle = opts.angle != undefined ? opts.angle : 50
|
|
34
|
+
|
|
35
|
+
/** A function returning the corner line stroke style.
|
|
36
|
+
* @type {function(import('../Dataset.js').Cell,number,number,number):string} */
|
|
37
|
+
this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r, zf, angle) => "#999")
|
|
38
|
+
|
|
39
|
+
/** A function returning the corner line width.
|
|
40
|
+
* @type {function(import('../Dataset.js').Cell,number,number,number):number} */
|
|
41
|
+
this.cornerLineWidth = opts.cornerLineWidth || ((c, r, zf, angle) => (angle % 90 == 0 ? 0 : 0.8 * zf))
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Show vertical cross-sections.
|
|
45
|
+
* @type {boolean} */
|
|
46
|
+
this.sVert = opts.sVert != undefined ? opts.sVert : true
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Show horizontal cross-sections.
|
|
50
|
+
* @type {boolean} */
|
|
51
|
+
this.sHor = opts.sHor != undefined ? opts.sHor : true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Draw cells as segments.
|
|
56
|
+
*
|
|
57
|
+
* @param {Array.<import("../Dataset.js").Cell>} cells
|
|
58
|
+
* @param {number} r
|
|
59
|
+
* @param {import("../GeoCanvas.js").GeoCanvas} cg
|
|
60
|
+
*/
|
|
61
|
+
draw(cells, r, cg) {
|
|
62
|
+
//filter
|
|
63
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
64
|
+
|
|
65
|
+
//zoom factor
|
|
66
|
+
const zf = cg.getZf()
|
|
67
|
+
|
|
68
|
+
let stat
|
|
69
|
+
if (this.heightCol) {
|
|
70
|
+
//if size is used, sort cells by size so that the biggest are drawn first
|
|
71
|
+
cells.sort((c1, c2) => c2[this.heightCol] - c1[this.heightCol])
|
|
72
|
+
//and compute statistics
|
|
73
|
+
stat = Style.getStatistics(cells, (c) => c[this.heightCol], true)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//nb categories - used for radar and agepyramid
|
|
77
|
+
const cats = Object.keys(this.color)
|
|
78
|
+
|
|
79
|
+
//draw in geo coordinates
|
|
80
|
+
cg.setCanvasTransform()
|
|
81
|
+
|
|
82
|
+
//half resolution
|
|
83
|
+
const r2 = r / 2
|
|
84
|
+
|
|
85
|
+
//get offset
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
const offset = this.offset(undefined, r, zf), dx = offset.dx, dy = offset.dy
|
|
88
|
+
|
|
89
|
+
//height
|
|
90
|
+
/** @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
91
|
+
let h_ = this.height
|
|
92
|
+
|
|
93
|
+
//make sides
|
|
94
|
+
/** @type {Array.<Side>} */
|
|
95
|
+
const sides = []
|
|
96
|
+
|
|
97
|
+
//make horizontal sides - except when angle%180=0
|
|
98
|
+
//sort cells by x and y
|
|
99
|
+
if (this.angle % 180 != 90 && this.sVert) {
|
|
100
|
+
cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
|
|
101
|
+
let c1 = cells[0]
|
|
102
|
+
for (let i = 1; i < cells.length; i++) {
|
|
103
|
+
let c2 = cells[i]
|
|
104
|
+
|
|
105
|
+
if ((c1.y + r == c2.y) && (c1.x == c2.x))
|
|
106
|
+
//cells in same column and touch along horizontal side
|
|
107
|
+
//make shared side
|
|
108
|
+
sides.push({ x: c1.x + r2, y: c2.y, or: 'h', c1: c1, c2: c2 })
|
|
109
|
+
else {
|
|
110
|
+
//cells do not touch along horizontal side
|
|
111
|
+
//make two sides: top one for c1, bottom for c2
|
|
112
|
+
sides.push({ x: c1.x + r2, y: c1.y + r, or: 'h', c1: c1, c2: undefined })
|
|
113
|
+
sides.push({ x: c2.x + r2, y: c2.y, or: 'h', c1: undefined, c2: c2 })
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
c1 = c2
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//make vertical sides - except when angle%180=90
|
|
121
|
+
//sort cells by y and x
|
|
122
|
+
if (this.angle % 180 != 0 && this.sHor) {
|
|
123
|
+
cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
|
|
124
|
+
let c1 = cells[0]
|
|
125
|
+
for (let i = 1; i < cells.length; i++) {
|
|
126
|
+
let c2 = cells[i]
|
|
127
|
+
|
|
128
|
+
if ((c1.x + r == c2.x) && (c1.y == c2.y))
|
|
129
|
+
//cells in same row and touch along vertical side
|
|
130
|
+
//make shared side
|
|
131
|
+
sides.push({ x: c2.x, y: c1.y + r2, or: 'v', c1: c1, c2: c2 })
|
|
132
|
+
else {
|
|
133
|
+
//cells do not touch along vertical side
|
|
134
|
+
//make two sides: right one for c1, left for c2
|
|
135
|
+
sides.push({ x: c1.x + r, y: c1.y + r2, or: 'v', c1: c1, c2: undefined })
|
|
136
|
+
sides.push({ x: c2.x, y: c2.y + r2, or: 'v', c1: undefined, c2: c2 })
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
c1 = c2
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
//
|
|
144
|
+
if (sides.length == 0) return
|
|
145
|
+
|
|
146
|
+
//angle in radians
|
|
147
|
+
const aRad = this.angle * Math.PI / 180, cos = Math.cos(aRad), sin = Math.sin(aRad)
|
|
148
|
+
|
|
149
|
+
//draw in geo coordinates
|
|
150
|
+
cg.setCanvasTransform()
|
|
151
|
+
|
|
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
|
+
//draw sides
|
|
164
|
+
for (let s of sides) {
|
|
165
|
+
|
|
166
|
+
//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
|
|
171
|
+
|
|
172
|
+
//compute totals for both cells
|
|
173
|
+
const total1 = computeTotal(s.c1, cats)
|
|
174
|
+
const total2 = computeTotal(s.c2, cats)
|
|
175
|
+
if (total1 == 0 && total2 == 0) continue
|
|
176
|
+
|
|
177
|
+
let cumul1 = 0, cumul2 = 0
|
|
178
|
+
for (let [column, color] of Object.entries(this.color)) {
|
|
179
|
+
//draw stripe of side s and category column
|
|
180
|
+
|
|
181
|
+
//get values for both cells
|
|
182
|
+
let v1 = s.c1 ? +s.c1[column] : 0
|
|
183
|
+
let v2 = s.c2 ? +s.c2[column] : 0
|
|
184
|
+
if (v1 == 0 && v2 == 0) continue
|
|
185
|
+
|
|
186
|
+
//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
|
|
191
|
+
|
|
192
|
+
//make path
|
|
193
|
+
cg.ctx.beginPath()
|
|
194
|
+
if (s.or == "h") {
|
|
195
|
+
//horizontal side - vertical section
|
|
196
|
+
//bottom left
|
|
197
|
+
cg.ctx.moveTo(s.x + h1 * cos + dx, s.y - r2 + h1 * sin + dy)
|
|
198
|
+
//top left
|
|
199
|
+
cg.ctx.lineTo(s.x + h2 * cos + dx, s.y + r2 + h2 * sin + dy)
|
|
200
|
+
//top right
|
|
201
|
+
cg.ctx.lineTo(s.x + h2n * cos + dx, s.y + r2 + h2n * sin + dy)
|
|
202
|
+
//bottom right
|
|
203
|
+
cg.ctx.lineTo(s.x + h1n * cos + dx, s.y - r2 + h1n * sin + dy)
|
|
204
|
+
} else {
|
|
205
|
+
//vertical side - horizontal section
|
|
206
|
+
//bottom left
|
|
207
|
+
cg.ctx.moveTo(s.x - r2 + h1 * cos + dx, s.y + h1 * sin + dy)
|
|
208
|
+
//bottom right
|
|
209
|
+
cg.ctx.lineTo(s.x + r2 + h2 * cos + dx, s.y + h2 * sin + dy)
|
|
210
|
+
//top right
|
|
211
|
+
cg.ctx.lineTo(s.x + r2 + h2n * cos + dx, s.y + h2n * sin + dy)
|
|
212
|
+
//top left
|
|
213
|
+
cg.ctx.lineTo(s.x - r2 + h1n * cos + dx, s.y + h1n * sin + dy)
|
|
214
|
+
}
|
|
215
|
+
cg.ctx.closePath()
|
|
216
|
+
|
|
217
|
+
//fill
|
|
218
|
+
cg.ctx.fillStyle = color
|
|
219
|
+
cg.ctx.fill()
|
|
220
|
+
|
|
221
|
+
cumul1 += v1
|
|
222
|
+
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
|
+
|
|
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()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//update legends
|
|
247
|
+
this.updateLegends({ style: this, r: r, zf: zf, sSize: stat })
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
const computeTotal = (cell, categories) => {
|
|
254
|
+
if (!cell) return 0
|
|
255
|
+
let total = 0
|
|
256
|
+
for (let column of categories) {
|
|
257
|
+
const v = cell[column]
|
|
258
|
+
if (!v) continue
|
|
259
|
+
total += +v
|
|
260
|
+
}
|
|
261
|
+
return total || 0
|
|
262
|
+
}
|