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.
- package/README.md +36 -33
- package/dist/gridviz.js +1300 -200
- package/dist/gridviz.min.js +1 -1
- package/package.json +4 -3
- package/src/button/Button.js +1 -0
- package/src/button/FullscreenButton.js +1 -0
- package/src/button/ZoomButtons.js +1 -0
- package/src/core/Dataset.js +1 -0
- package/src/core/Drawable.js +1 -0
- package/src/core/GeoCanvas.js +1 -0
- package/src/core/Layer.js +1 -0
- package/src/core/Legend.js +1 -0
- package/src/core/Map.js +1 -0
- package/src/core/MultiResolutionDataset.js +1 -0
- package/src/core/Style.js +11 -2
- package/src/core/Tooltip.js +1 -0
- package/src/dataset/COGeo.js +1 -0
- package/src/dataset/CSVGrid.js +1 -0
- package/src/dataset/GeoTIFF.js +1 -0
- package/src/dataset/JSGrid.js +1 -0
- package/src/dataset/TiledGrid.js +1 -0
- package/src/index.js +7 -3
- package/src/layer/BackgroundLayer.js +1 -0
- package/src/layer/BackgroundLayerWMS.js +1 -0
- package/src/layer/GeoJSONLayer.js +1 -0
- package/src/layer/GridLayer.js +1 -0
- package/src/layer/LabelLayer.js +1 -0
- package/src/legend/ColorCategoryLegend.js +1 -0
- package/src/legend/ColorDiscreteLegend.js +2 -0
- package/src/legend/ColorLegend.js +1 -0
- package/src/legend/OrientationLegend.js +1 -0
- package/src/legend/SizeLegend.js +4 -2
- package/src/legend/TrivariateLegend.js +210 -0
- package/src/style/CompositionStyle.js +1 -0
- package/src/style/ContourStyle.js +1 -0
- package/src/style/DotDensityStyle.js +1 -0
- package/src/style/ImageStyle.js +81 -0
- package/src/style/IsoFenceStyle.js +24 -72
- package/src/style/JoyPlotStyle.js +1 -1
- package/src/style/LegoStyle.js +22 -24
- package/src/style/MosaicStyle.js +1 -0
- package/src/style/NinjaStarStyle.js +1 -1
- package/src/style/PillarStyle.js +3 -2
- package/src/style/SegmentStyle.js +2 -1
- package/src/style/ShapeColorSizeStyle.js +29 -0
- package/src/style/SideCategoryStyle.js +1 -0
- package/src/style/SideStyle.js +50 -27
- package/src/style/SquareColorCategoryWebGLStyle.js +4 -3
- package/src/style/SquareColorWebGLStyle.js +1 -0
- package/src/style/StrokeStyle.js +48 -16
- package/src/style/TanakaStyle.js +11 -5
- package/src/style/TextStyle.js +1 -1
- package/src/style/TimeSeriesStyle.js +1 -0
- package/src/utils/chernoff.js +14 -0
- package/src/utils/scale.js +22 -11
- package/src/utils/stretching.js +4 -0
- package/src/utils/trivariate.js +203 -0
- 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
|
|
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
|
|
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 =
|
|
170
|
-
hG2 =
|
|
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(
|
|
174
|
-
total2 = computeTotal(
|
|
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 =
|
|
183
|
-
let v2 =
|
|
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 (
|
|
146
|
+
if (side.or == "h") {
|
|
195
147
|
//horizontal side - vertical section
|
|
196
148
|
//bottom left
|
|
197
|
-
geoCanvas.ctx.moveTo(
|
|
149
|
+
geoCanvas.ctx.moveTo(x + h1 * cos + dx, y - r2 + h1 * sin + dy)
|
|
198
150
|
//top left
|
|
199
|
-
geoCanvas.ctx.lineTo(
|
|
151
|
+
geoCanvas.ctx.lineTo(x + h2 * cos + dx, y + r2 + h2 * sin + dy)
|
|
200
152
|
//top right
|
|
201
|
-
geoCanvas.ctx.lineTo(
|
|
153
|
+
geoCanvas.ctx.lineTo(x + h2n * cos + dx, y + r2 + h2n * sin + dy)
|
|
202
154
|
//bottom right
|
|
203
|
-
geoCanvas.ctx.lineTo(
|
|
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(
|
|
159
|
+
geoCanvas.ctx.moveTo(x - r2 + h1 * cos + dx, y + h1 * sin + dy)
|
|
208
160
|
//bottom right
|
|
209
|
-
geoCanvas.ctx.lineTo(
|
|
161
|
+
geoCanvas.ctx.lineTo(x + r2 + h2 * cos + dx, y + h2 * sin + dy)
|
|
210
162
|
//top right
|
|
211
|
-
geoCanvas.ctx.lineTo(
|
|
163
|
+
geoCanvas.ctx.lineTo(x + r2 + h2n * cos + dx, y + h2n * sin + dy)
|
|
212
164
|
//top left
|
|
213
|
-
geoCanvas.ctx.lineTo(
|
|
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 (
|
|
227
|
-
drawCornerLine(
|
|
228
|
-
drawCornerLine(
|
|
229
|
-
//if (this.angle > 0 &&
|
|
230
|
-
//else drawCornerLine(
|
|
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
|
}
|
package/src/style/LegoStyle.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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: (
|
|
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(
|
|
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
|
|
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({
|
|
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: (
|
|
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,
|
|
88
|
+
draw(cells, geoCanvas, r) {
|
|
91
89
|
//filter
|
|
92
90
|
if (this.filter) cells = cells.filter(this.filter)
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
geoCanvas.ctx.lineWidth = 0.6 * geoCanvas.view.z
|
|
95
93
|
|
|
96
94
|
//dark part
|
|
97
|
-
|
|
95
|
+
geoCanvas.ctx.strokeStyle = this.colDark
|
|
98
96
|
for (let c of cells) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
103
|
+
geoCanvas.ctx.strokeStyle = this.colBright
|
|
106
104
|
for (let c of cells) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
}
|
package/src/style/MosaicStyle.js
CHANGED
package/src/style/PillarStyle.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
}
|
package/src/style/SideStyle.js
CHANGED
|
@@ -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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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.
|
|
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 =
|
|
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
|
-
*
|
|
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 =
|
|
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 {
|