gridviz 3.0.23 → 3.0.24

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 (66) hide show
  1. package/README.md +128 -128
  2. package/dist/gridviz.js +8618 -8579
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/Button.js +67 -67
  6. package/src/button/FullscreenButton.js +121 -121
  7. package/src/button/ZoomButtons.js +103 -101
  8. package/src/core/Dataset.js +154 -154
  9. package/src/core/Drawable.js +78 -78
  10. package/src/core/GeoCanvas.js +437 -430
  11. package/src/core/Layer.js +23 -23
  12. package/src/core/Legend.js +108 -108
  13. package/src/core/Map.js +542 -516
  14. package/src/core/MultiResolutionDataset.js +93 -93
  15. package/src/core/Style.js +98 -98
  16. package/src/core/Tooltip.js +182 -182
  17. package/src/dataset/COGeo.js +25 -25
  18. package/src/dataset/CSVGrid.js +112 -112
  19. package/src/dataset/GeoTIFF.js +122 -122
  20. package/src/dataset/JSGrid.js +55 -55
  21. package/src/dataset/TiledGrid.js +302 -302
  22. package/src/dataset/worker.js +18 -18
  23. package/src/index.js +77 -77
  24. package/src/layer/BackgroundLayer.js +173 -173
  25. package/src/layer/BackgroundLayerImage.js +81 -81
  26. package/src/layer/BackgroundLayerWMS.js +104 -104
  27. package/src/layer/GeoJSONLayer.js +214 -214
  28. package/src/layer/GridLayer.js +148 -148
  29. package/src/layer/LabelLayer.js +194 -194
  30. package/src/legend/ColorCategoryLegend.js +109 -109
  31. package/src/legend/ColorDiscreteLegend.js +100 -100
  32. package/src/legend/ColorLegend.js +115 -115
  33. package/src/legend/OrientationLegend.js +89 -89
  34. package/src/legend/SizeLegend.js +224 -224
  35. package/src/legend/TernaryLegend.js +302 -302
  36. package/src/style/CompositionStyle.js +291 -291
  37. package/src/style/ContourStyle.js +21 -21
  38. package/src/style/DotDensityStyle.js +133 -133
  39. package/src/style/ImageStyle.js +100 -100
  40. package/src/style/IsoFenceStyle.js +217 -217
  41. package/src/style/JoyPlotStyle.js +127 -127
  42. package/src/style/LegoStyle.js +110 -110
  43. package/src/style/MosaicStyle.js +99 -99
  44. package/src/style/NinjaStarStyle.js +102 -102
  45. package/src/style/PillarStyle.js +207 -207
  46. package/src/style/SegmentStyle.js +105 -105
  47. package/src/style/ShapeColorSizeStyle.js +147 -147
  48. package/src/style/SideCategoryStyle.js +112 -112
  49. package/src/style/SideStyle.js +212 -212
  50. package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
  51. package/src/style/SquareColorWebGLStyle.js +126 -126
  52. package/src/style/StrokeStyle.js +135 -135
  53. package/src/style/TanakaStyle.js +69 -69
  54. package/src/style/TextStyle.js +110 -110
  55. package/src/style/TimeSeriesStyle.js +222 -222
  56. package/src/utils/WebGLRectangleColoring.js +106 -106
  57. package/src/utils/WebGLSquareColoring.js +118 -118
  58. package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
  59. package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
  60. package/src/utils/WebGLSquareColoringKS.js +153 -153
  61. package/src/utils/scale.js +218 -218
  62. package/src/utils/stretching.js +120 -120
  63. package/src/utils/ternary.js +208 -208
  64. package/src/utils/utils.js +58 -58
  65. package/src/utils/webGLUtils.js +72 -72
  66. package/src/utils/zoomUtils.js +142 -142
@@ -1,207 +1,207 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../core/Style.js'
5
-
6
- /**
7
- * @module style
8
- * @author Julien Gaffuri
9
- */
10
- export class PillarStyle extends Style {
11
- /** @param {object} opts */
12
- constructor(opts) {
13
- super(opts)
14
- opts = opts || {}
15
-
16
- /** A function returning the height of the line representing a cell, in geo unit
17
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
18
- this.height = opts.height
19
-
20
- /** A function returning the color of the line representing a cell.
21
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
22
- this.color = opts.color || (() => '#c08c59') //(c,r,z,vs) => {}
23
-
24
- /** A function returning the width of the line representing a cell, in geo unit
25
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
26
- this.width = opts.width || ((cell, resolution) => 0.5 * resolution)
27
-
28
- /** A function returning the width of the line representing a cell, in geo unit
29
- * @type {function(number, number,object):boolean} */
30
- this.simple = opts.simple || (() => false)
31
-
32
- /** @type {number} */
33
- this.viewHeightFactor = opts.viewHeightFactor || 1.5
34
- //0,0 is the center
35
- /** @type {number} */
36
- this.viewSX = opts.viewSX == undefined ? 0 : opts.viewSX
37
- /** @type {number} */
38
- this.viewSY = opts.viewSY == undefined ? -0.5 : opts.viewSY
39
-
40
- //TODO replace with sun location ?
41
- /** @type {number} */
42
- this.shadowDirection =
43
- opts.shadowDirection == undefined ? (-40.3 * Math.PI) / 180.0 : opts.shadowDirection
44
- /** @type {number} */
45
- this.shadowFactor = opts.shadowFactor || 0.3
46
- /** @type {string} */
47
- this.shadowColor = opts.shadowColor || '#00000033'
48
-
49
- /** @type {string} */
50
- this.outlineCol = opts.outlineCol || '#FFFFFF'
51
- /** @type {number} */
52
- this.outlineWidthPix = opts.outlineWidthPix == undefined ? 0.5 : opts.outlineWidthPix
53
- }
54
-
55
- /**
56
- * Draw cells as segments.
57
- *
58
- * @param {Array.<import("../core/Dataset").Cell>} cells
59
- * @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
60
- * @param {number} resolution
61
- */
62
- draw(cells, geoCanvas, resolution) {
63
- //filter
64
- if (this.filter) cells = cells.filter(this.filter)
65
-
66
- //
67
- const z = geoCanvas.view.z
68
- const ctx = geoCanvas.offscreenCtx
69
-
70
- //get view scale
71
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
72
-
73
- //get view center geo position
74
- const cvx = geoCanvas.view.x + this.viewSX * geoCanvas.w * z
75
- const cvy = geoCanvas.view.y + this.viewSY * geoCanvas.h * z
76
- //get view height
77
- const H = this.viewHeightFactor * (geoCanvas.w + geoCanvas.h) * 0.5 * z
78
-
79
- //sort cells by y and x
80
- //const distToViewCenter = (c) => { const dx = cvx - c.x, dy = cvy - c.y; return Math.sqrt(dx * dx + dy * dy) }
81
- cells.sort((c1, c2) => 100000000 * (c2.y - c1.y) + c1.x - c2.x)
82
-
83
- //get simple information
84
- const simple = this.simple(resolution, z, viewScale)
85
-
86
- ctx.lineCap = simple ? 'butt' : 'round'
87
-
88
- //draw shadows
89
- ctx.strokeStyle = this.shadowColor
90
- ctx.fillStyle = this.shadowColor
91
- for (let cell of cells) {
92
- //width
93
- /** @type {number|undefined} */
94
- const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
95
- if (!wG || wG < 0) continue
96
-
97
- //height
98
- /** @type {number|undefined} */
99
- const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
100
- if (!hG || hG < 0) continue
101
-
102
- //get offset
103
- //TODO use that
104
- //const offset = this.offset(c, resolution, z)
105
-
106
- //set width
107
- ctx.lineWidth = wG
108
-
109
- //compute cell center postition
110
- const cx = cell.x + resolution / 2
111
- const cy = cell.y + resolution / 2
112
- const ls = hG * this.shadowFactor
113
-
114
- //draw segment
115
- ctx.beginPath()
116
- ctx.moveTo(cx, cy)
117
- ctx.lineTo(cx + ls * Math.cos(this.shadowDirection), cy + ls * Math.sin(this.shadowDirection))
118
- ctx.stroke()
119
-
120
- /*
121
- if (this.simple) {
122
- //draw base circle
123
- cg.ctx.beginPath();
124
- cg.ctx.arc(
125
- cx, cy,
126
- wG * 0.5,
127
- 0, 2 * Math.PI, false);
128
- //cg.ctx.stroke();
129
- cg.ctx.fill();
130
- }*/
131
- }
132
-
133
- //draw pillars
134
- for (let cell of cells) {
135
- //color
136
- /** @type {string|undefined} */
137
- const col = this.color ? this.color(cell, resolution, z, viewScale) : undefined
138
- if (!col) continue
139
-
140
- //width
141
- /** @type {number|undefined} */
142
- const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
143
- if (!wG || wG < 0) continue
144
-
145
- //height
146
- /** @type {number|undefined} */
147
- const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
148
- if (!hG || hG < 0) continue
149
-
150
- //get offset
151
- //TODO use that
152
- //const offset = this.offset(c, resolution, z)
153
-
154
- //compute cell center postition
155
- const cx = cell.x + resolution / 2
156
- const cy = cell.y + resolution / 2
157
-
158
- //compute angle
159
- const dx = cx - cvx,
160
- dy = cy - cvy
161
- const a = Math.atan2(dy, dx)
162
- const D = Math.sqrt(dx * dx + dy * dy)
163
- const d = (D * hG) / (H - hG)
164
-
165
- if (simple) {
166
- //draw segment
167
- ctx.strokeStyle = col
168
- ctx.lineWidth = wG
169
- ctx.beginPath()
170
- ctx.moveTo(cx, cy)
171
- ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
172
- ctx.stroke()
173
- } else {
174
- //draw background segment
175
- ctx.strokeStyle = this.outlineCol
176
- ctx.lineWidth = wG + 2 * this.outlineWidthPix * z
177
- ctx.beginPath()
178
- ctx.moveTo(cx, cy)
179
- ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
180
- ctx.stroke()
181
-
182
- //draw segment
183
- ctx.strokeStyle = col
184
- ctx.lineWidth = wG
185
- ctx.beginPath()
186
- ctx.moveTo(cx, cy)
187
- ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
188
- ctx.stroke()
189
-
190
- //draw top circle
191
- ctx.strokeStyle = this.outlineCol
192
- //cg.ctx.fillStyle = "#c08c59"
193
- ctx.lineWidth = this.outlineWidthPix * z
194
- ctx.beginPath()
195
- ctx.arc(cx + d * Math.cos(a), cy + d * Math.sin(a), wG * 0.5, 0, 2 * Math.PI, false)
196
- ctx.stroke()
197
- //cg.ctx.fill();
198
- }
199
- }
200
-
201
- //in case...
202
- ctx.lineCap = 'butt'
203
-
204
- //update legends
205
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
206
- }
207
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../core/Style.js'
5
+
6
+ /**
7
+ * @module style
8
+ * @author Julien Gaffuri
9
+ */
10
+ export class PillarStyle extends Style {
11
+ /** @param {object} opts */
12
+ constructor(opts) {
13
+ super(opts)
14
+ opts = opts || {}
15
+
16
+ /** A function returning the height of the line representing a cell, in geo unit
17
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
18
+ this.height = opts.height
19
+
20
+ /** A function returning the color of the line representing a cell.
21
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
22
+ this.color = opts.color || (() => '#c08c59') //(c,r,z,vs) => {}
23
+
24
+ /** A function returning the width of the line representing a cell, in geo unit
25
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
26
+ this.width = opts.width || ((cell, resolution) => 0.5 * resolution)
27
+
28
+ /** A function returning the width of the line representing a cell, in geo unit
29
+ * @type {function(number, number,object):boolean} */
30
+ this.simple = opts.simple || (() => false)
31
+
32
+ /** @type {number} */
33
+ this.viewHeightFactor = opts.viewHeightFactor || 1.5
34
+ //0,0 is the center
35
+ /** @type {number} */
36
+ this.viewSX = opts.viewSX == undefined ? 0 : opts.viewSX
37
+ /** @type {number} */
38
+ this.viewSY = opts.viewSY == undefined ? -0.5 : opts.viewSY
39
+
40
+ //TODO replace with sun location ?
41
+ /** @type {number} */
42
+ this.shadowDirection =
43
+ opts.shadowDirection == undefined ? (-40.3 * Math.PI) / 180.0 : opts.shadowDirection
44
+ /** @type {number} */
45
+ this.shadowFactor = opts.shadowFactor || 0.3
46
+ /** @type {string} */
47
+ this.shadowColor = opts.shadowColor || '#00000033'
48
+
49
+ /** @type {string} */
50
+ this.outlineCol = opts.outlineCol || '#FFFFFF'
51
+ /** @type {number} */
52
+ this.outlineWidthPix = opts.outlineWidthPix == undefined ? 0.5 : opts.outlineWidthPix
53
+ }
54
+
55
+ /**
56
+ * Draw cells as segments.
57
+ *
58
+ * @param {Array.<import("../core/Dataset").Cell>} cells
59
+ * @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
60
+ * @param {number} resolution
61
+ */
62
+ draw(cells, geoCanvas, resolution) {
63
+ //filter
64
+ if (this.filter) cells = cells.filter(this.filter)
65
+
66
+ //
67
+ const z = geoCanvas.view.z
68
+ const ctx = geoCanvas.offscreenCtx
69
+
70
+ //get view scale
71
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
72
+
73
+ //get view center geo position
74
+ const cvx = geoCanvas.view.x + this.viewSX * geoCanvas.w * z
75
+ const cvy = geoCanvas.view.y + this.viewSY * geoCanvas.h * z
76
+ //get view height
77
+ const H = this.viewHeightFactor * (geoCanvas.w + geoCanvas.h) * 0.5 * z
78
+
79
+ //sort cells by y and x
80
+ //const distToViewCenter = (c) => { const dx = cvx - c.x, dy = cvy - c.y; return Math.sqrt(dx * dx + dy * dy) }
81
+ cells.sort((c1, c2) => 100000000 * (c2.y - c1.y) + c1.x - c2.x)
82
+
83
+ //get simple information
84
+ const simple = this.simple(resolution, z, viewScale)
85
+
86
+ ctx.lineCap = simple ? 'butt' : 'round'
87
+
88
+ //draw shadows
89
+ ctx.strokeStyle = this.shadowColor
90
+ ctx.fillStyle = this.shadowColor
91
+ for (let cell of cells) {
92
+ //width
93
+ /** @type {number|undefined} */
94
+ const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
95
+ if (!wG || wG < 0) continue
96
+
97
+ //height
98
+ /** @type {number|undefined} */
99
+ const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
100
+ if (!hG || hG < 0) continue
101
+
102
+ //get offset
103
+ //TODO use that
104
+ //const offset = this.offset(c, resolution, z)
105
+
106
+ //set width
107
+ ctx.lineWidth = wG
108
+
109
+ //compute cell center postition
110
+ const cx = cell.x + resolution / 2
111
+ const cy = cell.y + resolution / 2
112
+ const ls = hG * this.shadowFactor
113
+
114
+ //draw segment
115
+ ctx.beginPath()
116
+ ctx.moveTo(cx, cy)
117
+ ctx.lineTo(cx + ls * Math.cos(this.shadowDirection), cy + ls * Math.sin(this.shadowDirection))
118
+ ctx.stroke()
119
+
120
+ /*
121
+ if (this.simple) {
122
+ //draw base circle
123
+ cg.ctx.beginPath();
124
+ cg.ctx.arc(
125
+ cx, cy,
126
+ wG * 0.5,
127
+ 0, 2 * Math.PI, false);
128
+ //cg.ctx.stroke();
129
+ cg.ctx.fill();
130
+ }*/
131
+ }
132
+
133
+ //draw pillars
134
+ for (let cell of cells) {
135
+ //color
136
+ /** @type {string|undefined} */
137
+ const col = this.color ? this.color(cell, resolution, z, viewScale) : undefined
138
+ if (!col) continue
139
+
140
+ //width
141
+ /** @type {number|undefined} */
142
+ const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
143
+ if (!wG || wG < 0) continue
144
+
145
+ //height
146
+ /** @type {number|undefined} */
147
+ const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
148
+ if (!hG || hG < 0) continue
149
+
150
+ //get offset
151
+ //TODO use that
152
+ //const offset = this.offset(c, resolution, z)
153
+
154
+ //compute cell center postition
155
+ const cx = cell.x + resolution / 2
156
+ const cy = cell.y + resolution / 2
157
+
158
+ //compute angle
159
+ const dx = cx - cvx,
160
+ dy = cy - cvy
161
+ const a = Math.atan2(dy, dx)
162
+ const D = Math.sqrt(dx * dx + dy * dy)
163
+ const d = (D * hG) / (H - hG)
164
+
165
+ if (simple) {
166
+ //draw segment
167
+ ctx.strokeStyle = col
168
+ ctx.lineWidth = wG
169
+ ctx.beginPath()
170
+ ctx.moveTo(cx, cy)
171
+ ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
172
+ ctx.stroke()
173
+ } else {
174
+ //draw background segment
175
+ ctx.strokeStyle = this.outlineCol
176
+ ctx.lineWidth = wG + 2 * this.outlineWidthPix * z
177
+ ctx.beginPath()
178
+ ctx.moveTo(cx, cy)
179
+ ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
180
+ ctx.stroke()
181
+
182
+ //draw segment
183
+ ctx.strokeStyle = col
184
+ ctx.lineWidth = wG
185
+ ctx.beginPath()
186
+ ctx.moveTo(cx, cy)
187
+ ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
188
+ ctx.stroke()
189
+
190
+ //draw top circle
191
+ ctx.strokeStyle = this.outlineCol
192
+ //cg.ctx.fillStyle = "#c08c59"
193
+ ctx.lineWidth = this.outlineWidthPix * z
194
+ ctx.beginPath()
195
+ ctx.arc(cx + d * Math.cos(a), cy + d * Math.sin(a), wG * 0.5, 0, 2 * Math.PI, false)
196
+ ctx.stroke()
197
+ //cg.ctx.fill();
198
+ }
199
+ }
200
+
201
+ //in case...
202
+ ctx.lineCap = 'butt'
203
+
204
+ //update legends
205
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
206
+ }
207
+ }
@@ -1,105 +1,105 @@
1
- //@ts-check
2
- 'use strict'
3
-
4
- import { Style } from '../core/Style.js'
5
-
6
- /**
7
- * A style where each cell is represented by a segment whose length, width, color and orientation can vary according to statistical values.
8
- *
9
- * @module style
10
- * @author Julien Gaffuri
11
- */
12
- export class SegmentStyle extends Style {
13
- /** @param {object} opts */
14
- constructor(opts) {
15
- super(opts)
16
- opts = opts || {}
17
-
18
- /** A function returning the color of the cell segment.
19
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
20
- this.color = opts.color || (() => '#EA6BAC') //(c,r,z,vs) => {}
21
-
22
- /** A function returning the width of the segment representing a cell, in geo unit
23
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
24
- this.width = opts.width || ((cell, resolution) => resolution * 0.1) //(c,r,z,vs) => {}
25
-
26
- /** A function returning the length of the segment representing a cell, in geo unit
27
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
28
- this.length = opts.length || ((cell, resolution) => resolution * 0.9) //(c,r,z,vs) => {}
29
-
30
- /** A function returning the orientation (in degrees) of the segment representing a cell.
31
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
32
- this.orientation = opts.orientation || (() => 180 * Math.random()) //(c,r,z,vs) => {}
33
- }
34
-
35
- /**
36
- * Draw cells as segments.
37
- *
38
- * @param {Array.<import("../core/Dataset").Cell>} cells
39
- * @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
40
- * @param {number} resolution
41
- */
42
- draw(cells, geoCanvas, resolution) {
43
- //filter
44
- if (this.filter) cells = cells.filter(this.filter)
45
-
46
- //
47
- const z = geoCanvas.view.z
48
- const ctx = geoCanvas.offscreenCtx
49
-
50
- //get view scale
51
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
52
-
53
- //
54
- ctx.lineCap = 'butt'
55
-
56
- //conversion factor degree -> radian
57
- const f = Math.PI / 180
58
-
59
- for (let cell of cells) {
60
- //color
61
- /** @type {string|undefined} */
62
- const col = this.color ? this.color(cell, resolution, z, viewScale) : undefined
63
- if (!col) continue
64
-
65
- //width
66
- /** @type {number|undefined} */
67
- const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
68
- if (!wG || wG < 0) continue
69
-
70
- //length
71
- /** @type {number|undefined} */
72
- const lG = this.length ? this.length(cell, resolution, z, viewScale) : undefined
73
- if (!lG || lG < 0) continue
74
-
75
- //orientation (in radian)
76
- /** @type {number} */
77
- const or = this.orientation(cell, resolution, z, viewScale) * f
78
- if (or === undefined || isNaN(or)) continue
79
-
80
- //get offset
81
- const offset = this.offset(cell, resolution, z)
82
-
83
- //set color and width
84
- ctx.strokeStyle = col
85
- ctx.lineWidth = wG
86
-
87
- //compute segment center postition
88
- const cx = cell.x + resolution / 2 + offset.dx
89
- const cy = cell.y + resolution / 2 + offset.dy
90
-
91
- //compute segment direction
92
- const dx = 0.5 * Math.cos(or) * lG
93
- const dy = 0.5 * Math.sin(or) * lG
94
-
95
- //draw segment
96
- ctx.beginPath()
97
- ctx.moveTo(cx - dx, cy - dy)
98
- ctx.lineTo(cx + dx, cy + dy)
99
- ctx.stroke()
100
- }
101
-
102
- //update legends
103
- this.updateLegends({ viewScale: viewScale, resolution: resolution, z: z, cells: cells })
104
- }
105
- }
1
+ //@ts-check
2
+ 'use strict'
3
+
4
+ import { Style } from '../core/Style.js'
5
+
6
+ /**
7
+ * A style where each cell is represented by a segment whose length, width, color and orientation can vary according to statistical values.
8
+ *
9
+ * @module style
10
+ * @author Julien Gaffuri
11
+ */
12
+ export class SegmentStyle extends Style {
13
+ /** @param {object} opts */
14
+ constructor(opts) {
15
+ super(opts)
16
+ opts = opts || {}
17
+
18
+ /** A function returning the color of the cell segment.
19
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
20
+ this.color = opts.color || (() => '#EA6BAC') //(c,r,z,vs) => {}
21
+
22
+ /** A function returning the width of the segment representing a cell, in geo unit
23
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
24
+ this.width = opts.width || ((cell, resolution) => resolution * 0.1) //(c,r,z,vs) => {}
25
+
26
+ /** A function returning the length of the segment representing a cell, in geo unit
27
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
28
+ this.length = opts.length || ((cell, resolution) => resolution * 0.9) //(c,r,z,vs) => {}
29
+
30
+ /** A function returning the orientation (in degrees) of the segment representing a cell.
31
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
32
+ this.orientation = opts.orientation || (() => 180 * Math.random()) //(c,r,z,vs) => {}
33
+ }
34
+
35
+ /**
36
+ * Draw cells as segments.
37
+ *
38
+ * @param {Array.<import("../core/Dataset").Cell>} cells
39
+ * @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
40
+ * @param {number} resolution
41
+ */
42
+ draw(cells, geoCanvas, resolution) {
43
+ //filter
44
+ if (this.filter) cells = cells.filter(this.filter)
45
+
46
+ //
47
+ const z = geoCanvas.view.z
48
+ const ctx = geoCanvas.offscreenCtx
49
+
50
+ //get view scale
51
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
52
+
53
+ //
54
+ ctx.lineCap = 'butt'
55
+
56
+ //conversion factor degree -> radian
57
+ const f = Math.PI / 180
58
+
59
+ for (let cell of cells) {
60
+ //color
61
+ /** @type {string|undefined} */
62
+ const col = this.color ? this.color(cell, resolution, z, viewScale) : undefined
63
+ if (!col) continue
64
+
65
+ //width
66
+ /** @type {number|undefined} */
67
+ const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
68
+ if (!wG || wG < 0) continue
69
+
70
+ //length
71
+ /** @type {number|undefined} */
72
+ const lG = this.length ? this.length(cell, resolution, z, viewScale) : undefined
73
+ if (!lG || lG < 0) continue
74
+
75
+ //orientation (in radian)
76
+ /** @type {number} */
77
+ const or = this.orientation(cell, resolution, z, viewScale) * f
78
+ if (or === undefined || isNaN(or)) continue
79
+
80
+ //get offset
81
+ const offset = this.offset(cell, resolution, z)
82
+
83
+ //set color and width
84
+ ctx.strokeStyle = col
85
+ ctx.lineWidth = wG
86
+
87
+ //compute segment center postition
88
+ const cx = cell.x + resolution / 2 + offset.dx
89
+ const cy = cell.y + resolution / 2 + offset.dy
90
+
91
+ //compute segment direction
92
+ const dx = 0.5 * Math.cos(or) * lG
93
+ const dy = 0.5 * Math.sin(or) * lG
94
+
95
+ //draw segment
96
+ ctx.beginPath()
97
+ ctx.moveTo(cx - dx, cy - dy)
98
+ ctx.lineTo(cx + dx, cy + dy)
99
+ ctx.stroke()
100
+ }
101
+
102
+ //update legends
103
+ this.updateLegends({ viewScale: viewScale, resolution: resolution, z: z, cells: cells })
104
+ }
105
+ }