gridviz 2.1.8 → 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 -125
- package/dist/gridviz.js +8021 -8013
- 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 -262
- 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
package/src/style/SideStyle.js
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Style } from '../Style.js'
|
|
5
|
-
|
|
6
|
-
/** @typedef {{x:number,y:number,or:"v"|"h",value:number}} Side */
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* @author Julien Gaffuri
|
|
11
|
-
*/
|
|
12
|
-
export class SideStyle extends Style {
|
|
13
|
-
/** @param {object} opts */
|
|
14
|
-
constructor(opts) {
|
|
15
|
-
super(opts)
|
|
16
|
-
opts = opts || {}
|
|
17
|
-
|
|
18
|
-
/** The name of the column/attribute of the tabular data where to retrieve the variable for the cell values.
|
|
19
|
-
* @type {string} */
|
|
20
|
-
this.valueCol = opts.valueCol
|
|
21
|
-
|
|
22
|
-
/** A function returning the value of a cell side. This value is computed from the two adjacent cell values.
|
|
23
|
-
* For horizontal sides, v1 is the value of the cell below and v2 the value of the cell above.
|
|
24
|
-
* For vertical sides, v1 is the value of the cell left and v2 the value of the cell right.
|
|
25
|
-
* @type {function(number|undefined,number|undefined,number,import("../Style").Stat|undefined,number):number} */
|
|
26
|
-
this.value = opts.value || ((v1, v2, r, s, zf) => 1)
|
|
27
|
-
|
|
28
|
-
/** A function returning the color of a cell side.
|
|
29
|
-
* @type {function(Side,number,import("../Style").Stat|undefined,number):string} */
|
|
30
|
-
this.color = opts.color || (() => '#EA6BAC')
|
|
31
|
-
|
|
32
|
-
/** A function returning the width of a cell side, in geo unit
|
|
33
|
-
* @type {function(Side,number,import("../Style").Stat|undefined,number):number} */
|
|
34
|
-
this.width = opts.width || ((side, r, s, zf) => (r * side.value) / 5)
|
|
35
|
-
|
|
36
|
-
/** orientation. Set to 90 to show sides as slope lines for example.
|
|
37
|
-
* @type {number} */
|
|
38
|
-
this.orientation = opts.orientation || 0
|
|
39
|
-
|
|
40
|
-
/** A fill color for the cells.
|
|
41
|
-
* @type {function(import("../Dataset").Cell):string} */
|
|
42
|
-
this.fillColor = opts.fillColor
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {Array.<import("../Dataset").Cell>} cells
|
|
47
|
-
* @param {number} r
|
|
48
|
-
* @param {import("../GeoCanvas").GeoCanvas} cg
|
|
49
|
-
*/
|
|
50
|
-
draw(cells, r, cg) {
|
|
51
|
-
//filter
|
|
52
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
53
|
-
|
|
54
|
-
//zoom factor
|
|
55
|
-
const zf = cg.getZf()
|
|
56
|
-
|
|
57
|
-
//compute stats on cell values
|
|
58
|
-
let statValue
|
|
59
|
-
if (this.valueCol) {
|
|
60
|
-
//compute color variable statistics
|
|
61
|
-
statValue = Style.getStatistics(cells, (c) => c[this.valueCol], true)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** @type {Array.<Side>} */
|
|
65
|
-
const sides = []
|
|
66
|
-
|
|
67
|
-
//make horizontal sides
|
|
68
|
-
//sort cells by x and y
|
|
69
|
-
cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
|
|
70
|
-
let c1 = cells[0]
|
|
71
|
-
for (let i = 1; i < cells.length; i++) {
|
|
72
|
-
let c2 = cells[i]
|
|
73
|
-
|
|
74
|
-
if ((c1.y + r == c2.y) && (c1.x == c2.x))
|
|
75
|
-
//cells in same column and touch along horizontal side
|
|
76
|
-
//make shared side
|
|
77
|
-
sides.push({
|
|
78
|
-
x: c1.x,
|
|
79
|
-
y: c2.y,
|
|
80
|
-
or: 'h',
|
|
81
|
-
value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
|
|
82
|
-
})
|
|
83
|
-
else {
|
|
84
|
-
//cells do not touch along horizontal side
|
|
85
|
-
//make two sides: top one for c1, bottom for c2
|
|
86
|
-
sides.push({
|
|
87
|
-
x: c1.x,
|
|
88
|
-
y: c1.y + r,
|
|
89
|
-
or: 'h',
|
|
90
|
-
value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
|
|
91
|
-
})
|
|
92
|
-
sides.push({
|
|
93
|
-
x: c2.x,
|
|
94
|
-
y: c2.y,
|
|
95
|
-
or: 'h',
|
|
96
|
-
value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
c1 = c2
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
//make vertical sides
|
|
104
|
-
//sort cells by y and x
|
|
105
|
-
cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
|
|
106
|
-
c1 = cells[0]
|
|
107
|
-
for (let i = 1; i < cells.length; i++) {
|
|
108
|
-
let c2 = cells[i]
|
|
109
|
-
|
|
110
|
-
if ((c1.x + r == c2.x) && (c1.y == c2.y))
|
|
111
|
-
//cells in same row and touch along vertical side
|
|
112
|
-
//make shared side
|
|
113
|
-
sides.push({
|
|
114
|
-
x: c1.x + r,
|
|
115
|
-
y: c1.y,
|
|
116
|
-
or: 'v',
|
|
117
|
-
value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
|
|
118
|
-
})
|
|
119
|
-
else {
|
|
120
|
-
//cells do not touch along vertical side
|
|
121
|
-
//make two sides: right one for c1, left for c2
|
|
122
|
-
sides.push({
|
|
123
|
-
x: c1.x + r,
|
|
124
|
-
y: c1.y,
|
|
125
|
-
or: 'v',
|
|
126
|
-
value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
|
|
127
|
-
})
|
|
128
|
-
sides.push({
|
|
129
|
-
x: c2.x,
|
|
130
|
-
y: c2.y,
|
|
131
|
-
or: 'v',
|
|
132
|
-
value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
c1 = c2
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
//
|
|
140
|
-
if (sides.length == 0) return
|
|
141
|
-
|
|
142
|
-
//compute stats on sides
|
|
143
|
-
const statSides = SideStyle.getSideStatistics(sides, true)
|
|
144
|
-
|
|
145
|
-
//draw in geo coordinates
|
|
146
|
-
cg.setCanvasTransform()
|
|
147
|
-
|
|
148
|
-
//draw cells, if fillColor specified
|
|
149
|
-
if (this.fillColor)
|
|
150
|
-
for (let c of cells) {
|
|
151
|
-
const fc = this.fillColor(c)
|
|
152
|
-
if (!fc || fc == 'none') continue
|
|
153
|
-
cg.ctx.fillStyle = fc
|
|
154
|
-
cg.ctx.fillRect(c.x, c.y, r, r)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
//draw sides
|
|
158
|
-
cg.ctx.lineCap = 'butt'
|
|
159
|
-
const r2 = r / 2
|
|
160
|
-
for (let s of sides) {
|
|
161
|
-
//color
|
|
162
|
-
/** @type {string|undefined} */
|
|
163
|
-
const col = this.color ? this.color(s, r, statSides, zf) : undefined
|
|
164
|
-
if (!col || col == 'none') continue
|
|
165
|
-
|
|
166
|
-
//width
|
|
167
|
-
/** @type {number|undefined} */
|
|
168
|
-
const wG = this.width ? this.width(s, r, statSides, zf) : undefined
|
|
169
|
-
if (!wG || wG <= 0) continue
|
|
170
|
-
|
|
171
|
-
//set color and width
|
|
172
|
-
cg.ctx.strokeStyle = col
|
|
173
|
-
cg.ctx.lineWidth = wG
|
|
174
|
-
|
|
175
|
-
//draw segment with correct orientation
|
|
176
|
-
cg.ctx.beginPath()
|
|
177
|
-
if (this.orientation == 90) {
|
|
178
|
-
cg.ctx.moveTo(s.x + r2, s.y + r2)
|
|
179
|
-
if (s.or === 'h') cg.ctx.lineTo(s.x + r2, s.y - r2)
|
|
180
|
-
else cg.ctx.lineTo(s.x - r2, s.y + r2)
|
|
181
|
-
} else {
|
|
182
|
-
cg.ctx.moveTo(s.x, s.y)
|
|
183
|
-
cg.ctx.lineTo(s.x + (s.or === 'h' ? r : 0), s.y + (s.or === 'v' ? r : 0))
|
|
184
|
-
}
|
|
185
|
-
cg.ctx.stroke()
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
//update legends
|
|
189
|
-
this.updateLegends({ style: this, r: r, zf: zf })
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Compute some statistics on a value of some sides.
|
|
194
|
-
* This is used to define how to draw specifically the sides within the view.
|
|
195
|
-
*
|
|
196
|
-
* @param {Array.<Side>} sides
|
|
197
|
-
* @param {boolean} ignoreZeros
|
|
198
|
-
* @returns {import("../Style").Stat | undefined}
|
|
199
|
-
*/
|
|
200
|
-
static getSideStatistics(sides, ignoreZeros) {
|
|
201
|
-
if (!sides || sides.length == 0) return undefined
|
|
202
|
-
let min = Infinity
|
|
203
|
-
let max = -Infinity
|
|
204
|
-
//let sum = 0
|
|
205
|
-
//let nb = 0
|
|
206
|
-
for (const s of sides) {
|
|
207
|
-
const v = s.value
|
|
208
|
-
if (ignoreZeros && !v) continue
|
|
209
|
-
if (v < min) min = v
|
|
210
|
-
if (v > max) max = v
|
|
211
|
-
//sum += v
|
|
212
|
-
//nb++
|
|
213
|
-
}
|
|
214
|
-
return { min: min, max: max }
|
|
215
|
-
}
|
|
216
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../Style.js'
|
|
5
|
+
|
|
6
|
+
/** @typedef {{x:number,y:number,or:"v"|"h",value:number}} Side */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @author Julien Gaffuri
|
|
11
|
+
*/
|
|
12
|
+
export class SideStyle extends Style {
|
|
13
|
+
/** @param {object} opts */
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super(opts)
|
|
16
|
+
opts = opts || {}
|
|
17
|
+
|
|
18
|
+
/** The name of the column/attribute of the tabular data where to retrieve the variable for the cell values.
|
|
19
|
+
* @type {string} */
|
|
20
|
+
this.valueCol = opts.valueCol
|
|
21
|
+
|
|
22
|
+
/** A function returning the value of a cell side. This value is computed from the two adjacent cell values.
|
|
23
|
+
* For horizontal sides, v1 is the value of the cell below and v2 the value of the cell above.
|
|
24
|
+
* For vertical sides, v1 is the value of the cell left and v2 the value of the cell right.
|
|
25
|
+
* @type {function(number|undefined,number|undefined,number,import("../Style").Stat|undefined,number):number} */
|
|
26
|
+
this.value = opts.value || ((v1, v2, r, s, zf) => 1)
|
|
27
|
+
|
|
28
|
+
/** A function returning the color of a cell side.
|
|
29
|
+
* @type {function(Side,number,import("../Style").Stat|undefined,number):string} */
|
|
30
|
+
this.color = opts.color || (() => '#EA6BAC')
|
|
31
|
+
|
|
32
|
+
/** A function returning the width of a cell side, in geo unit
|
|
33
|
+
* @type {function(Side,number,import("../Style").Stat|undefined,number):number} */
|
|
34
|
+
this.width = opts.width || ((side, r, s, zf) => (r * side.value) / 5)
|
|
35
|
+
|
|
36
|
+
/** orientation. Set to 90 to show sides as slope lines for example.
|
|
37
|
+
* @type {number} */
|
|
38
|
+
this.orientation = opts.orientation || 0
|
|
39
|
+
|
|
40
|
+
/** A fill color for the cells.
|
|
41
|
+
* @type {function(import("../Dataset").Cell):string} */
|
|
42
|
+
this.fillColor = opts.fillColor
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {Array.<import("../Dataset").Cell>} cells
|
|
47
|
+
* @param {number} r
|
|
48
|
+
* @param {import("../GeoCanvas").GeoCanvas} cg
|
|
49
|
+
*/
|
|
50
|
+
draw(cells, r, cg) {
|
|
51
|
+
//filter
|
|
52
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
53
|
+
|
|
54
|
+
//zoom factor
|
|
55
|
+
const zf = cg.getZf()
|
|
56
|
+
|
|
57
|
+
//compute stats on cell values
|
|
58
|
+
let statValue
|
|
59
|
+
if (this.valueCol) {
|
|
60
|
+
//compute color variable statistics
|
|
61
|
+
statValue = Style.getStatistics(cells, (c) => c[this.valueCol], true)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @type {Array.<Side>} */
|
|
65
|
+
const sides = []
|
|
66
|
+
|
|
67
|
+
//make horizontal sides
|
|
68
|
+
//sort cells by x and y
|
|
69
|
+
cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
|
|
70
|
+
let c1 = cells[0]
|
|
71
|
+
for (let i = 1; i < cells.length; i++) {
|
|
72
|
+
let c2 = cells[i]
|
|
73
|
+
|
|
74
|
+
if ((c1.y + r == c2.y) && (c1.x == c2.x))
|
|
75
|
+
//cells in same column and touch along horizontal side
|
|
76
|
+
//make shared side
|
|
77
|
+
sides.push({
|
|
78
|
+
x: c1.x,
|
|
79
|
+
y: c2.y,
|
|
80
|
+
or: 'h',
|
|
81
|
+
value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
|
|
82
|
+
})
|
|
83
|
+
else {
|
|
84
|
+
//cells do not touch along horizontal side
|
|
85
|
+
//make two sides: top one for c1, bottom for c2
|
|
86
|
+
sides.push({
|
|
87
|
+
x: c1.x,
|
|
88
|
+
y: c1.y + r,
|
|
89
|
+
or: 'h',
|
|
90
|
+
value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
|
|
91
|
+
})
|
|
92
|
+
sides.push({
|
|
93
|
+
x: c2.x,
|
|
94
|
+
y: c2.y,
|
|
95
|
+
or: 'h',
|
|
96
|
+
value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
c1 = c2
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//make vertical sides
|
|
104
|
+
//sort cells by y and x
|
|
105
|
+
cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
|
|
106
|
+
c1 = cells[0]
|
|
107
|
+
for (let i = 1; i < cells.length; i++) {
|
|
108
|
+
let c2 = cells[i]
|
|
109
|
+
|
|
110
|
+
if ((c1.x + r == c2.x) && (c1.y == c2.y))
|
|
111
|
+
//cells in same row and touch along vertical side
|
|
112
|
+
//make shared side
|
|
113
|
+
sides.push({
|
|
114
|
+
x: c1.x + r,
|
|
115
|
+
y: c1.y,
|
|
116
|
+
or: 'v',
|
|
117
|
+
value: this.value(c1[this.valueCol], c2[this.valueCol], r, statValue, zf),
|
|
118
|
+
})
|
|
119
|
+
else {
|
|
120
|
+
//cells do not touch along vertical side
|
|
121
|
+
//make two sides: right one for c1, left for c2
|
|
122
|
+
sides.push({
|
|
123
|
+
x: c1.x + r,
|
|
124
|
+
y: c1.y,
|
|
125
|
+
or: 'v',
|
|
126
|
+
value: this.value(c1[this.valueCol], undefined, r, statValue, zf),
|
|
127
|
+
})
|
|
128
|
+
sides.push({
|
|
129
|
+
x: c2.x,
|
|
130
|
+
y: c2.y,
|
|
131
|
+
or: 'v',
|
|
132
|
+
value: this.value(undefined, c2[this.valueCol], r, statValue, zf),
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
c1 = c2
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
//
|
|
140
|
+
if (sides.length == 0) return
|
|
141
|
+
|
|
142
|
+
//compute stats on sides
|
|
143
|
+
const statSides = SideStyle.getSideStatistics(sides, true)
|
|
144
|
+
|
|
145
|
+
//draw in geo coordinates
|
|
146
|
+
cg.setCanvasTransform()
|
|
147
|
+
|
|
148
|
+
//draw cells, if fillColor specified
|
|
149
|
+
if (this.fillColor)
|
|
150
|
+
for (let c of cells) {
|
|
151
|
+
const fc = this.fillColor(c)
|
|
152
|
+
if (!fc || fc == 'none') continue
|
|
153
|
+
cg.ctx.fillStyle = fc
|
|
154
|
+
cg.ctx.fillRect(c.x, c.y, r, r)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//draw sides
|
|
158
|
+
cg.ctx.lineCap = 'butt'
|
|
159
|
+
const r2 = r / 2
|
|
160
|
+
for (let s of sides) {
|
|
161
|
+
//color
|
|
162
|
+
/** @type {string|undefined} */
|
|
163
|
+
const col = this.color ? this.color(s, r, statSides, zf) : undefined
|
|
164
|
+
if (!col || col == 'none') continue
|
|
165
|
+
|
|
166
|
+
//width
|
|
167
|
+
/** @type {number|undefined} */
|
|
168
|
+
const wG = this.width ? this.width(s, r, statSides, zf) : undefined
|
|
169
|
+
if (!wG || wG <= 0) continue
|
|
170
|
+
|
|
171
|
+
//set color and width
|
|
172
|
+
cg.ctx.strokeStyle = col
|
|
173
|
+
cg.ctx.lineWidth = wG
|
|
174
|
+
|
|
175
|
+
//draw segment with correct orientation
|
|
176
|
+
cg.ctx.beginPath()
|
|
177
|
+
if (this.orientation == 90) {
|
|
178
|
+
cg.ctx.moveTo(s.x + r2, s.y + r2)
|
|
179
|
+
if (s.or === 'h') cg.ctx.lineTo(s.x + r2, s.y - r2)
|
|
180
|
+
else cg.ctx.lineTo(s.x - r2, s.y + r2)
|
|
181
|
+
} else {
|
|
182
|
+
cg.ctx.moveTo(s.x, s.y)
|
|
183
|
+
cg.ctx.lineTo(s.x + (s.or === 'h' ? r : 0), s.y + (s.or === 'v' ? r : 0))
|
|
184
|
+
}
|
|
185
|
+
cg.ctx.stroke()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//update legends
|
|
189
|
+
this.updateLegends({ style: this, r: r, zf: zf })
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Compute some statistics on a value of some sides.
|
|
194
|
+
* This is used to define how to draw specifically the sides within the view.
|
|
195
|
+
*
|
|
196
|
+
* @param {Array.<Side>} sides
|
|
197
|
+
* @param {boolean} ignoreZeros
|
|
198
|
+
* @returns {import("../Style").Stat | undefined}
|
|
199
|
+
*/
|
|
200
|
+
static getSideStatistics(sides, ignoreZeros) {
|
|
201
|
+
if (!sides || sides.length == 0) return undefined
|
|
202
|
+
let min = Infinity
|
|
203
|
+
let max = -Infinity
|
|
204
|
+
//let sum = 0
|
|
205
|
+
//let nb = 0
|
|
206
|
+
for (const s of sides) {
|
|
207
|
+
const v = s.value
|
|
208
|
+
if (ignoreZeros && !v) continue
|
|
209
|
+
if (v < min) min = v
|
|
210
|
+
if (v > max) max = v
|
|
211
|
+
//sum += v
|
|
212
|
+
//nb++
|
|
213
|
+
}
|
|
214
|
+
return { min: min, max: max }
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Style } from '../Style.js'
|
|
5
|
-
import { makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
-
import { WebGLSquareColoringCatAdvanced } from '../utils/WebGLSquareColoringCatAdvanced.js'
|
|
7
|
-
import { monitor, monitorDuration } from '../utils/Utils.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Style based on webGL
|
|
11
|
-
* To show cells as colored squares, from categories.
|
|
12
|
-
* Alls squares with the same size
|
|
13
|
-
*
|
|
14
|
-
* @author Julien Gaffuri
|
|
15
|
-
*/
|
|
16
|
-
export class SquareColorCatWGLStyle extends Style {
|
|
17
|
-
/** @param {object} opts */
|
|
18
|
-
constructor(opts) {
|
|
19
|
-
super(opts)
|
|
20
|
-
opts = opts || {}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The name of the column/attribute of the tabular data where to retrieve the category of the cell, for coloring.
|
|
24
|
-
* @type {string} */
|
|
25
|
-
this.colorCol = opts.colorCol
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* The dictionary (string -> color) which give the color of each category.
|
|
29
|
-
* @type {object} */
|
|
30
|
-
opts.color = opts.color || undefined
|
|
31
|
-
|
|
32
|
-
/** @type { Array.<string> } @private */
|
|
33
|
-
const keys = Object.keys(opts.color)
|
|
34
|
-
|
|
35
|
-
/** @type { object } @private */
|
|
36
|
-
this.catToI = {}
|
|
37
|
-
for (let i = 0; i < keys.length; i++) this.catToI[keys[i]] = i + ''
|
|
38
|
-
|
|
39
|
-
/** @type { Array.<string> } @private */
|
|
40
|
-
this.colors = []
|
|
41
|
-
for (let i = 0; i < keys.length; i++) {
|
|
42
|
-
this.colors.push(opts.color['' + keys[i]])
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* A function returning the size of the cells, in geographical unit. All cells have the same size.
|
|
47
|
-
* @type {function(number,number):number} */
|
|
48
|
-
this.size = opts.size // (resolution, zf) => ...
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @private
|
|
52
|
-
* @type { WebGLSquareColoringCatAdvanced } */
|
|
53
|
-
this.wgp = new WebGLSquareColoringCatAdvanced(this.colors)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param {Array.<import("../Dataset").Cell>} cells
|
|
58
|
-
* @param {number} r
|
|
59
|
-
* @param {import("../GeoCanvas").GeoCanvas} cg
|
|
60
|
-
*/
|
|
61
|
-
draw(cells, r, cg) {
|
|
62
|
-
if (monitor) monitorDuration('*** SquareColorCatWGLStyle draw')
|
|
63
|
-
|
|
64
|
-
//filter
|
|
65
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
66
|
-
|
|
67
|
-
//zoom factor
|
|
68
|
-
const zf = cg.getZf()
|
|
69
|
-
|
|
70
|
-
//add vertice and fragment data
|
|
71
|
-
const r2 = r / 2
|
|
72
|
-
let c,
|
|
73
|
-
nb = cells.length
|
|
74
|
-
const verticesBuffer = []
|
|
75
|
-
const iBuffer = []
|
|
76
|
-
for (let i = 0; i < nb; i++) {
|
|
77
|
-
c = cells[i]
|
|
78
|
-
const cat = c[this.colorCol]
|
|
79
|
-
if (cat == undefined) {
|
|
80
|
-
console.log('Unexpected category: ' + cat)
|
|
81
|
-
continue
|
|
82
|
-
}
|
|
83
|
-
/** @type {number} */
|
|
84
|
-
const i_ = this.catToI[cat]
|
|
85
|
-
if (isNaN(+i_)) {
|
|
86
|
-
console.log('Unexpected category index: ' + cat + ' ' + i_)
|
|
87
|
-
continue
|
|
88
|
-
}
|
|
89
|
-
verticesBuffer.push(c.x + r2, c.y + r2)
|
|
90
|
-
iBuffer.push(+i_)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (monitor) monitorDuration(' webgl program inputs preparation')
|
|
94
|
-
|
|
95
|
-
//create canvas and webgl renderer
|
|
96
|
-
const cvWGL = makeWebGLCanvas(cg.w + '', cg.h + '')
|
|
97
|
-
if (!cvWGL) {
|
|
98
|
-
console.error('No webGL')
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
if (monitor) monitorDuration(' web GL canvas creation')
|
|
102
|
-
|
|
103
|
-
//draw
|
|
104
|
-
const sizeGeo = this.size ? this.size(r, zf) : r + 0.2 * zf
|
|
105
|
-
this.wgp.draw(cvWGL.gl, verticesBuffer, iBuffer, cg.getWebGLTransform(), sizeGeo / zf)
|
|
106
|
-
|
|
107
|
-
if (monitor) monitorDuration(' webgl drawing')
|
|
108
|
-
|
|
109
|
-
//draw in canvas geo
|
|
110
|
-
cg.initCanvasTransform()
|
|
111
|
-
cg.ctx.drawImage(cvWGL.canvas, 0, 0)
|
|
112
|
-
|
|
113
|
-
if (monitor) monitorDuration(' canvas drawing')
|
|
114
|
-
|
|
115
|
-
//update legends
|
|
116
|
-
this.updateLegends({ style: this, r: r, zf: zf })
|
|
117
|
-
|
|
118
|
-
if (monitor) monitorDuration('*** SquareColorCatWGLStyle end draw')
|
|
119
|
-
}
|
|
120
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../Style.js'
|
|
5
|
+
import { makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
+
import { WebGLSquareColoringCatAdvanced } from '../utils/WebGLSquareColoringCatAdvanced.js'
|
|
7
|
+
import { monitor, monitorDuration } from '../utils/Utils.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Style based on webGL
|
|
11
|
+
* To show cells as colored squares, from categories.
|
|
12
|
+
* Alls squares with the same size
|
|
13
|
+
*
|
|
14
|
+
* @author Julien Gaffuri
|
|
15
|
+
*/
|
|
16
|
+
export class SquareColorCatWGLStyle extends Style {
|
|
17
|
+
/** @param {object} opts */
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
super(opts)
|
|
20
|
+
opts = opts || {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The name of the column/attribute of the tabular data where to retrieve the category of the cell, for coloring.
|
|
24
|
+
* @type {string} */
|
|
25
|
+
this.colorCol = opts.colorCol
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The dictionary (string -> color) which give the color of each category.
|
|
29
|
+
* @type {object} */
|
|
30
|
+
opts.color = opts.color || undefined
|
|
31
|
+
|
|
32
|
+
/** @type { Array.<string> } @private */
|
|
33
|
+
const keys = Object.keys(opts.color)
|
|
34
|
+
|
|
35
|
+
/** @type { object } @private */
|
|
36
|
+
this.catToI = {}
|
|
37
|
+
for (let i = 0; i < keys.length; i++) this.catToI[keys[i]] = i + ''
|
|
38
|
+
|
|
39
|
+
/** @type { Array.<string> } @private */
|
|
40
|
+
this.colors = []
|
|
41
|
+
for (let i = 0; i < keys.length; i++) {
|
|
42
|
+
this.colors.push(opts.color['' + keys[i]])
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A function returning the size of the cells, in geographical unit. All cells have the same size.
|
|
47
|
+
* @type {function(number,number):number} */
|
|
48
|
+
this.size = opts.size // (resolution, zf) => ...
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @private
|
|
52
|
+
* @type { WebGLSquareColoringCatAdvanced } */
|
|
53
|
+
this.wgp = new WebGLSquareColoringCatAdvanced(this.colors)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {Array.<import("../Dataset").Cell>} cells
|
|
58
|
+
* @param {number} r
|
|
59
|
+
* @param {import("../GeoCanvas").GeoCanvas} cg
|
|
60
|
+
*/
|
|
61
|
+
draw(cells, r, cg) {
|
|
62
|
+
if (monitor) monitorDuration('*** SquareColorCatWGLStyle draw')
|
|
63
|
+
|
|
64
|
+
//filter
|
|
65
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
66
|
+
|
|
67
|
+
//zoom factor
|
|
68
|
+
const zf = cg.getZf()
|
|
69
|
+
|
|
70
|
+
//add vertice and fragment data
|
|
71
|
+
const r2 = r / 2
|
|
72
|
+
let c,
|
|
73
|
+
nb = cells.length
|
|
74
|
+
const verticesBuffer = []
|
|
75
|
+
const iBuffer = []
|
|
76
|
+
for (let i = 0; i < nb; i++) {
|
|
77
|
+
c = cells[i]
|
|
78
|
+
const cat = c[this.colorCol]
|
|
79
|
+
if (cat == undefined) {
|
|
80
|
+
console.log('Unexpected category: ' + cat)
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
/** @type {number} */
|
|
84
|
+
const i_ = this.catToI[cat]
|
|
85
|
+
if (isNaN(+i_)) {
|
|
86
|
+
console.log('Unexpected category index: ' + cat + ' ' + i_)
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
89
|
+
verticesBuffer.push(c.x + r2, c.y + r2)
|
|
90
|
+
iBuffer.push(+i_)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (monitor) monitorDuration(' webgl program inputs preparation')
|
|
94
|
+
|
|
95
|
+
//create canvas and webgl renderer
|
|
96
|
+
const cvWGL = makeWebGLCanvas(cg.w + '', cg.h + '')
|
|
97
|
+
if (!cvWGL) {
|
|
98
|
+
console.error('No webGL')
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
if (monitor) monitorDuration(' web GL canvas creation')
|
|
102
|
+
|
|
103
|
+
//draw
|
|
104
|
+
const sizeGeo = this.size ? this.size(r, zf) : r + 0.2 * zf
|
|
105
|
+
this.wgp.draw(cvWGL.gl, verticesBuffer, iBuffer, cg.getWebGLTransform(), sizeGeo / zf)
|
|
106
|
+
|
|
107
|
+
if (monitor) monitorDuration(' webgl drawing')
|
|
108
|
+
|
|
109
|
+
//draw in canvas geo
|
|
110
|
+
cg.initCanvasTransform()
|
|
111
|
+
cg.ctx.drawImage(cvWGL.canvas, 0, 0)
|
|
112
|
+
|
|
113
|
+
if (monitor) monitorDuration(' canvas drawing')
|
|
114
|
+
|
|
115
|
+
//update legends
|
|
116
|
+
this.updateLegends({ style: this, r: r, zf: zf })
|
|
117
|
+
|
|
118
|
+
if (monitor) monitorDuration('*** SquareColorCatWGLStyle end draw')
|
|
119
|
+
}
|
|
120
|
+
}
|