gridviz 3.0.19 → 3.0.21

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 +128 -128
  2. package/dist/gridviz.js +7875 -7857
  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 +78 -60
  8. package/src/core/GeoCanvas.js +430 -430
  9. package/src/core/Layer.js +23 -23
  10. package/src/core/Legend.js +108 -108
  11. package/src/core/Map.js +516 -516
  12. package/src/core/MultiResolutionDataset.js +93 -93
  13. package/src/core/Style.js +98 -98
  14. package/src/dataset/CSVGrid.js +112 -112
  15. package/src/dataset/GeoTIFF.js +122 -122
  16. package/src/dataset/JSGrid.js +55 -55
  17. package/src/dataset/TiledGrid.js +302 -302
  18. package/src/dataset/worker.js +18 -18
  19. package/src/index.js +77 -77
  20. package/src/layer/BackgroundLayer.js +162 -162
  21. package/src/layer/BackgroundLayerImage.js +81 -81
  22. package/src/layer/BackgroundLayerWMS.js +104 -104
  23. package/src/layer/GeoJSONLayer.js +214 -214
  24. package/src/layer/GridLayer.js +148 -148
  25. package/src/layer/LabelLayer.js +194 -194
  26. package/src/legend/ColorCategoryLegend.js +109 -109
  27. package/src/legend/ColorDiscreteLegend.js +100 -100
  28. package/src/legend/ColorLegend.js +115 -115
  29. package/src/legend/OrientationLegend.js +89 -89
  30. package/src/legend/SizeLegend.js +224 -224
  31. package/src/legend/TernaryLegend.js +302 -302
  32. package/src/style/CompositionStyle.js +291 -291
  33. package/src/style/DotDensityStyle.js +133 -133
  34. package/src/style/ImageStyle.js +100 -100
  35. package/src/style/IsoFenceStyle.js +217 -217
  36. package/src/style/JoyPlotStyle.js +127 -127
  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 -207
  41. package/src/style/SegmentStyle.js +105 -105
  42. package/src/style/ShapeColorSizeStyle.js +147 -147
  43. package/src/style/SideCategoryStyle.js +112 -112
  44. package/src/style/SideStyle.js +212 -212
  45. package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
  46. package/src/style/SquareColorWebGLStyle.js +126 -126
  47. package/src/style/StrokeStyle.js +135 -135
  48. package/src/style/TanakaStyle.js +69 -69
  49. package/src/style/TextStyle.js +110 -110
  50. package/src/style/TimeSeriesStyle.js +222 -222
  51. package/src/utils/scale.js +218 -218
  52. package/src/utils/stretching.js +120 -120
  53. package/src/utils/ternary.js +208 -208
  54. package/src/utils/utils.js +58 -58
  55. 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
+ }