gridviz 3.0.18 → 3.0.20

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 (56) hide show
  1. package/README.md +128 -127
  2. package/dist/gridviz.js +7862 -7819
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +74 -74
  5. package/src/button/ZoomButtons.js +101 -101
  6. package/src/core/Dataset.js +154 -154
  7. package/src/core/Drawable.js +60 -60
  8. package/src/core/GeoCanvas.js +430 -419
  9. package/src/core/Layer.js +23 -23
  10. package/src/core/Legend.js +108 -108
  11. package/src/core/Map.js +516 -503
  12. package/src/core/MultiResolutionDataset.js +93 -93
  13. package/src/core/Style.js +98 -98
  14. package/src/core/Tooltip.js +1 -0
  15. package/src/dataset/CSVGrid.js +112 -112
  16. package/src/dataset/GeoTIFF.js +122 -122
  17. package/src/dataset/JSGrid.js +55 -55
  18. package/src/dataset/TiledGrid.js +302 -289
  19. package/src/dataset/worker.js +18 -18
  20. package/src/index.js +77 -77
  21. package/src/layer/BackgroundLayer.js +162 -162
  22. package/src/layer/BackgroundLayerImage.js +81 -81
  23. package/src/layer/BackgroundLayerWMS.js +104 -104
  24. package/src/layer/GeoJSONLayer.js +214 -214
  25. package/src/layer/GridLayer.js +148 -148
  26. package/src/layer/LabelLayer.js +194 -194
  27. package/src/legend/ColorCategoryLegend.js +109 -109
  28. package/src/legend/ColorDiscreteLegend.js +100 -100
  29. package/src/legend/ColorLegend.js +115 -115
  30. package/src/legend/OrientationLegend.js +89 -89
  31. package/src/legend/SizeLegend.js +224 -224
  32. package/src/legend/TernaryLegend.js +302 -302
  33. package/src/style/CompositionStyle.js +291 -291
  34. package/src/style/DotDensityStyle.js +133 -133
  35. package/src/style/ImageStyle.js +100 -100
  36. package/src/style/IsoFenceStyle.js +217 -217
  37. package/src/style/JoyPlotStyle.js +127 -127
  38. package/src/style/LegoStyle.js +110 -110
  39. package/src/style/MosaicStyle.js +99 -99
  40. package/src/style/NinjaStarStyle.js +102 -102
  41. package/src/style/PillarStyle.js +207 -207
  42. package/src/style/SegmentStyle.js +105 -105
  43. package/src/style/ShapeColorSizeStyle.js +147 -147
  44. package/src/style/SideCategoryStyle.js +112 -112
  45. package/src/style/SideStyle.js +212 -212
  46. package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
  47. package/src/style/SquareColorWebGLStyle.js +126 -126
  48. package/src/style/StrokeStyle.js +135 -135
  49. package/src/style/TanakaStyle.js +69 -69
  50. package/src/style/TextStyle.js +110 -110
  51. package/src/style/TimeSeriesStyle.js +222 -222
  52. package/src/utils/scale.js +218 -218
  53. package/src/utils/stretching.js +120 -120
  54. package/src/utils/ternary.js +208 -203
  55. package/src/utils/utils.js +58 -58
  56. package/src/utils/webGLUtils.js +72 -72
@@ -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
+ }