gridviz 2.1.16 → 3.0.0

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 (67) hide show
  1. package/README.md +2 -3
  2. package/dist/gridviz.js +4971 -5654
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +3 -2
  5. package/src/button/Button.js +14 -15
  6. package/src/button/FullscreenButton.js +14 -14
  7. package/src/button/ZoomButtons.js +2 -2
  8. package/src/{DatasetComponent.js → core/Dataset.js} +33 -12
  9. package/src/core/Drawable.js +60 -0
  10. package/src/{GeoCanvas.js → core/GeoCanvas.js} +65 -155
  11. package/src/core/Layer.js +24 -0
  12. package/src/{Legend.js → core/Legend.js} +24 -1
  13. package/src/core/Map.js +460 -0
  14. package/src/core/MultiResolutionDataset.js +96 -0
  15. package/src/core/Style.js +84 -0
  16. package/src/dataset/COGeo.js +5 -5
  17. package/src/dataset/CSVGrid.js +43 -41
  18. package/src/dataset/GeoTIFF.js +9 -14
  19. package/src/dataset/{LGrid.js → JSGrid.js} +9 -10
  20. package/src/dataset/TiledGrid.js +68 -45
  21. package/src/index.js +22 -29
  22. package/src/{BackgroundLayer.js → layer/BackgroundLayer.js} +27 -52
  23. package/src/{BackgroundLayerWMS.js → layer/BackgroundLayerWMS.js} +21 -45
  24. package/src/{LineLayer.js → layer/GeoJSONLayer.js} +22 -23
  25. package/src/layer/GridLayer.js +140 -0
  26. package/src/{LabelLayer.js → layer/LabelLayer.js} +25 -23
  27. package/src/legend/ColorCategoryLegend.js +9 -24
  28. package/src/legend/ColorDiscreteLegend.js +20 -24
  29. package/src/legend/ColorLegend.js +21 -33
  30. package/src/legend/OrientationLegend.js +90 -0
  31. package/src/legend/SizeLegend.js +153 -72
  32. package/src/style/CompositionStyle.js +71 -84
  33. package/src/style/ContourStyle.js +2 -36
  34. package/src/style/DotDensityStyle.js +50 -73
  35. package/src/style/IsoFenceStyle.js +59 -70
  36. package/src/style/JoyPlotStyle.js +41 -48
  37. package/src/style/LegoStyle.js +4 -4
  38. package/src/style/MosaicStyle.js +30 -39
  39. package/src/style/NinjaStarStyle.js +45 -68
  40. package/src/style/PillarStyle.js +70 -93
  41. package/src/style/SegmentStyle.js +37 -75
  42. package/src/style/ShapeColorSizeStyle.js +49 -98
  43. package/src/style/SideCategoryStyle.js +112 -0
  44. package/src/style/SideStyle.js +99 -133
  45. package/src/style/{SquareColorCatWGLStyle.js → SquareColorCategoryWebGLStyle.js} +28 -41
  46. package/src/style/{SquareColorWGLStyle.js → SquareColorWebGLStyle.js} +28 -49
  47. package/src/style/StrokeStyle.js +43 -70
  48. package/src/style/TanakaStyle.js +34 -132
  49. package/src/style/TextStyle.js +43 -64
  50. package/src/style/TimeSeriesStyle.js +44 -75
  51. package/src/utils/WebGLSquareColoringAdvanced.js +4 -4
  52. package/src/utils/scale.js +202 -0
  53. package/src/utils/stretching.js +86 -129
  54. package/src/utils/{Utils.js → utils.js} +15 -0
  55. package/src/utils/webGLUtils.js +4 -5
  56. package/src/utils/zoomUtils.js +30 -30
  57. package/src/App.js +0 -760
  58. package/src/Dataset.js +0 -76
  59. package/src/Layer.js +0 -103
  60. package/src/Style.js +0 -131
  61. package/src/dataset/GridTile.js +0 -41
  62. package/src/legend/SegmentOrientationLegend.js +0 -87
  63. package/src/legend/SegmentWidthLegend.js +0 -101
  64. package/src/style/CompositionStyle_.js +0 -293
  65. package/src/style/ShapeColorSizeStyle_.js +0 -108
  66. package/src/style/SideCatStyle.js +0 -172
  67. /package/src/{Tooltip.js → core/Tooltip.js} +0 -0
@@ -1,8 +1,9 @@
1
1
  //@ts-check
2
2
  'use strict'
3
3
 
4
- import { Legend } from '../Legend.js'
5
- import { format } from 'd3-format'
4
+ import { Legend } from '../core/Legend.js'
5
+ import { nice } from '../utils/utils.js'
6
+ import { max } from 'd3-array'
6
7
 
7
8
  /**
8
9
  * A legend element for proportional symbols.
@@ -15,103 +16,78 @@ export class SizeLegend extends Legend {
15
16
  super(opts)
16
17
  opts = opts || {}
17
18
 
18
- //exageration
19
- this.exaggerationFactor = opts.exaggerationFactor || 0.8
19
+ /** A function returning the text label
20
+ * @type { function(object, Array.<import('../core/Dataset.js').Cell>):(number|string) } */
21
+ this.label = opts.label || undefined
20
22
 
21
- //if value is to be forced
22
- this.value = opts.value || undefined
23
-
24
- //title
25
- this.title = opts.title
26
- this.titleFontSize = opts.titleFontSize || '0.8em'
27
- this.titleFontWeight = opts.titleFontWeight || 'bold'
23
+ /** A function returning the size of the legend symbol
24
+ * @type { function(object):number } */
25
+ this.size = opts.size || undefined
28
26
 
29
27
  //symbol
30
- /**
31
- * @private
32
- * @type {import("../Style").Shape} */
28
+ /** @type {(import("../core/Style").Shape)|"line"} */
33
29
  this.shape = opts.shape || 'circle'
30
+
31
+ //general case
34
32
  this.fillColor = opts.fillColor || 'none'
35
33
  this.strokeColor = opts.strokeColor || 'gray'
36
34
  this.strokeWidth = opts.strokeWidth || 1
37
35
 
38
- //label
39
- this.labelFontSize = opts.labelFontSize || '0.8em'
40
- this.labelUnitText = opts.labelUnitText || ''
41
- this.labelFormat = opts.labelFormat || ',.2r'
42
-
43
- //
44
- //this.div.style("text-align", "center")
36
+ //for line shape
37
+ //TODO this.orientation = opts.orientation || 0
38
+ this.color = opts.color || 'gray'
39
+ this.length = opts.length || ((resolution, z, viewScale) => resolution)
45
40
  }
46
41
 
47
42
  /**
48
- * @param {{ style: import("../style/ShapeColorSizeStyle").ShapeColorSizeStyle, r: number, zf: number, sSize: import("../Style").Stat, sColor: import("../Style").Stat }} opts
43
+ * @param {{ viewScale:object, resolution: number, z:number, cells:Array.<import('../core/Dataset.js').Cell> }} opts
49
44
  */
50
45
  update(opts) {
51
- //could happen when data is still loading
52
- if (!opts.sSize) return
53
46
 
54
47
  //clear
55
48
  this.div.selectAll('*').remove()
56
49
 
57
- //get value
58
- let value = this.value
59
- if (value == undefined) {
60
- //compute 'nice value
61
-
62
- //get max value
63
- const value_ = opts.sSize.max * this.exaggerationFactor
64
-
65
- //take 'nice' value (power of ten, or multiple)
66
- let pow10 = Math.log10(value_)
67
- pow10 = Math.floor(pow10)
68
- value = Math.pow(10, pow10)
69
- if (value * 8 <= value_) value *= 8
70
- else if (value * 6 <= value_) value *= 6
71
- else if (value * 5 <= value_) value *= 5
72
- else if (value * 4 <= value_) value *= 4
73
- else if (value * 2.5 <= value_) value *= 2.5
74
- else if (value * 2 <= value_) value *= 2
75
- }
50
+ //title
51
+ this.makeTitle()
76
52
 
77
- if (!value) return
53
+ //get label. May not be a number (!)
54
+ let label = this.label(opts.viewScale, opts.cells)
55
+
56
+ //compute size of symbol, in pix
57
+ let sizePix
58
+ if (this.size)
59
+ sizePix = this.size(opts.viewScale) / opts.z
60
+ else
61
+ sizePix = opts.viewScale(+label) / opts.z
62
+ if (!sizePix) return
63
+
64
+ //format label, if specified and possible
65
+ if (this.labelFormat && !isNaN(+label)) label = this.labelFormat(label)
78
66
 
79
67
  const d = this.div.append('div')
80
68
  //to enable vertical centering
81
69
  //.style("position", "relative")
82
70
 
83
- //title
84
- if (this.title) {
85
- d.append('div')
86
- .attr('class', 'title')
87
- .style('font-size', this.titleFontSize)
88
- .style('font-weight', this.titleFontWeight)
89
- .text(this.title)
90
- }
91
-
92
- //compute size of symbol, in pix
93
- const size = opts.style.size(value, opts.r, opts.sSize, opts.zf) / opts.zf
94
-
95
- const svg = d
71
+ //default svg construction, for square and circle
72
+ const svg = () => d
96
73
  .append('svg')
97
- .attr('width', size + this.strokeWidth + 2)
98
- .attr('height', size + this.strokeWidth + 2)
74
+ .attr('width', sizePix + this.strokeWidth + 2)
75
+ .attr('height', sizePix + this.strokeWidth + 2)
99
76
  .style('', 'inline-block')
100
77
 
101
78
  if (this.shape === 'square') {
102
- svg.append('rect')
79
+ svg().append('rect')
103
80
  .attr('x', 0)
104
81
  .attr('y', 0)
105
- .attr('width', size)
106
- .attr('height', size)
82
+ .attr('width', sizePix)
83
+ .attr('height', sizePix)
107
84
  .style('fill', this.fillColor)
108
85
  .style('stroke', this.strokeColor)
109
86
  .style('stroke-width', this.strokeWidth)
110
- //TODO test
111
87
  } else if (this.shape === 'circle') {
112
88
  // <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
113
- const r = (size + this.strokeWidth) * 0.5
114
- svg.append('circle')
89
+ const r = (sizePix + this.strokeWidth) * 0.5
90
+ svg().append('circle')
115
91
  .attr('cx', r + 1)
116
92
  .attr('cy', r + 1)
117
93
  .attr('r', r)
@@ -122,20 +98,125 @@ export class SizeLegend extends Legend {
122
98
  //TODO
123
99
  } else if (this.shape === 'diamond') {
124
100
  //TODO
101
+ } else if (this.shape === 'line') {
102
+
103
+ //get segment length
104
+ let lengthPix = this.length ? this.length(opts.resolution, opts.z, opts.viewScale) : opts.resolution
105
+ lengthPix /= opts.z
106
+
107
+ const svg = d.append('svg').attr('width', lengthPix).attr('height', sizePix).style('', 'inline-block')
108
+
109
+ //TODO orientation
110
+ //<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
111
+ svg.append('line')
112
+ .attr('x1', 0)
113
+ .attr('y1', sizePix / 2)
114
+ .attr('x2', lengthPix)
115
+ .attr('y2', sizePix / 2)
116
+ .style('stroke', this.color)
117
+ .style('stroke-width', sizePix)
125
118
  } else {
126
119
  throw new Error('Unexpected shape:' + this.shape)
127
120
  }
128
121
 
129
- const valueT = format(this.labelFormat)(value)
122
+ //label
130
123
  d.append('div')
131
- //show on right of graphic
132
124
  .style('display', 'inline')
133
-
134
- //center vertically
135
- //.style("position", "absolute").style("top", "0").style("bottom", "0")
136
-
137
125
  .style('padding-left', '5px')
138
126
  .style('font-size', this.labelFontSize)
139
- .text(valueT + (this.labelUnitText ? ' ' : '') + this.labelUnitText)
127
+ .text(label + (this.labelUnitText ? ' ' : '') + this.labelUnitText)
128
+ }
129
+ }
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+ /**
138
+ * @param {Array.<number>} values
139
+ * @param {function(number):number} size
140
+ * @param { object } opts
141
+ * @returns {Array.<SizeLegend>}
142
+ */
143
+ export function sizeLegend(values, size, opts = {}) {
144
+ const legends = []
145
+ for (let value of values) {
146
+ opts.title = value == values[0] ? opts.title : undefined;
147
+ opts.size = () => size(value)
148
+ opts.label = () => value
149
+ legends.push(new SizeLegend(opts))
150
+ }
151
+ return legends
152
+ }
153
+
154
+ /**
155
+ * @param { function(import('../core/Dataset.js').Cell):number } value
156
+ * @param {*} opts
157
+ * @returns {Array.<SizeLegend>}
158
+ */
159
+ export function sizeLegendViewScale(value, opts = {}) {
160
+ const k = opts.k || [0.9, 0.5, 0.2, 0.05]
161
+ const legends = []
162
+ for (let k_ of k) {
163
+ opts.title = k_ == k[0] ? opts.title : undefined
164
+ opts.label = (viewScale, cells) => nice(k_ * max(cells, value))
165
+ legends.push(new SizeLegend(opts))
166
+ }
167
+ return legends
168
+ }
169
+
170
+ /**
171
+ * A function which return a stack of size legends for a discrete classification.
172
+ *
173
+ * @param { Array.<number> } breaks
174
+ * @param { Array.<number> } sizes
175
+ * @param { object } opts
176
+ * @returns {Array.<SizeLegend>}
177
+ */
178
+ export function sizeDiscreteLegend(breaks, sizes, opts = {}) {
179
+ const f = opts.labelFormat || (x => x)
180
+ const labelText = opts.labelText || defaultLabelText(f)
181
+ const legends = []
182
+ for (let i = sizes.length - 1; i >= 0; i--) {
183
+ opts.title = i == sizes.length - 1 ? opts.title : undefined
184
+ opts.size = () => sizes[i]
185
+ opts.label = () => labelText(breaks[i - 1], breaks[i])
186
+ legends.push(new SizeLegend(opts))
187
+ }
188
+ return legends
189
+ }
190
+
191
+ /**
192
+ * A function which return a stack of size legends for a discrete classification using a viewscale.
193
+ * @param { number } classNumber
194
+ * @param { object } opts
195
+ * @returns {Array.<SizeLegend>}
196
+ */
197
+ export function sizeDiscreteViewScaleLegend(classNumber, opts = {}) {
198
+ const f = opts.labelFormat || (x => x)
199
+ const labelText = opts.labelText || defaultLabelText(f)
200
+ const legends = []
201
+ for (let i = classNumber - 1; i >= 0; i--) {
202
+ opts.title = i == classNumber - 1 ? opts.title : undefined
203
+ opts.size = (viewScale) => viewScale.values[i]
204
+ opts.label = (viewScale) => labelText(viewScale.breaks[i - 1], viewScale.breaks[i])
205
+ legends.push(new SizeLegend(opts))
206
+ }
207
+ return legends
208
+ }
209
+
210
+ /**
211
+ * A function that returns a function to format laberls for discrete scale legends.
212
+ * @param { function(number):string } format
213
+ * @returns { function(number|undefined, number|undefined): string }
214
+ */
215
+ function defaultLabelText(format) {
216
+ return (v0, v1) => {
217
+ if (v0 == undefined && v1 == undefined) return ""
218
+ if (v1 == undefined) return "> " + format(v0)
219
+ if (v0 == undefined) return "< " + format(v1)
220
+ return format(v0) + " - " + format(v1)
140
221
  }
141
222
  }
@@ -1,7 +1,7 @@
1
1
  //@ts-check
2
2
  'use strict'
3
3
 
4
- import { Style } from '../Style.js'
4
+ import { Style } from '../core/Style.js'
5
5
 
6
6
  /** @typedef {"flag"|"piechart"|"ring"|"segment"|"radar"|"agepyramid"|"halftone"} CompositionType */
7
7
 
@@ -26,29 +26,25 @@ export class CompositionStyle extends Style {
26
26
 
27
27
  /**
28
28
  * A function returning the type of decomposition symbol of a cell, @see CompositionType
29
- * @type {function(import("../Dataset").Cell):CompositionType} */
30
- this.type = opts.type
29
+ * @type {function(import("../core/Dataset.js").Cell,number, number,object):CompositionType} */
30
+ this.type = opts.type || (() => "flag") //(c,r,z,vs) => {}
31
31
 
32
- /** The column where to get the size values.
33
- * @type {string} */
34
- this.sizeCol = opts.sizeCol
35
-
36
- /** A function returning the size of a cell.
37
- * @type {function(number,number,import("../Style").Stat|undefined,number):number} */
38
- this.size = opts.size || ((v, r, s, zf) => r)
32
+ /** A function returning the size of a cell in geographical unit.
33
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
34
+ this.size = opts.size || ((c, r) => r) //(c,r,z,vs) => {}
39
35
 
40
36
  /** For style types with stripes (flag, segment), the orientation of the stripes (0 for horizontal, other for vertical).
41
- * @type {function(import("../Dataset").Cell,number,number):number} */
42
- this.stripesOrientation = opts.stripesOrientation || (() => 0) //(c,r,zf) => ...
37
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
38
+ this.stripesOrientation = opts.stripesOrientation || (() => 0) //(c,r,z,vs) => ...
43
39
 
44
40
  /** The function specifying an offset angle for a radar, halftone or pie chart style.
45
41
  * The angle is specified in degree. The rotation is anti-clockwise.
46
- * @type {function(import("../Dataset").Cell,number,number):number} */
47
- this.offsetAngle = opts.offsetAngle || (() => 0) //(cell,r,zf) => ...
42
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
43
+ this.offsetAngle = opts.offsetAngle || (() => 0) //(c,r,z,vs) => ...
48
44
 
49
45
  /** The function specifying the height of the age pyramid, in geo unit.
50
- * @type {function(import("../Dataset").Cell,number,number):number} */
51
- this.agePyramidHeight = opts.agePyramidHeight || ((c, r, zf) => r) //(cell,r,zf) => ...
46
+ * @type {function(import("../core/Dataset.js").Cell,number,number,object):number} */
47
+ this.agePyramidHeight = opts.agePyramidHeight || ((c, r) => r) //(c,r,z,vs) => ...
52
48
 
53
49
  /** For pie chart, this is parameter for internal radius, so that the pie chart looks like a donut.
54
50
  * 0 for normal pie charts, 0.5 to empty half of the radius.
@@ -59,52 +55,43 @@ export class CompositionStyle extends Style {
59
55
  /**
60
56
  * Draw cells as squares depending on their value.
61
57
  *
62
- * @param {Array.<import("../Dataset").Cell>} cells
63
- * @param {number} r
64
- * @param {import("../GeoCanvas").GeoCanvas} cg
58
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
59
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
60
+ * @param {number} resolution
65
61
  */
66
- draw(cells, r, cg) {
62
+ draw(cells, geoCanvas, resolution) {
63
+
67
64
  //filter
68
65
  if (this.filter) cells = cells.filter(this.filter)
69
66
 
70
- //zoom factor
71
- const zf = cg.getZf()
67
+ //
68
+ const z = geoCanvas.view.z
72
69
 
73
- let stat
74
- if (this.sizeCol) {
75
- //if size is used, sort cells by size so that the biggest are drawn first
76
- cells.sort((c1, c2) => c2[this.sizeCol] - c1[this.sizeCol])
77
- //and compute statistics
78
- stat = Style.getStatistics(cells, (c) => c[this.sizeCol], true)
79
- }
70
+ //get view scale
71
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
80
72
 
81
73
  //nb categories - used for radar and agepyramid
82
74
  const nbCat = Object.entries(this.color).length
83
75
 
84
- //draw in geo coordinates
85
- cg.setCanvasTransform()
86
-
87
76
  //draw calls
88
77
  for (let cell of cells) {
78
+
89
79
  //size
90
- /** @type {function(number,number,import("../Style").Stat|undefined,number):number} */
91
- let s_ = this.size || (() => r)
92
- //size - in geo
93
- /** @type {number} */
94
- const sG = s_(cell[this.sizeCol], r, stat, zf)
80
+ const sG = this.size ? this.size(cell, resolution, z, viewScale) : resolution
81
+ if (!sG) continue
95
82
 
96
83
  //get offset
97
- const offset = this.offset(cell, r, zf)
84
+ const offset = this.offset(cell, resolution, z)
98
85
 
99
86
  //get symbol type
100
- const type_ = this.type ? this.type(cell) : 'flag'
87
+ const type_ = this.type ? this.type(cell, resolution, z, viewScale) : 'flag'
101
88
 
102
89
  //compute center position
103
- const xc = cell.x + offset.dx + (type_ === 'agepyramid' ? 0 : r * 0.5)
104
- const yc = cell.y + offset.dy + (type_ === 'agepyramid' ? 0 : r * 0.5)
90
+ const xc = cell.x + offset.dx + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
91
+ const yc = cell.y + offset.dy + (type_ === 'agepyramid' ? 0 : resolution * 0.5)
105
92
 
106
93
  //compute offset angle, when relevant
107
- const offAng = this.offsetAngle ? (this.offsetAngle(cell, r, zf) * Math.PI) / 180 : 0
94
+ const offAng = this.offsetAngle ? (this.offsetAngle(cell, resolution, z, viewScale) * Math.PI) / 180 : 0
108
95
 
109
96
  if (type_ === 'agepyramid' || type_ === 'radar' || type_ === 'halftone') {
110
97
  //get cell category max value
@@ -117,22 +104,22 @@ export class CompositionStyle extends Style {
117
104
  //cumul
118
105
  let cumul = 0
119
106
  if (type_ === 'agepyramid' && this.agePyramidHeight)
120
- cumul = (r - this.agePyramidHeight(cell, r, zf)) / 2
107
+ cumul = (resolution - this.agePyramidHeight(cell, resolution, z, viewScale)) / 2
121
108
  if (type_ === 'radar' || type_ === 'halftone') cumul = Math.PI / 2 + offAng
122
109
 
123
110
  //compute the increment, which is the value to increment the cumul for each category
124
111
  const incr =
125
112
  type_ === 'agepyramid'
126
- ? (this.agePyramidHeight ? this.agePyramidHeight(cell, r, zf) : r) / nbCat
113
+ ? (this.agePyramidHeight ? this.agePyramidHeight(cell, resolution, z, viewScale) : resolution) / nbCat
127
114
  : type_ === 'radar' || type_ === 'halftone'
128
- ? (2 * Math.PI) / nbCat
129
- : undefined
115
+ ? (2 * Math.PI) / nbCat
116
+ : undefined
130
117
  if (incr === undefined) throw new Error('Unexpected symbol type:' + type_)
131
118
 
132
119
  for (let [column, color] of Object.entries(this.color)) {
133
120
  if (type_ === 'agepyramid') {
134
121
  //set category color
135
- cg.ctx.fillStyle = color
122
+ geoCanvas.ctx.fillStyle = color
136
123
 
137
124
  //get category value
138
125
  const val = cell[column]
@@ -142,34 +129,34 @@ export class CompositionStyle extends Style {
142
129
  const wG = (sG * val) / maxVal
143
130
 
144
131
  //draw bar
145
- cg.ctx.fillRect(xc + (r - wG) / 2, yc + cumul, wG, incr)
132
+ geoCanvas.ctx.fillRect(xc + (resolution - wG) / 2, yc + cumul, wG, incr)
146
133
 
147
134
  //next height
148
135
  cumul += incr
149
136
  } else if (type_ === 'radar') {
150
137
  //set category color
151
- cg.ctx.fillStyle = color
138
+ geoCanvas.ctx.fillStyle = color
152
139
 
153
140
  //get categroy value
154
141
  const val = cell[column]
155
142
 
156
143
  //compute category radius - in geo
157
144
  /** @type {number} */
158
- //const rG = this.radius(val, r, stat, cellStat, zf)
145
+ //const rG = this.radius(val, r, stat, cellStat, z)
159
146
  const rG = (sG / 2) * Math.sqrt(val / maxVal)
160
147
 
161
148
  //draw angular sector
162
- cg.ctx.beginPath()
163
- cg.ctx.moveTo(xc, yc)
164
- cg.ctx.arc(xc, yc, rG, cumul - incr, cumul)
165
- cg.ctx.lineTo(xc, yc)
166
- cg.ctx.fill()
149
+ geoCanvas.ctx.beginPath()
150
+ geoCanvas.ctx.moveTo(xc, yc)
151
+ geoCanvas.ctx.arc(xc, yc, rG, cumul - incr, cumul)
152
+ geoCanvas.ctx.lineTo(xc, yc)
153
+ geoCanvas.ctx.fill()
167
154
 
168
155
  //next angular sector
169
156
  cumul += incr
170
157
  } else if (type_ === 'halftone') {
171
158
  //set category color
172
- cg.ctx.fillStyle = color
159
+ geoCanvas.ctx.fillStyle = color
173
160
 
174
161
  //get categroy value
175
162
  const val = cell[column]
@@ -179,15 +166,15 @@ export class CompositionStyle extends Style {
179
166
  const rG = sG * 0.333 * Math.sqrt(val / maxVal)
180
167
 
181
168
  //draw circle
182
- cg.ctx.beginPath()
183
- cg.ctx.arc(
184
- xc + r * 0.25 * Math.cos(cumul),
185
- yc + r * 0.25 * Math.sin(cumul),
169
+ geoCanvas.ctx.beginPath()
170
+ geoCanvas.ctx.arc(
171
+ xc + resolution * 0.25 * Math.cos(cumul),
172
+ yc + resolution * 0.25 * Math.sin(cumul),
186
173
  rG,
187
174
  0,
188
175
  2 * Math.PI
189
176
  )
190
- cg.ctx.fill()
177
+ geoCanvas.ctx.fill()
191
178
 
192
179
  //next angular sector
193
180
  cumul += incr
@@ -207,8 +194,8 @@ export class CompositionStyle extends Style {
207
194
 
208
195
  //draw decomposition symbol
209
196
  let cumul = 0
210
- const d = r * (1 - sG / r) * 0.5
211
- const ori = this.stripesOrientation(cell, r, zf)
197
+ const d = resolution * (1 - sG / resolution) * 0.5
198
+ const ori = this.stripesOrientation(cell, resolution, z, viewScale)
212
199
 
213
200
  for (let [column, color] of Object.entries(this.color)) {
214
201
  //get share
@@ -216,14 +203,14 @@ export class CompositionStyle extends Style {
216
203
  if (!share || isNaN(share)) continue
217
204
 
218
205
  //set color
219
- cg.ctx.fillStyle = color
206
+ geoCanvas.ctx.fillStyle = color
220
207
 
221
208
  //draw symbol part
222
209
  if (type_ === 'flag') {
223
210
  //draw flag stripe
224
211
  if (ori == 0) {
225
212
  //horizontal
226
- cg.ctx.fillRect(
213
+ geoCanvas.ctx.fillRect(
227
214
  cell.x + d + offset.dx,
228
215
  cell.y + d + cumul * sG + offset.dy,
229
216
  sG,
@@ -231,7 +218,7 @@ export class CompositionStyle extends Style {
231
218
  )
232
219
  } else {
233
220
  //vertical
234
- cg.ctx.fillRect(
221
+ geoCanvas.ctx.fillRect(
235
222
  cell.x + d + cumul * sG + offset.dx,
236
223
  cell.y + d + offset.dy,
237
224
  share * sG,
@@ -246,11 +233,11 @@ export class CompositionStyle extends Style {
246
233
  const a2 = (cumul + share) * 2 * Math.PI
247
234
 
248
235
  //draw
249
- cg.ctx.beginPath()
250
- cg.ctx.moveTo(xc, yc)
251
- cg.ctx.arc(xc, yc, sG * 0.5, a1 + offAng, a2 + offAng)
236
+ geoCanvas.ctx.beginPath()
237
+ geoCanvas.ctx.moveTo(xc, yc)
238
+ geoCanvas.ctx.arc(xc, yc, sG * 0.5, a1 + offAng, a2 + offAng)
252
239
  if (this.pieChartInternalRadiusFactor)
253
- cg.ctx.arc(
240
+ geoCanvas.ctx.arc(
254
241
  xc,
255
242
  yc,
256
243
  sG * 0.5 * this.pieChartInternalRadiusFactor,
@@ -258,30 +245,30 @@ export class CompositionStyle extends Style {
258
245
  a2 + offAng,
259
246
  true
260
247
  )
261
- cg.ctx.closePath()
262
- cg.ctx.fill()
248
+ geoCanvas.ctx.closePath()
249
+ geoCanvas.ctx.fill()
263
250
  } else if (type_ === 'ring') {
264
251
  //draw ring
265
- cg.ctx.beginPath()
266
- cg.ctx.arc(xc, yc, Math.sqrt(1 - cumul) * sG * 0.5, 0, 2 * Math.PI)
267
- cg.ctx.fill()
252
+ geoCanvas.ctx.beginPath()
253
+ geoCanvas.ctx.arc(xc, yc, Math.sqrt(1 - cumul) * sG * 0.5, 0, 2 * Math.PI)
254
+ geoCanvas.ctx.fill()
268
255
  } else if (type_ === 'segment') {
269
256
  //draw segment sections
270
- const wG = (sG * sG) / r
257
+ const wG = (sG * sG) / resolution
271
258
  if (ori == 0) {
272
259
  //horizontal
273
- cg.ctx.fillRect(
260
+ geoCanvas.ctx.fillRect(
274
261
  cell.x + offset.dx,
275
- cell.y + (r - wG) / 2 + cumul * wG + offset.dy,
276
- r,
262
+ cell.y + (resolution - wG) / 2 + cumul * wG + offset.dy,
263
+ resolution,
277
264
  share * wG
278
265
  )
279
266
  } else {
280
267
  //vertical
281
- cg.ctx.fillRect(
282
- cell.x + cumul * r + offset.dx,
283
- cell.y + (r - wG) / 2 + offset.dy,
284
- share * r,
268
+ geoCanvas.ctx.fillRect(
269
+ cell.x + cumul * resolution + offset.dx,
270
+ cell.y + (resolution - wG) / 2 + offset.dy,
271
+ share * resolution,
285
272
  wG
286
273
  )
287
274
  }
@@ -295,6 +282,6 @@ export class CompositionStyle extends Style {
295
282
  }
296
283
 
297
284
  //update legends
298
- this.updateLegends({ style: this, r: r, zf: zf, sSize: stat })
285
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
299
286
  }
300
287
  }
@@ -13,42 +13,8 @@ export class ContourStyle extends SideStyle {
13
13
  /** @param {object} opts */
14
14
  constructor(opts) {
15
15
  super(opts)
16
- opts = opts || {}
16
+ //opts = opts || {}
17
17
 
18
- /** @type {number} */
19
- //opts.interval = opts.interval || 100
20
-
21
- /** @type {Array.<number>} */
22
- opts.breaks = opts.breaks || [100, 1000, 10000, 100000, 1000000]
23
-
24
- /** @type {function(Side,number,number):string} */
25
- opts.width = opts.width || (() => 1) //(s, r, zf) => ...
26
-
27
- /** @type {function(Side,number,number):string} */
28
- opts.color = opts.color || (() => '#E7A935') //(s, r, zf) => ...
29
-
30
- //override method for contour drawing
31
-
32
- const getClass = function (v) {
33
- if (v == undefined) return 0
34
- for (let i = 0; i < opts.breaks.length; i++) if (v < opts.breaks[i]) return i
35
- return opts.breaks.length
36
- }
37
-
38
- this.value = (v1, v2, r, s, zf) => {
39
- //if (!v1 || !v2) return 0
40
- return Math.abs(getClass(v2) - getClass(v1))
41
-
42
- //check if v1 - v2 cross a contour line
43
- //const r1 = Math.floor(v1 / opts.interval);
44
- //const r2 = Math.floor(v2 / opts.interval);
45
- //return Math.abs(r2 - r1);
46
- }
47
-
48
- //same color for all
49
- this.color = (side, r, s, zf) => (side.value ? opts.color(side, r, zf) : undefined)
50
-
51
- //width: multiple of
52
- this.width = (side, r, s, zf) => side.value * zf * opts.width(side, r, zf)
18
+ //TODO
53
19
  }
54
20
  }