gridviz 3.0.1 → 3.0.3

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 (58) hide show
  1. package/README.md +36 -33
  2. package/dist/gridviz.js +1300 -200
  3. package/dist/gridviz.min.js +1 -1
  4. package/package.json +4 -3
  5. package/src/button/Button.js +1 -0
  6. package/src/button/FullscreenButton.js +1 -0
  7. package/src/button/ZoomButtons.js +1 -0
  8. package/src/core/Dataset.js +1 -0
  9. package/src/core/Drawable.js +1 -0
  10. package/src/core/GeoCanvas.js +1 -0
  11. package/src/core/Layer.js +1 -0
  12. package/src/core/Legend.js +1 -0
  13. package/src/core/Map.js +1 -0
  14. package/src/core/MultiResolutionDataset.js +1 -0
  15. package/src/core/Style.js +11 -2
  16. package/src/core/Tooltip.js +1 -0
  17. package/src/dataset/COGeo.js +1 -0
  18. package/src/dataset/CSVGrid.js +1 -0
  19. package/src/dataset/GeoTIFF.js +1 -0
  20. package/src/dataset/JSGrid.js +1 -0
  21. package/src/dataset/TiledGrid.js +1 -0
  22. package/src/index.js +7 -3
  23. package/src/layer/BackgroundLayer.js +1 -0
  24. package/src/layer/BackgroundLayerWMS.js +1 -0
  25. package/src/layer/GeoJSONLayer.js +1 -0
  26. package/src/layer/GridLayer.js +1 -0
  27. package/src/layer/LabelLayer.js +1 -0
  28. package/src/legend/ColorCategoryLegend.js +1 -0
  29. package/src/legend/ColorDiscreteLegend.js +2 -0
  30. package/src/legend/ColorLegend.js +1 -0
  31. package/src/legend/OrientationLegend.js +1 -0
  32. package/src/legend/SizeLegend.js +4 -2
  33. package/src/legend/TrivariateLegend.js +210 -0
  34. package/src/style/CompositionStyle.js +1 -0
  35. package/src/style/ContourStyle.js +1 -0
  36. package/src/style/DotDensityStyle.js +1 -0
  37. package/src/style/ImageStyle.js +81 -0
  38. package/src/style/IsoFenceStyle.js +24 -72
  39. package/src/style/JoyPlotStyle.js +1 -1
  40. package/src/style/LegoStyle.js +22 -24
  41. package/src/style/MosaicStyle.js +1 -0
  42. package/src/style/NinjaStarStyle.js +1 -1
  43. package/src/style/PillarStyle.js +3 -2
  44. package/src/style/SegmentStyle.js +2 -1
  45. package/src/style/ShapeColorSizeStyle.js +29 -0
  46. package/src/style/SideCategoryStyle.js +1 -0
  47. package/src/style/SideStyle.js +50 -27
  48. package/src/style/SquareColorCategoryWebGLStyle.js +4 -3
  49. package/src/style/SquareColorWebGLStyle.js +1 -0
  50. package/src/style/StrokeStyle.js +48 -16
  51. package/src/style/TanakaStyle.js +11 -5
  52. package/src/style/TextStyle.js +1 -1
  53. package/src/style/TimeSeriesStyle.js +1 -0
  54. package/src/utils/chernoff.js +14 -0
  55. package/src/utils/scale.js +22 -11
  56. package/src/utils/stretching.js +4 -0
  57. package/src/utils/trivariate.js +203 -0
  58. package/src/utils/utils.js +11 -0
@@ -0,0 +1,81 @@
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 ImageStyle extends Style {
11
+
12
+ /** @param {object} opts */
13
+ constructor(opts) {
14
+ super(opts)
15
+ opts = opts || {}
16
+
17
+ /** A function returning the image code of a cell.
18
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
19
+ this.imageCode = opts.imageCode || (() => '') //(c,r,z,vs) => {}
20
+
21
+ /** The dictionnary code -> image
22
+ * @type {object} */
23
+ this.images = opts.images || {}
24
+
25
+ /** The image size in ground meters
26
+ * @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
27
+ this.size = opts.size || ((cell, resolution) => resolution)
28
+ }
29
+
30
+ /**
31
+ * @param {Array.<import("../core/Dataset.js").Cell>} cells
32
+ * @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
33
+ * @param {number} resolution
34
+ * @override
35
+ */
36
+ draw(cells, geoCanvas, resolution) {
37
+
38
+ //
39
+ const z = geoCanvas.view.z,
40
+ resolutionPix = resolution / z
41
+
42
+ //get view scale
43
+ const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
44
+
45
+ //draw in screen coordinates
46
+ geoCanvas.initCanvasTransform()
47
+
48
+ //
49
+ for (let cell of cells) {
50
+
51
+ //get cell image code
52
+ const code = this.imageCode(cell, resolution, z, viewScale)
53
+
54
+ //get image
55
+ const image = this.images[code]
56
+ if (!image) continue
57
+
58
+ //size and position values
59
+ let sizePix = this.size(cell, resolution, z, viewScale) / z
60
+ if (!sizePix) continue
61
+ const d = (resolutionPix - sizePix) / 2
62
+
63
+ try {
64
+ geoCanvas.ctx.drawImage(image, geoCanvas.geoToPixX(cell.x) + d, geoCanvas.geoToPixY(cell.y) + d -resolutionPix, sizePix, sizePix)
65
+
66
+ /*/red color filter
67
+ geoCanvas.ctx.globalCompositeOperation = 'source-in';
68
+ geoCanvas.ctx.fillStyle = 'red';
69
+ geoCanvas.ctx.fillRect(geoCanvas.geoToPixX(cell.x) + d, geoCanvas.geoToPixY(cell.y) + d, sizePix, sizePix);
70
+ geoCanvas.ctx.globalCompositeOperation = 'source-over';*/
71
+ } catch (error) {
72
+ console.error(error)
73
+ }
74
+
75
+ }
76
+
77
+
78
+ //update legends
79
+ this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
80
+ }
81
+ }
@@ -7,6 +7,7 @@ import { SideStyle } from './SideStyle.js'
7
7
  /** @typedef {{x:number,y:number,or:"v"|"h",c1:import('../core/Dataset.js').Cell|undefined,c2:import('../core/Dataset.js').Cell|undefined}} Side */
8
8
 
9
9
  /**
10
+ * @module style
10
11
  * @author Julien Gaffuri
11
12
  */
12
13
  export class IsoFenceStyle extends Style {
@@ -77,57 +78,7 @@ export class IsoFenceStyle extends Style {
77
78
 
78
79
  //make sides
79
80
  /** @type {Array.<Side>} */
80
- const sides = SideStyle.buildSides(cells, resolution, this.angle % 180 != 90 && this.sVert, this.angle % 180 != 0 && this.sHor, true)
81
-
82
-
83
-
84
- /*const sides = []
85
-
86
- //make horizontal sides - except when angle%180=0
87
- //sort cells by x and y
88
- if (this.angle % 180 != 90 && this.sVert) {
89
- cells.sort((c1, c2) => (c2.x == c1.x ? c1.y - c2.y : c1.x - c2.x))
90
- let c1 = cells[0]
91
- for (let i = 1; i < cells.length; i++) {
92
- let c2 = cells[i]
93
-
94
- if ((c1.y + resolution == c2.y) && (c1.x == c2.x))
95
- //cells in same column and touch along horizontal side
96
- //make shared side
97
- sides.push({ x: c1.x + r2, y: c2.y, or: 'h', c1: c1, c2: c2 })
98
- else {
99
- //cells do not touch along horizontal side
100
- //make two sides: top one for c1, bottom for c2
101
- sides.push({ x: c1.x + r2, y: c1.y + resolution, or: 'h', c1: c1, c2: undefined })
102
- sides.push({ x: c2.x + r2, y: c2.y, or: 'h', c1: undefined, c2: c2 })
103
- }
104
-
105
- c1 = c2
106
- }
107
- }
108
-
109
- //make vertical sides - except when angle%180=90
110
- //sort cells by y and x
111
- if (this.angle % 180 != 0 && this.sHor) {
112
- cells.sort((c1, c2) => (c2.y == c1.y ? c1.x - c2.x : c1.y - c2.y))
113
- let c1 = cells[0]
114
- for (let i = 1; i < cells.length; i++) {
115
- let c2 = cells[i]
116
-
117
- if ((c1.x + resolution == c2.x) && (c1.y == c2.y))
118
- //cells in same row and touch along vertical side
119
- //make shared side
120
- sides.push({ x: c2.x, y: c1.y + r2, or: 'v', c1: c1, c2: c2 })
121
- else {
122
- //cells do not touch along vertical side
123
- //make two sides: right one for c1, left for c2
124
- sides.push({ x: c1.x + resolution, y: c1.y + r2, or: 'v', c1: c1, c2: undefined })
125
- sides.push({ x: c2.x, y: c2.y + r2, or: 'v', c1: undefined, c2: c2 })
126
- }
127
-
128
- c1 = c2
129
- }
130
- }*/
81
+ const sides = SideStyle.buildSides(cells, resolution, this.angle % 180 != 90 && this.sVert, this.angle % 180 != 0 && this.sHor)
131
82
 
132
83
  //
133
84
  if (sides.length == 0) return
@@ -163,15 +114,16 @@ export class IsoFenceStyle extends Style {
163
114
 
164
115
  //draw sides
165
116
  geoCanvas.ctx.lineCap = "round";
166
- for (let s of sides) {
117
+ for (let side of sides) {
118
+ const c1 = side.c1, c2 = side.c2, x = side.x, y = side.y
167
119
 
168
120
  //heights - in geo
169
- const hG1 = s.c1 ? this.height(s.c1, resolution, z, viewScale) : 0,
170
- hG2 = s.c2 ? this.height(s.c2, resolution, z, viewScale) : 0
121
+ const hG1 = c1 ? this.height(c1, resolution, z, viewScale) : 0,
122
+ hG2 = c2 ? this.height(c2, resolution, z, viewScale) : 0
171
123
 
172
124
  //compute totals for both cells
173
- const total1 = computeTotal(s.c1, cats),
174
- total2 = computeTotal(s.c2, cats)
125
+ const total1 = computeTotal(c1, cats),
126
+ total2 = computeTotal(c2, cats)
175
127
  if (total1 == 0 && total2 == 0) continue
176
128
 
177
129
  let cumul1 = 0, cumul2 = 0
@@ -179,8 +131,8 @@ export class IsoFenceStyle extends Style {
179
131
  //draw stripe of side s and category column
180
132
 
181
133
  //get values for both cells
182
- let v1 = s.c1 ? +s.c1[column] : 0
183
- let v2 = s.c2 ? +s.c2[column] : 0
134
+ let v1 = c1 ? +c1[column] : 0
135
+ let v2 = c2 ? +c2[column] : 0
184
136
  if (v1 == 0 && v2 == 0) continue
185
137
 
186
138
  //compute heights
@@ -191,26 +143,26 @@ export class IsoFenceStyle extends Style {
191
143
 
192
144
  //make path
193
145
  geoCanvas.ctx.beginPath()
194
- if (s.or == "h") {
146
+ if (side.or == "h") {
195
147
  //horizontal side - vertical section
196
148
  //bottom left
197
- geoCanvas.ctx.moveTo(s.x + h1 * cos + dx, s.y - r2 + h1 * sin + dy)
149
+ geoCanvas.ctx.moveTo(x + h1 * cos + dx, y - r2 + h1 * sin + dy)
198
150
  //top left
199
- geoCanvas.ctx.lineTo(s.x + h2 * cos + dx, s.y + r2 + h2 * sin + dy)
151
+ geoCanvas.ctx.lineTo(x + h2 * cos + dx, y + r2 + h2 * sin + dy)
200
152
  //top right
201
- geoCanvas.ctx.lineTo(s.x + h2n * cos + dx, s.y + r2 + h2n * sin + dy)
153
+ geoCanvas.ctx.lineTo(x + h2n * cos + dx, y + r2 + h2n * sin + dy)
202
154
  //bottom right
203
- geoCanvas.ctx.lineTo(s.x + h1n * cos + dx, s.y - r2 + h1n * sin + dy)
155
+ geoCanvas.ctx.lineTo(x + h1n * cos + dx, y - r2 + h1n * sin + dy)
204
156
  } else {
205
157
  //vertical side - horizontal section
206
158
  //bottom left
207
- geoCanvas.ctx.moveTo(s.x - r2 + h1 * cos + dx, s.y + h1 * sin + dy)
159
+ geoCanvas.ctx.moveTo(x - r2 + h1 * cos + dx, y + h1 * sin + dy)
208
160
  //bottom right
209
- geoCanvas.ctx.lineTo(s.x + r2 + h2 * cos + dx, s.y + h2 * sin + dy)
161
+ geoCanvas.ctx.lineTo(x + r2 + h2 * cos + dx, y + h2 * sin + dy)
210
162
  //top right
211
- geoCanvas.ctx.lineTo(s.x + r2 + h2n * cos + dx, s.y + h2n * sin + dy)
163
+ geoCanvas.ctx.lineTo(x + r2 + h2n * cos + dx, y + h2n * sin + dy)
212
164
  //top left
213
- geoCanvas.ctx.lineTo(s.x - r2 + h1n * cos + dx, s.y + h1n * sin + dy)
165
+ geoCanvas.ctx.lineTo(x - r2 + h1n * cos + dx, y + h1n * sin + dy)
214
166
  }
215
167
  //cg.ctx.closePath()
216
168
 
@@ -223,11 +175,11 @@ export class IsoFenceStyle extends Style {
223
175
 
224
176
  //TODO draw only one line
225
177
  //draw corner line
226
- //if (s.or == "h") {
227
- drawCornerLine(s.c1)
228
- drawCornerLine(s.c2)
229
- //if (this.angle > 0 && s.or == "h") drawCornerLine(s.c2)
230
- //else drawCornerLine(s.c2)
178
+ //if (side.or == "h") {
179
+ drawCornerLine(c1)
180
+ drawCornerLine(c2)
181
+ //if (this.angle > 0 && side.or == "h") drawCornerLine(c2)
182
+ //else drawCornerLine(c2)
231
183
  //}
232
184
  }
233
185
  }
@@ -4,7 +4,7 @@
4
4
  import { Style } from '../core/Style.js'
5
5
 
6
6
  /**
7
- *
7
+ * @module style
8
8
  * @author Julien Gaffuri
9
9
  */
10
10
  export class JoyPlotStyle extends Style {
@@ -7,21 +7,18 @@ import { SquareColorCategoryWebGLStyle } from './SquareColorCategoryWebGLStyle.j
7
7
  import { Style } from '../core/Style.js'
8
8
 
9
9
  /**
10
+ * @module style
10
11
  * @author Julien Gaffuri
11
12
  */
12
13
  export class LegoStyle {
13
- /**
14
- * @param {string} col
15
- * @param {object} opts
16
- * @returns {Array.<Style>}
17
- */
18
- static get(col, opts) {
14
+
15
+ static get(value, breaks, colors, opts = {}) {
19
16
  opts = opts || {}
20
17
 
21
18
  //the colors
22
19
  //http://www.jennyscrayoncollection.com/2021/06/all-current-lego-colors.html
23
20
  //https://leonawicz.github.io/legocolors/reference/figures/README-plot-1.png
24
- opts.colors = opts.colors || [
21
+ /*opts.colors = opts.colors || [
25
22
  '#00852b', //darker green
26
23
  '#afd246', //light green
27
24
  '#fac80a', //dark yellow
@@ -32,18 +29,18 @@ export class LegoStyle {
32
29
  '#720012', //dark red
33
30
  //"purple",
34
31
  //"#eee" //whithe
35
- ]
32
+ ]*/
36
33
 
37
34
  opts.colDark = opts.colDark || '#333'
38
35
  opts.colBright = opts.colBright || '#aaa'
39
36
  opts.widthFactor = opts.widthFactor || 0.12
40
37
 
41
38
  //reuse tanaka as basis
42
- const ts = TanakaStyle.get(col, opts)
39
+ const ts = TanakaStyle.get(value, breaks, colors, opts)
43
40
  //style to show limits between pieces
44
41
  const sst = new StrokeStyle({
45
42
  strokeColor: () => '#666',
46
- strokeWidth: (v, r, s, z) => 0.2 * z,
43
+ strokeWidth: (c, r, z) => 0.2 * z,
47
44
  filter: opts.filter,
48
45
  })
49
46
 
@@ -56,20 +53,21 @@ export class LegoStyle {
56
53
  }
57
54
 
58
55
  /**
59
- * @param {function(string):string} col
56
+ * @param {function(import('../core/Dataset.js').Cell):string} code
57
+ * @param {object} color
60
58
  * @param {object} opts
61
59
  * @returns {Array.<Style>}
62
60
  */
63
- static getCat(col, opts) {
61
+ static getCategory(code, color, opts) {
64
62
  opts = opts || {}
65
63
 
66
64
  opts.colDark = opts.colDark || '#333'
67
65
  opts.colBright = opts.colBright || '#aaa'
68
66
 
69
67
  //
70
- const s = new SquareColorCategoryWebGLStyle({ colorCol: col, color: opts.color })
68
+ const s = new SquareColorCategoryWebGLStyle({ code: code, color: color })
71
69
  //style to show limits between pieces
72
- const sst = new StrokeStyle({ strokeColor: () => '#666', strokeWidth: (v, r, s, z) => 0.2 * z })
70
+ const sst = new StrokeStyle({ strokeColor: () => '#666', strokeWidth: (c, r, z) => 0.2 * z })
73
71
 
74
72
  return [s, sst, new LegoTopStyle({ colDark: opts.colDark, colBright: opts.colBright })]
75
73
  }
@@ -87,26 +85,26 @@ class LegoTopStyle extends Style {
87
85
  this.colBright = opts.colBright || '#aaa'
88
86
  }
89
87
 
90
- draw(cells, r, cg) {
88
+ draw(cells, geoCanvas, r) {
91
89
  //filter
92
90
  if (this.filter) cells = cells.filter(this.filter)
93
91
 
94
- cg.ctx.lineWidth = 0.6 * cg.view.z
92
+ geoCanvas.ctx.lineWidth = 0.6 * geoCanvas.view.z
95
93
 
96
94
  //dark part
97
- cg.ctx.strokeStyle = this.colDark
95
+ geoCanvas.ctx.strokeStyle = this.colDark
98
96
  for (let c of cells) {
99
- cg.ctx.beginPath()
100
- cg.ctx.arc(c.x + r * 0.5, c.y + r * 0.5, r * 0.55 * 0.5, Math.PI / 4, -Math.PI * (3 / 4), true)
101
- cg.ctx.stroke()
97
+ geoCanvas.ctx.beginPath()
98
+ geoCanvas.ctx.arc(c.x + r * 0.5, c.y + r * 0.5, r * 0.55 * 0.5, Math.PI / 4, -Math.PI * (3 / 4), true)
99
+ geoCanvas.ctx.stroke()
102
100
  }
103
101
 
104
102
  //bright part
105
- cg.ctx.strokeStyle = this.colBright
103
+ geoCanvas.ctx.strokeStyle = this.colBright
106
104
  for (let c of cells) {
107
- cg.ctx.beginPath()
108
- cg.ctx.arc(c.x + r * 0.5, c.y + r * 0.5, r * 0.55 * 0.5, Math.PI / 4, -Math.PI * (3 / 4), false)
109
- cg.ctx.stroke()
105
+ geoCanvas.ctx.beginPath()
106
+ geoCanvas.ctx.arc(c.x + r * 0.5, c.y + r * 0.5, r * 0.55 * 0.5, Math.PI / 4, -Math.PI * (3 / 4), false)
107
+ geoCanvas.ctx.stroke()
110
108
  }
111
109
  }
112
110
  }
@@ -4,6 +4,7 @@
4
4
  import { Style } from '../core/Style.js'
5
5
 
6
6
  /**
7
+ * @module style
7
8
  * @author Julien Gaffuri
8
9
  */
9
10
  export class MosaicStyle extends Style {
@@ -4,7 +4,7 @@
4
4
  import { Style } from '../core/Style.js'
5
5
 
6
6
  /**
7
- *
7
+ * @module style
8
8
  * @author Joseph Davies, Julien Gaffuri
9
9
  */
10
10
  export class NinjaStarStyle extends Style {
@@ -4,6 +4,7 @@
4
4
  import { Style } from '../core/Style.js'
5
5
 
6
6
  /**
7
+ * @module style
7
8
  * @author Julien Gaffuri
8
9
  */
9
10
  export class PillarStyle extends Style {
@@ -106,7 +107,7 @@ export class PillarStyle extends Style {
106
107
  //set width
107
108
  geoCanvas.ctx.lineWidth = wG
108
109
 
109
- //compute cell centre postition
110
+ //compute cell center postition
110
111
  const cx = cell.x + resolution / 2
111
112
  const cy = cell.y + resolution / 2
112
113
  const ls = hG * this.shadowFactor
@@ -151,7 +152,7 @@ export class PillarStyle extends Style {
151
152
  //TODO use that
152
153
  //const offset = this.offset(c, resolution, z)
153
154
 
154
- //compute cell centre postition
155
+ //compute cell center postition
155
156
  const cx = cell.x + resolution / 2
156
157
  const cy = cell.y + resolution / 2
157
158
 
@@ -6,6 +6,7 @@ import { Style } from '../core/Style.js'
6
6
  /**
7
7
  * A style where each cell is represented by a segment whose length, width, color and orientation can vary according to statistical values.
8
8
  *
9
+ * @module style
9
10
  * @author Julien Gaffuri
10
11
  */
11
12
  export class SegmentStyle extends Style {
@@ -83,7 +84,7 @@ export class SegmentStyle extends Style {
83
84
  geoCanvas.ctx.strokeStyle = col
84
85
  geoCanvas.ctx.lineWidth = wG
85
86
 
86
- //compute segment centre postition
87
+ //compute segment center postition
87
88
  const cx = cell.x + resolution / 2 + offset.dx
88
89
  const cy = cell.y + resolution / 2 + offset.dy
89
90
 
@@ -7,6 +7,7 @@ import { Style } from '../core/Style.js'
7
7
  * A very generic style that shows grid cells with specific color, size and shape.
8
8
  * It can be used to show variables as cell colors, cell size, cell shape, or any combination of the three visual variables.
9
9
  *
10
+ * @module style
10
11
  * @author Joseph Davies, Julien Gaffuri
11
12
  */
12
13
  export class ShapeColorSizeStyle extends Style {
@@ -92,6 +93,34 @@ export class ShapeColorSizeStyle extends Style {
92
93
  geoCanvas.ctx.lineTo(c.x + r2 + s2, c.y + r2)
93
94
  geoCanvas.ctx.lineTo(c.x + r2, c.y + r2 - s2)
94
95
  geoCanvas.ctx.fill()
96
+ } else if (shape === 'triangle_up') {
97
+ const dr2 = (size - resolution) / 2
98
+ geoCanvas.ctx.beginPath()
99
+ geoCanvas.ctx.moveTo(c.x - dr2, c.y - dr2)
100
+ geoCanvas.ctx.lineTo(c.x + r2, c.y + resolution + dr2)
101
+ geoCanvas.ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
102
+ geoCanvas.ctx.fill()
103
+ } else if (shape === 'triangle_down') {
104
+ const dr2 = (size - resolution) / 2
105
+ geoCanvas.ctx.beginPath()
106
+ geoCanvas.ctx.moveTo(c.x - dr2, c.y + resolution + dr2)
107
+ geoCanvas.ctx.lineTo(c.x + r2, c.y - dr2)
108
+ geoCanvas.ctx.lineTo(c.x + resolution + dr2, c.y + resolution + dr2)
109
+ geoCanvas.ctx.fill()
110
+ } else if (shape === 'triangle_left') {
111
+ const dr2 = (size - resolution) / 2
112
+ geoCanvas.ctx.beginPath()
113
+ geoCanvas.ctx.moveTo(c.x + resolution + dr2, c.y + resolution + dr2)
114
+ geoCanvas.ctx.lineTo(c.x - dr2, c.y + r2)
115
+ geoCanvas.ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
116
+ geoCanvas.ctx.fill()
117
+ } else if (shape === 'triangle_right') {
118
+ const dr2 = (size - resolution) / 2
119
+ geoCanvas.ctx.beginPath()
120
+ geoCanvas.ctx.moveTo(c.x - dr2, c.y - dr2)
121
+ geoCanvas.ctx.lineTo(c.x + resolution + dr2, c.y + r2)
122
+ geoCanvas.ctx.lineTo(c.x - dr2, c.y + resolution + dr2)
123
+ geoCanvas.ctx.fill()
95
124
  } else {
96
125
  throw new Error('Unexpected shape:' + shape)
97
126
  }
@@ -6,6 +6,7 @@ import { SideStyle } from './SideStyle.js'
6
6
  /**
7
7
  * A style to show the sides of grid cells based on their different categories.
8
8
  *
9
+ * @module style
9
10
  * @author Julien Gaffuri
10
11
  */
11
12
  export class SideCategoryStyle extends SideStyle {
@@ -9,7 +9,7 @@ import { Style } from '../core/Style.js'
9
9
  * @typedef {function(Array.<Side>,number, number):*} SideViewScale */
10
10
 
11
11
  /**
12
- *
12
+ * @module style
13
13
  * @author Julien Gaffuri
14
14
  */
15
15
  export class SideStyle extends Style {
@@ -28,6 +28,9 @@ export class SideStyle extends Style {
28
28
  /** A function returning the length of a cell side, in geo unit
29
29
  * @type {function(Side, number, number, object):number} */
30
30
  this.length = opts.length || ((side, resolution, z, sideViewScale) => resolution)
31
+
32
+ /** Set to A or true so that the side is drawn as a diamond */
33
+ this.diamond = opts.diamond
31
34
  }
32
35
 
33
36
  /**
@@ -63,31 +66,51 @@ export class SideStyle extends Style {
63
66
  const col = this.color ? this.color(side, resolution, z, viewScale) : undefined
64
67
  if (!col || col == 'none') continue
65
68
 
66
- //width
67
- /** @type {number|undefined} */
68
- const wG = this.width ? this.width(side, resolution, z, viewScale) : undefined
69
- if (!wG || wG <= 0) continue
70
-
71
- //length
72
- /** @type {number|undefined} */
73
- const lG = this.length ? this.length(side, resolution, z, viewScale) : undefined
74
- if (!lG || lG <= 0) continue
75
- const lG2 = lG * 0.5
76
-
77
- //set color and width
78
- geoCanvas.ctx.strokeStyle = col
79
- geoCanvas.ctx.lineWidth = wG
80
-
81
- //draw segment with correct orientation
82
- geoCanvas.ctx.beginPath()
83
- if (side.or === "v") {
84
- geoCanvas.ctx.moveTo(side.x, side.y + r2 - lG2)
85
- geoCanvas.ctx.lineTo(side.x, side.y + r2 + lG2)
69
+ if (this.diamond) {
70
+
71
+ //set color
72
+ geoCanvas.ctx.fillStyle = col
73
+
74
+ //draw diamond
75
+ const x = side.x, y = side.y
76
+ geoCanvas.ctx.beginPath()
77
+ geoCanvas.ctx.moveTo(x - r2, y)
78
+ geoCanvas.ctx.lineTo(x, y + r2)
79
+ geoCanvas.ctx.lineTo(x + r2, y)
80
+ geoCanvas.ctx.lineTo(x, y - r2)
81
+ geoCanvas.ctx.closePath()
82
+ geoCanvas.ctx.fill()
83
+
86
84
  } else {
87
- geoCanvas.ctx.moveTo(side.x + r2 - lG2, side.y)
88
- geoCanvas.ctx.lineTo(side.x + r2 + lG2, side.y)
85
+
86
+ //width
87
+ /** @type {number|undefined} */
88
+ const wG = this.width ? this.width(side, resolution, z, viewScale) : undefined
89
+ if (!wG || wG <= 0) continue
90
+
91
+ //length
92
+ /** @type {number|undefined} */
93
+ const lG = this.length ? this.length(side, resolution, z, viewScale) : undefined
94
+ if (!lG || lG <= 0) continue
95
+ const lG2 = lG * 0.5
96
+
97
+ //set width
98
+ geoCanvas.ctx.lineWidth = wG
99
+ //set color
100
+ geoCanvas.ctx.strokeStyle = col
101
+
102
+ //draw segment with correct orientation
103
+ const x = side.x, y = side.y
104
+ geoCanvas.ctx.beginPath()
105
+ if (side.or === "v") {
106
+ geoCanvas.ctx.moveTo(x, y - lG2)
107
+ geoCanvas.ctx.lineTo(x, y + lG2)
108
+ } else {
109
+ geoCanvas.ctx.moveTo(x - lG2, y)
110
+ geoCanvas.ctx.lineTo(x + lG2, y)
111
+ }
112
+ geoCanvas.ctx.stroke()
89
113
  }
90
- geoCanvas.ctx.stroke()
91
114
  }
92
115
 
93
116
  //update legends
@@ -98,14 +121,14 @@ export class SideStyle extends Style {
98
121
 
99
122
  /**
100
123
  *
101
- * @param {Array.<import('../core/Dataset').Cell>} cells The cells to use to build the sides. The side x,y coordinates are those of the left point for horizontal sides, and of the bottom point for vertical sides.
124
+ * @param {Array.<import('../core/Dataset').Cell>} cells The cells to use to build the sides.
102
125
  * @param {number} resolution The cells resolution
103
126
  * @param {boolean} withHorizontal Set to true to build horizontal sides, false otherwise.
104
127
  * @param {boolean} withVertical Set to true to build vertical sides, false otherwise.
105
- * @param {boolean} center Set to true so that the side coordinate are those of its center point rather than its left/bottom point.
128
+ * @param {boolean} center Set to true so that the side coordinate are those of its center point rather than its left/bottom point (the side x,y coordinates are those of the left point for horizontal sides, and of the bottom point for vertical sides)
106
129
  * @returns { Array.<Side> }
107
130
  */
108
- static buildSides(cells, resolution, withHorizontal = true, withVertical = true, center = false) {
131
+ static buildSides(cells, resolution, withHorizontal = true, withVertical = true, center = true) {
109
132
  /** @type { Array.<Side> } */
110
133
  const sides = []
111
134
 
@@ -10,6 +10,7 @@ import { WebGLSquareColoringCatAdvanced } from '../utils/WebGLSquareColoringCatA
10
10
  * To show cells as colored squares, from categories.
11
11
  * All cells are drawn as squares, with the same size
12
12
  *
13
+ * @module style
13
14
  * @author Julien Gaffuri
14
15
  */
15
16
  export class SquareColorCategoryWebGLStyle extends Style {
@@ -19,8 +20,8 @@ export class SquareColorCategoryWebGLStyle extends Style {
19
20
  opts = opts || {}
20
21
 
21
22
  /**
22
- * The name of the column/attribute of the tabular data where to retrieve the category code of the cell, for coloring.
23
- * @type {string} */
23
+ * A function returning the category code of the cell, for coloring.
24
+ * @type {function(import('../core/Dataset.js').Cell):string} */
24
25
  this.code = opts.code
25
26
 
26
27
  /**
@@ -71,7 +72,7 @@ export class SquareColorCategoryWebGLStyle extends Style {
71
72
  const iBuffer = []
72
73
  for (let i = 0; i < nb; i++) {
73
74
  c = cells[i]
74
- const cat = c[this.code]
75
+ const cat = this.code(c)
75
76
  if (cat == undefined) {
76
77
  console.log('Unexpected category: ' + cat)
77
78
  continue
@@ -10,6 +10,7 @@ import { WebGLSquareColoringAdvanced } from '../utils/WebGLSquareColoringAdvance
10
10
  * To show cells as colored squares, with computation of the colors on GPU side (faster than JavaScript side).
11
11
  * Alls squares with the same size
12
12
  *
13
+ * @module style
13
14
  * @author Julien Gaffuri
14
15
  */
15
16
  export class SquareColorWebGLStyle extends Style {