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,208 +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
-
12
- /** @param {object} opts */
13
- constructor(opts) {
14
- super(opts)
15
- opts = opts || {}
16
-
17
- /** A function returning the height of the line representing a cell, in geo unit
18
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
19
- this.height = opts.height
20
-
21
- /** A function returning the color of the line representing a cell.
22
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
23
- this.color = opts.color || (() => "#c08c59") //(c,r,z,vs) => {}
24
-
25
- /** A function returning the width of the line representing a cell, in geo unit
26
- * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
27
- this.width = opts.width || ((cell, resolution) => 0.5 * resolution)
28
-
29
- /** A function returning the width of the line representing a cell, in geo unit
30
- * @type {function(number, number,object):boolean} */
31
- this.simple = opts.simple || (() => false)
32
-
33
- /** @type {number} */
34
- this.viewHeightFactor = opts.viewHeightFactor || 1.5
35
- //0,0 is the center
36
- /** @type {number} */
37
- this.viewSX = opts.viewSX == undefined ? 0 : opts.viewSX
38
- /** @type {number} */
39
- this.viewSY = opts.viewSY == undefined ? -0.5 : opts.viewSY
40
-
41
- //TODO replace with sun location ?
42
- /** @type {number} */
43
- this.shadowDirection =
44
- opts.shadowDirection == undefined ? (-40.3 * Math.PI) / 180.0 : opts.shadowDirection
45
- /** @type {number} */
46
- this.shadowFactor = opts.shadowFactor || 0.3
47
- /** @type {string} */
48
- this.shadowColor = opts.shadowColor || '#00000033'
49
-
50
- /** @type {string} */
51
- this.outlineCol = opts.outlineCol || '#FFFFFF'
52
- /** @type {number} */
53
- this.outlineWidthPix = opts.outlineWidthPix == undefined ? 0.5 : opts.outlineWidthPix
54
- }
55
-
56
- /**
57
- * Draw cells as segments.
58
- *
59
- * @param {Array.<import("../core/Dataset").Cell>} cells
60
- * @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
61
- * @param {number} resolution
62
- */
63
- draw(cells, geoCanvas, resolution) {
64
-
65
- //filter
66
- if (this.filter) cells = cells.filter(this.filter)
67
-
68
- //
69
- const z = geoCanvas.view.z
70
-
71
- //get view scale
72
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
73
-
74
- //get view center geo position
75
- const cvx = geoCanvas.view.x + this.viewSX * geoCanvas.w * z
76
- const cvy = geoCanvas.view.y + this.viewSY * geoCanvas.h * z
77
- //get view height
78
- const H = this.viewHeightFactor * (geoCanvas.w + geoCanvas.h) * 0.5 * z
79
-
80
- //sort cells by y and x
81
- //const distToViewCenter = (c) => { const dx = cvx - c.x, dy = cvy - c.y; return Math.sqrt(dx * dx + dy * dy) }
82
- cells.sort((c1, c2) => 100000000 * (c2.y - c1.y) + c1.x - c2.x)
83
-
84
- //get simple information
85
- const simple = this.simple(resolution, z, viewScale)
86
-
87
- geoCanvas.ctx.lineCap = simple ? 'butt' : 'round'
88
-
89
- //draw shadows
90
- geoCanvas.ctx.strokeStyle = this.shadowColor
91
- geoCanvas.ctx.fillStyle = this.shadowColor
92
- for (let cell of cells) {
93
- //width
94
- /** @type {number|undefined} */
95
- const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
96
- if (!wG || wG < 0) continue
97
-
98
- //height
99
- /** @type {number|undefined} */
100
- const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
101
- if (!hG || hG < 0) continue
102
-
103
- //get offset
104
- //TODO use that
105
- //const offset = this.offset(c, resolution, z)
106
-
107
- //set width
108
- geoCanvas.ctx.lineWidth = wG
109
-
110
- //compute cell center postition
111
- const cx = cell.x + resolution / 2
112
- const cy = cell.y + resolution / 2
113
- const ls = hG * this.shadowFactor
114
-
115
- //draw segment
116
- geoCanvas.ctx.beginPath()
117
- geoCanvas.ctx.moveTo(cx, cy)
118
- geoCanvas.ctx.lineTo(cx + ls * Math.cos(this.shadowDirection), cy + ls * Math.sin(this.shadowDirection))
119
- geoCanvas.ctx.stroke()
120
-
121
- /*
122
- if (this.simple) {
123
- //draw base circle
124
- cg.ctx.beginPath();
125
- cg.ctx.arc(
126
- cx, cy,
127
- wG * 0.5,
128
- 0, 2 * Math.PI, false);
129
- //cg.ctx.stroke();
130
- cg.ctx.fill();
131
- }*/
132
- }
133
-
134
- //draw pillars
135
- for (let cell of cells) {
136
- //color
137
- /** @type {string|undefined} */
138
- const col = this.color ? this.color(cell, resolution, z, viewScale) : undefined
139
- if (!col) continue
140
-
141
- //width
142
- /** @type {number|undefined} */
143
- const wG = this.width ? this.width(cell, resolution, z, viewScale) : undefined
144
- if (!wG || wG < 0) continue
145
-
146
- //height
147
- /** @type {number|undefined} */
148
- const hG = this.height ? this.height(cell, resolution, z, viewScale) : undefined
149
- if (!hG || hG < 0) continue
150
-
151
- //get offset
152
- //TODO use that
153
- //const offset = this.offset(c, resolution, z)
154
-
155
- //compute cell center postition
156
- const cx = cell.x + resolution / 2
157
- const cy = cell.y + resolution / 2
158
-
159
- //compute angle
160
- const dx = cx - cvx,
161
- dy = cy - cvy
162
- const a = Math.atan2(dy, dx)
163
- const D = Math.sqrt(dx * dx + dy * dy)
164
- const d = (D * hG) / (H - hG)
165
-
166
- if (simple) {
167
- //draw segment
168
- geoCanvas.ctx.strokeStyle = col
169
- geoCanvas.ctx.lineWidth = wG
170
- geoCanvas.ctx.beginPath()
171
- geoCanvas.ctx.moveTo(cx, cy)
172
- geoCanvas.ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
173
- geoCanvas.ctx.stroke()
174
- } else {
175
- //draw background segment
176
- geoCanvas.ctx.strokeStyle = this.outlineCol
177
- geoCanvas.ctx.lineWidth = wG + 2 * this.outlineWidthPix * z
178
- geoCanvas.ctx.beginPath()
179
- geoCanvas.ctx.moveTo(cx, cy)
180
- geoCanvas.ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
181
- geoCanvas.ctx.stroke()
182
-
183
- //draw segment
184
- geoCanvas.ctx.strokeStyle = col
185
- geoCanvas.ctx.lineWidth = wG
186
- geoCanvas.ctx.beginPath()
187
- geoCanvas.ctx.moveTo(cx, cy)
188
- geoCanvas.ctx.lineTo(cx + d * Math.cos(a), cy + d * Math.sin(a))
189
- geoCanvas.ctx.stroke()
190
-
191
- //draw top circle
192
- geoCanvas.ctx.strokeStyle = this.outlineCol
193
- //cg.ctx.fillStyle = "#c08c59"
194
- geoCanvas.ctx.lineWidth = this.outlineWidthPix * z
195
- geoCanvas.ctx.beginPath()
196
- geoCanvas.ctx.arc(cx + d * Math.cos(a), cy + d * Math.sin(a), wG * 0.5, 0, 2 * Math.PI, false)
197
- geoCanvas.ctx.stroke()
198
- //cg.ctx.fill();
199
- }
200
- }
201
-
202
- //in case...
203
- geoCanvas.ctx.lineCap = 'butt'
204
-
205
- //update legends
206
- this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
207
- }
208
- }
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
-
44
- //filter
45
- if (this.filter) cells = cells.filter(this.filter)
46
-
47
- //
48
- const z = geoCanvas.view.z
49
-
50
- //get view scale
51
- const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
52
-
53
- //
54
- geoCanvas.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
- geoCanvas.ctx.strokeStyle = col
85
- geoCanvas.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
- geoCanvas.ctx.beginPath()
97
- geoCanvas.ctx.moveTo(cx - dx, cy - dy)
98
- geoCanvas.ctx.lineTo(cx + dx, cy + dy)
99
- geoCanvas.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
+ }