gridviz 3.0.15 → 3.0.17

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 +127 -128
  2. package/dist/gridviz.js +7958 -7861
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/ZoomButtons.js +101 -96
  6. package/src/core/Dataset.js +154 -157
  7. package/src/core/Drawable.js +60 -61
  8. package/src/core/GeoCanvas.js +409 -370
  9. package/src/core/Layer.js +23 -25
  10. package/src/core/Legend.js +108 -110
  11. package/src/core/Map.js +494 -495
  12. package/src/core/MultiResolutionDataset.js +93 -97
  13. package/src/core/Style.js +98 -99
  14. package/src/dataset/CSVGrid.js +112 -112
  15. package/src/dataset/GeoTIFF.js +122 -123
  16. package/src/dataset/JSGrid.js +55 -54
  17. package/src/dataset/TiledGrid.js +289 -288
  18. package/src/dataset/worker.js +18 -0
  19. package/src/index.js +77 -71
  20. package/src/layer/BackgroundLayer.js +162 -158
  21. package/src/layer/BackgroundLayerImage.js +81 -84
  22. package/src/layer/BackgroundLayerWMS.js +104 -108
  23. package/src/layer/GeoJSONLayer.js +214 -220
  24. package/src/layer/GridLayer.js +148 -157
  25. package/src/layer/LabelLayer.js +194 -193
  26. package/src/legend/ColorCategoryLegend.js +109 -110
  27. package/src/legend/ColorDiscreteLegend.js +100 -102
  28. package/src/legend/ColorLegend.js +115 -118
  29. package/src/legend/OrientationLegend.js +89 -91
  30. package/src/legend/SizeLegend.js +224 -224
  31. package/src/legend/TernaryLegend.js +302 -210
  32. package/src/style/CompositionStyle.js +291 -288
  33. package/src/style/DotDensityStyle.js +133 -134
  34. package/src/style/ImageStyle.js +100 -102
  35. package/src/style/IsoFenceStyle.js +217 -203
  36. package/src/style/JoyPlotStyle.js +127 -128
  37. package/src/style/LegoStyle.js +110 -110
  38. package/src/style/MosaicStyle.js +99 -99
  39. package/src/style/NinjaStarStyle.js +102 -102
  40. package/src/style/PillarStyle.js +207 -208
  41. package/src/style/SegmentStyle.js +105 -105
  42. package/src/style/ShapeColorSizeStyle.js +147 -132
  43. package/src/style/SideCategoryStyle.js +112 -114
  44. package/src/style/SideStyle.js +212 -205
  45. package/src/style/SquareColorCategoryWebGLStyle.js +107 -108
  46. package/src/style/SquareColorWebGLStyle.js +126 -126
  47. package/src/style/StrokeStyle.js +135 -136
  48. package/src/style/TanakaStyle.js +69 -68
  49. package/src/style/TextStyle.js +110 -111
  50. package/src/style/TimeSeriesStyle.js +222 -229
  51. package/src/utils/scale.js +218 -228
  52. package/src/utils/stretching.js +120 -133
  53. package/src/utils/ternary.js +203 -204
  54. package/src/utils/utils.js +58 -63
  55. package/src/utils/webGLUtils.js +72 -70
@@ -1,203 +1,217 @@
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
- * @module style
11
- * @author Julien Gaffuri
12
- */
13
- export class IsoFenceStyle extends Style {
14
-
15
- /** @param {object} opts */
16
- constructor(opts) {
17
- super(opts)
18
- opts = opts || {}
19
-
20
- /**
21
- * The dictionary (string -> color) which give the color of each category.
22
- * @type {object} */
23
- this.color = opts.color
24
-
25
- /** A function returning the height of a cell in geographical unit.
26
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
27
- this.height = opts.height || ((cell, resolution, z, viewScale) => resolution * 0.4)
28
-
29
- /** The perspective angle, in degree, within [-180,180], from [O,x] axis.
30
- * @type {number} */
31
- this.angle = opts.angle != undefined ? opts.angle : 50
32
-
33
- /** A function returning the corner line stroke style.
34
- * @type {function(import('../core/Dataset.js').Cell,number,number,number):string} */
35
- this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r, z, angle) => "#999")
36
-
37
- /** A function returning the corner line width.
38
- * @type {function(import('../core/Dataset.js').Cell,number,number,number):number} */
39
- this.cornerLineWidth = opts.cornerLineWidth || ((c, r, z, angle) => (angle % 90 == 0 ? 0 : 0.8 * z))
40
-
41
- /**
42
- * Show vertical cross-sections.
43
- * @type {boolean} */
44
- this.sVert = opts.sVert != undefined ? opts.sVert : true
45
-
46
- /**
47
- * Show horizontal cross-sections.
48
- * @type {boolean} */
49
- this.sHor = opts.sHor != undefined ? opts.sHor : true
50
- }
51
-
52
- /**
53
- * @param {Array.<import("../core/Dataset.js").Cell>} cells
54
- * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
55
- * @param {number} resolution
56
- * @override
57
- */
58
- draw(cells, geoCanvas, resolution) {
59
-
60
- //filter
61
- if (this.filter) cells = cells.filter(this.filter)
62
-
63
- //
64
- const z = geoCanvas.view.z
65
-
66
- //get view scale
67
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
68
-
69
- //nb categories - used for radar and agepyramid
70
- const cats = Object.keys(this.color)
71
-
72
- //half resolution
73
- const r2 = resolution / 2
74
-
75
- //get offset
76
- // @ts-ignore
77
- const offset = this.offset(undefined, resolution, z), dx = offset.dx, dy = offset.dy
78
-
79
- //make sides
80
- /** @type {Array.<Side>} */
81
- const sides = SideStyle.buildSides(cells, resolution, this.angle % 180 != 90 && this.sVert, this.angle % 180 != 0 && this.sHor)
82
-
83
- //
84
- if (sides.length == 0) return
85
-
86
- //angle in radians
87
- const aRad = this.angle * Math.PI / 180, cos = Math.cos(aRad), sin = Math.sin(aRad)
88
-
89
- //sort sides so that the back ones are drawn first. This depends on the angle.
90
- //depending on distance to the reference corner point
91
- const xCorner = Math.abs(this.angle) < 90 ? geoCanvas.extGeo.xMin : geoCanvas.extGeo.xMax
92
- const yCorner = this.angle < 0 ? geoCanvas.extGeo.yMax : geoCanvas.extGeo.yMin
93
- sides.sort((s1, s2) => (Math.hypot(s2.x - xCorner, s2.y - yCorner) - Math.hypot(s1.x - xCorner, s1.y - yCorner)))
94
-
95
- //prepare function to draw corner line for a cell *c*
96
- const drawCornerLine = (cell) => {
97
-
98
- if (!cell) return
99
- //line style
100
- const lw = this.cornerLineWidth ? this.cornerLineWidth(cell, resolution, z, this.angle) : 0.8 * z
101
- if (lw == 0) return
102
- geoCanvas.ctx.strokeStyle = this.cornerLineStrokeColor ? this.cornerLineStrokeColor(cell, resolution, z, this.angle) : "#333"
103
- geoCanvas.ctx.lineWidth = lw
104
-
105
- //height - in geo
106
- const hG = this.height(cell, resolution, z, viewScale)
107
-
108
- //draw line
109
- geoCanvas.ctx.beginPath()
110
- geoCanvas.ctx.moveTo(cell.x + r2 + dx, cell.y + r2 + dy)
111
- geoCanvas.ctx.lineTo(cell.x + r2 + hG * cos + dx, cell.y + r2 + hG * sin + dy)
112
- geoCanvas.ctx.stroke()
113
- }
114
-
115
- //draw sides
116
- geoCanvas.ctx.lineCap = "round";
117
- for (let side of sides) {
118
- const c1 = side.c1, c2 = side.c2, x = side.x, y = side.y
119
-
120
- //heights - in geo
121
- const hG1 = c1 ? this.height(c1, resolution, z, viewScale) : 0,
122
- hG2 = c2 ? this.height(c2, resolution, z, viewScale) : 0
123
-
124
- //compute totals for both cells
125
- const total1 = computeTotal(c1, cats),
126
- total2 = computeTotal(c2, cats)
127
- if (total1 == 0 && total2 == 0) continue
128
-
129
- let cumul1 = 0, cumul2 = 0
130
- for (let [column, color] of Object.entries(this.color)) {
131
- //draw stripe of side s and category column
132
-
133
- //get values for both cells
134
- let v1 = c1 ? +c1[column] : 0
135
- let v2 = c2 ? +c2[column] : 0
136
- if (v1 == 0 && v2 == 0) continue
137
-
138
- //compute heights
139
- const h1 = hG1 * cumul1 / total1 || 0
140
- const h1n = hG1 * (cumul1 + v1) / total1 || 0
141
- const h2 = hG2 * cumul2 / total2 || 0
142
- const h2n = hG2 * (cumul2 + v2) / total2 || 0
143
-
144
- //make path
145
- geoCanvas.ctx.beginPath()
146
- if (side.or == "h") {
147
- //horizontal side - vertical section
148
- //bottom left
149
- geoCanvas.ctx.moveTo(x + h1 * cos + dx, y - r2 + h1 * sin + dy)
150
- //top left
151
- geoCanvas.ctx.lineTo(x + h2 * cos + dx, y + r2 + h2 * sin + dy)
152
- //top right
153
- geoCanvas.ctx.lineTo(x + h2n * cos + dx, y + r2 + h2n * sin + dy)
154
- //bottom right
155
- geoCanvas.ctx.lineTo(x + h1n * cos + dx, y - r2 + h1n * sin + dy)
156
- } else {
157
- //vertical side - horizontal section
158
- //bottom left
159
- geoCanvas.ctx.moveTo(x - r2 + h1 * cos + dx, y + h1 * sin + dy)
160
- //bottom right
161
- geoCanvas.ctx.lineTo(x + r2 + h2 * cos + dx, y + h2 * sin + dy)
162
- //top right
163
- geoCanvas.ctx.lineTo(x + r2 + h2n * cos + dx, y + h2n * sin + dy)
164
- //top left
165
- geoCanvas.ctx.lineTo(x - r2 + h1n * cos + dx, y + h1n * sin + dy)
166
- }
167
- //cg.ctx.closePath()
168
-
169
- //fill
170
- geoCanvas.ctx.fillStyle = color
171
- geoCanvas.ctx.fill()
172
-
173
- cumul1 += v1
174
- cumul2 += v2
175
-
176
- //TODO draw only one line
177
- //draw corner line
178
- //if (side.or == "h") {
179
- drawCornerLine(c1)
180
- drawCornerLine(c2)
181
- //if (this.angle > 0 && side.or == "h") drawCornerLine(c2)
182
- //else drawCornerLine(c2)
183
- //}
184
- }
185
- }
186
-
187
- //update legends
188
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
189
- }
190
- }
191
-
192
-
193
-
194
- const computeTotal = (cell, categories) => {
195
- if (!cell) return 0
196
- let total = 0
197
- for (let column of categories) {
198
- const v = cell[column]
199
- if (!v) continue
200
- total += +v
201
- }
202
- return total || 0
203
- }
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
+ * @module style
11
+ * @author Julien Gaffuri
12
+ */
13
+ export class IsoFenceStyle extends Style {
14
+ /** @param {object} opts */
15
+ constructor(opts) {
16
+ super(opts)
17
+ opts = opts || {}
18
+
19
+ /**
20
+ * The dictionary (string -> color) which give the color of each category.
21
+ * @type {object} */
22
+ this.color = opts.color
23
+
24
+ /** A function returning the height of a cell in geographical unit.
25
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
26
+ this.height = opts.height || ((cell, resolution, z, viewScale) => resolution * 0.4)
27
+
28
+ /** The perspective angle, in degree, within [-180,180], from [O,x] axis.
29
+ * @type {number} */
30
+ this.angle = opts.angle != undefined ? opts.angle : 50
31
+
32
+ /** A function returning the corner line stroke style.
33
+ * @type {function(import('../core/Dataset.js').Cell,number,number,number):string} */
34
+ this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r, z, angle) => '#999')
35
+
36
+ /** A function returning the corner line width.
37
+ * @type {function(import('../core/Dataset.js').Cell,number,number,number):number} */
38
+ this.cornerLineWidth = opts.cornerLineWidth || ((c, r, z, angle) => (angle % 90 == 0 ? 0 : 0.8 * z))
39
+
40
+ /**
41
+ * Show vertical cross-sections.
42
+ * @type {boolean} */
43
+ this.sVert = opts.sVert != undefined ? opts.sVert : true
44
+
45
+ /**
46
+ * Show horizontal cross-sections.
47
+ * @type {boolean} */
48
+ this.sHor = opts.sHor != undefined ? opts.sHor : true
49
+ }
50
+
51
+ /**
52
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
53
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
54
+ * @param {number} resolution
55
+ * @override
56
+ */
57
+ draw(cells, geoCanvas, resolution) {
58
+ //filter
59
+ if (this.filter) cells = cells.filter(this.filter)
60
+
61
+ //
62
+ const z = geoCanvas.view.z
63
+ const ctx = geoCanvas.offscreenCtx
64
+
65
+ //get view scale
66
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
67
+
68
+ //nb categories - used for radar and agepyramid
69
+ const cats = Object.keys(this.color)
70
+
71
+ //half resolution
72
+ const r2 = resolution / 2
73
+
74
+ //get offset
75
+ // @ts-ignore
76
+ const offset = this.offset(undefined, resolution, z),
77
+ dx = offset.dx,
78
+ dy = offset.dy
79
+
80
+ //make sides
81
+ /** @type {Array.<Side>} */
82
+ const sides = SideStyle.buildSides(
83
+ cells,
84
+ resolution,
85
+ this.angle % 180 != 90 && this.sVert,
86
+ this.angle % 180 != 0 && this.sHor
87
+ )
88
+
89
+ //
90
+ if (sides.length == 0) return
91
+
92
+ //angle in radians
93
+ const aRad = (this.angle * Math.PI) / 180,
94
+ cos = Math.cos(aRad),
95
+ sin = Math.sin(aRad)
96
+
97
+ //sort sides so that the back ones are drawn first. This depends on the angle.
98
+ //depending on distance to the reference corner point
99
+ const xCorner = Math.abs(this.angle) < 90 ? geoCanvas.extGeo.xMin : geoCanvas.extGeo.xMax
100
+ const yCorner = this.angle < 0 ? geoCanvas.extGeo.yMax : geoCanvas.extGeo.yMin
101
+ sides.sort(
102
+ (s1, s2) =>
103
+ Math.hypot(s2.x - xCorner, s2.y - yCorner) - Math.hypot(s1.x - xCorner, s1.y - yCorner)
104
+ )
105
+
106
+ //prepare function to draw corner line for a cell *c*
107
+ const drawCornerLine = (cell) => {
108
+ if (!cell) return
109
+ //line style
110
+ const lw = this.cornerLineWidth ? this.cornerLineWidth(cell, resolution, z, this.angle) : 0.8 * z
111
+ if (lw == 0) return
112
+ ctx.strokeStyle = this.cornerLineStrokeColor
113
+ ? this.cornerLineStrokeColor(cell, resolution, z, this.angle)
114
+ : '#333'
115
+ ctx.lineWidth = lw
116
+
117
+ //height - in geo
118
+ const hG = this.height(cell, resolution, z, viewScale)
119
+
120
+ //draw line
121
+ ctx.beginPath()
122
+ ctx.moveTo(cell.x + r2 + dx, cell.y + r2 + dy)
123
+ ctx.lineTo(cell.x + r2 + hG * cos + dx, cell.y + r2 + hG * sin + dy)
124
+ ctx.stroke()
125
+ }
126
+
127
+ //draw sides
128
+ ctx.lineCap = 'round'
129
+ for (let side of sides) {
130
+ const c1 = side.c1,
131
+ c2 = side.c2,
132
+ x = side.x,
133
+ y = side.y
134
+
135
+ //heights - in geo
136
+ const hG1 = c1 ? this.height(c1, resolution, z, viewScale) : 0,
137
+ hG2 = c2 ? this.height(c2, resolution, z, viewScale) : 0
138
+
139
+ //compute totals for both cells
140
+ const total1 = computeTotal(c1, cats),
141
+ total2 = computeTotal(c2, cats)
142
+ if (total1 == 0 && total2 == 0) continue
143
+
144
+ let cumul1 = 0,
145
+ cumul2 = 0
146
+ for (let [column, color] of Object.entries(this.color)) {
147
+ //draw stripe of side s and category column
148
+
149
+ //get values for both cells
150
+ let v1 = c1 ? +c1[column] : 0
151
+ let v2 = c2 ? +c2[column] : 0
152
+ if (v1 == 0 && v2 == 0) continue
153
+
154
+ //compute heights
155
+ const h1 = (hG1 * cumul1) / total1 || 0
156
+ const h1n = (hG1 * (cumul1 + v1)) / total1 || 0
157
+ const h2 = (hG2 * cumul2) / total2 || 0
158
+ const h2n = (hG2 * (cumul2 + v2)) / total2 || 0
159
+
160
+ //make path
161
+ ctx.beginPath()
162
+ if (side.or == 'h') {
163
+ //horizontal side - vertical section
164
+ //bottom left
165
+ ctx.moveTo(x + h1 * cos + dx, y - r2 + h1 * sin + dy)
166
+ //top left
167
+ ctx.lineTo(x + h2 * cos + dx, y + r2 + h2 * sin + dy)
168
+ //top right
169
+ ctx.lineTo(x + h2n * cos + dx, y + r2 + h2n * sin + dy)
170
+ //bottom right
171
+ ctx.lineTo(x + h1n * cos + dx, y - r2 + h1n * sin + dy)
172
+ } else {
173
+ //vertical side - horizontal section
174
+ //bottom left
175
+ ctx.moveTo(x - r2 + h1 * cos + dx, y + h1 * sin + dy)
176
+ //bottom right
177
+ ctx.lineTo(x + r2 + h2 * cos + dx, y + h2 * sin + dy)
178
+ //top right
179
+ ctx.lineTo(x + r2 + h2n * cos + dx, y + h2n * sin + dy)
180
+ //top left
181
+ ctx.lineTo(x - r2 + h1n * cos + dx, y + h1n * sin + dy)
182
+ }
183
+ //cg.ctx.closePath()
184
+
185
+ //fill
186
+ ctx.fillStyle = color
187
+ ctx.fill()
188
+
189
+ cumul1 += v1
190
+ cumul2 += v2
191
+
192
+ //TODO draw only one line
193
+ //draw corner line
194
+ //if (side.or == "h") {
195
+ drawCornerLine(c1)
196
+ drawCornerLine(c2)
197
+ //if (this.angle > 0 && side.or == "h") drawCornerLine(c2)
198
+ //else drawCornerLine(c2)
199
+ //}
200
+ }
201
+ }
202
+
203
+ //update legends
204
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
205
+ }
206
+ }
207
+
208
+ const computeTotal = (cell, categories) => {
209
+ if (!cell) return 0
210
+ let total = 0
211
+ for (let column of categories) {
212
+ const v = cell[column]
213
+ if (!v) continue
214
+ total += +v
215
+ }
216
+ return total || 0
217
+ }