gridviz 3.0.18 → 3.0.20
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 +128 -127
- package/dist/gridviz.js +7862 -7819
- package/dist/gridviz.min.js +1 -1
- package/package.json +74 -74
- package/src/button/ZoomButtons.js +101 -101
- package/src/core/Dataset.js +154 -154
- package/src/core/Drawable.js +60 -60
- package/src/core/GeoCanvas.js +430 -419
- package/src/core/Layer.js +23 -23
- package/src/core/Legend.js +108 -108
- package/src/core/Map.js +516 -503
- package/src/core/MultiResolutionDataset.js +93 -93
- package/src/core/Style.js +98 -98
- package/src/core/Tooltip.js +1 -0
- package/src/dataset/CSVGrid.js +112 -112
- package/src/dataset/GeoTIFF.js +122 -122
- package/src/dataset/JSGrid.js +55 -55
- package/src/dataset/TiledGrid.js +302 -289
- package/src/dataset/worker.js +18 -18
- package/src/index.js +77 -77
- package/src/layer/BackgroundLayer.js +162 -162
- package/src/layer/BackgroundLayerImage.js +81 -81
- package/src/layer/BackgroundLayerWMS.js +104 -104
- package/src/layer/GeoJSONLayer.js +214 -214
- package/src/layer/GridLayer.js +148 -148
- package/src/layer/LabelLayer.js +194 -194
- package/src/legend/ColorCategoryLegend.js +109 -109
- package/src/legend/ColorDiscreteLegend.js +100 -100
- package/src/legend/ColorLegend.js +115 -115
- package/src/legend/OrientationLegend.js +89 -89
- package/src/legend/SizeLegend.js +224 -224
- package/src/legend/TernaryLegend.js +302 -302
- package/src/style/CompositionStyle.js +291 -291
- package/src/style/DotDensityStyle.js +133 -133
- package/src/style/ImageStyle.js +100 -100
- package/src/style/IsoFenceStyle.js +217 -217
- package/src/style/JoyPlotStyle.js +127 -127
- package/src/style/LegoStyle.js +110 -110
- package/src/style/MosaicStyle.js +99 -99
- package/src/style/NinjaStarStyle.js +102 -102
- package/src/style/PillarStyle.js +207 -207
- package/src/style/SegmentStyle.js +105 -105
- package/src/style/ShapeColorSizeStyle.js +147 -147
- package/src/style/SideCategoryStyle.js +112 -112
- package/src/style/SideStyle.js +212 -212
- package/src/style/SquareColorCategoryWebGLStyle.js +107 -107
- package/src/style/SquareColorWebGLStyle.js +126 -126
- package/src/style/StrokeStyle.js +135 -135
- package/src/style/TanakaStyle.js +69 -69
- package/src/style/TextStyle.js +110 -110
- package/src/style/TimeSeriesStyle.js +222 -222
- package/src/utils/scale.js +218 -218
- package/src/utils/stretching.js +120 -120
- package/src/utils/ternary.js +208 -203
- package/src/utils/utils.js +58 -58
- package/src/utils/webGLUtils.js +72 -72
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Style } from '../core/Style.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A very generic style that shows grid cells with specific color, size and shape.
|
|
8
|
-
* It can be used to show variables as cell colors, cell size, cell shape, or any combination of the three visual variables.
|
|
9
|
-
*
|
|
10
|
-
* @module style
|
|
11
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
12
|
-
*/
|
|
13
|
-
export class ShapeColorSizeStyle extends Style {
|
|
14
|
-
/** @param {object} opts */
|
|
15
|
-
constructor(opts) {
|
|
16
|
-
super(opts)
|
|
17
|
-
opts = opts || {}
|
|
18
|
-
/** @type {(function(import('../core/Dataset.js').Cell, number, number, object):string) | string} */
|
|
19
|
-
this.color = opts.color || '#EA6BAC'
|
|
20
|
-
|
|
21
|
-
/** @type {(function(import('../core/Dataset.js').Cell, number, number, object):number) | number} */
|
|
22
|
-
this.size = opts.size || ((cell, resolution) => resolution)
|
|
23
|
-
|
|
24
|
-
/** @type {(function(import("../core/Dataset.js").Cell,number, number,object):import("../core/Style.js").Shape) | string} */
|
|
25
|
-
this.shape = opts.shape || 'square'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Draw cells as squares, with various colors and sizes.
|
|
30
|
-
*
|
|
31
|
-
* @param {Array.<import("../core/Dataset.js").Cell>} cells - The grid cells to draw.
|
|
32
|
-
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas - The canvas to draw on.
|
|
33
|
-
* @param {number} resolution - Resolution of the grid.
|
|
34
|
-
* @override
|
|
35
|
-
*/
|
|
36
|
-
draw(cells, geoCanvas, resolution) {
|
|
37
|
-
//filter
|
|
38
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
39
|
-
|
|
40
|
-
//zoom
|
|
41
|
-
const z = geoCanvas.view.z
|
|
42
|
-
|
|
43
|
-
//get view scale
|
|
44
|
-
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
45
|
-
|
|
46
|
-
const r2 = resolution * 0.5
|
|
47
|
-
|
|
48
|
-
// Precompute if color, size, and shape are functions, for efficiency
|
|
49
|
-
const isColorFunction = typeof this.color === 'function'
|
|
50
|
-
const isSizeFunction = typeof this.size === 'function'
|
|
51
|
-
const isShapeFunction = typeof this.shape === 'function'
|
|
52
|
-
|
|
53
|
-
const defaultColor = this.color || 'black'
|
|
54
|
-
const defaultSize = this.size || resolution
|
|
55
|
-
const defaultShape = this.shape || 'square'
|
|
56
|
-
|
|
57
|
-
// Optimized
|
|
58
|
-
const colorFunction = isColorFunction ? this.color : null
|
|
59
|
-
const sizeFunction = isSizeFunction ? this.size : null
|
|
60
|
-
const shapeFunction = isShapeFunction ? this.shape : null
|
|
61
|
-
|
|
62
|
-
for (let c of cells) {
|
|
63
|
-
// Determine color
|
|
64
|
-
//@ts-ignore
|
|
65
|
-
const col = colorFunction ? colorFunction(c, resolution, z, viewScale) : defaultColor
|
|
66
|
-
if (!col || col === 'none') continue
|
|
67
|
-
|
|
68
|
-
// Determine size
|
|
69
|
-
//@ts-ignore
|
|
70
|
-
const size = sizeFunction ? sizeFunction(c, resolution, z, viewScale) : defaultSize
|
|
71
|
-
if (!size) continue
|
|
72
|
-
|
|
73
|
-
// Determine shape
|
|
74
|
-
//@ts-ignore
|
|
75
|
-
const shape = shapeFunction ? shapeFunction(c, resolution, z, viewScale) : defaultShape
|
|
76
|
-
if (shape === 'none') continue
|
|
77
|
-
|
|
78
|
-
//get offset
|
|
79
|
-
const offset = this.offset(c, resolution, z)
|
|
80
|
-
|
|
81
|
-
//get context
|
|
82
|
-
const ctx = geoCanvas.offscreenCtx
|
|
83
|
-
ctx.fillStyle = col
|
|
84
|
-
if (shape === 'square') {
|
|
85
|
-
//draw square
|
|
86
|
-
const d = resolution * (1 - size / resolution) * 0.5
|
|
87
|
-
ctx.fillRect(c.x + d + offset.dx, c.y + d + offset.dy, size, size)
|
|
88
|
-
} else if (shape === 'circle') {
|
|
89
|
-
//draw circle
|
|
90
|
-
ctx.beginPath()
|
|
91
|
-
ctx.arc(c.x + r2 + offset.dx, c.y + r2 + offset.dy, size * 0.5, 0, 2 * Math.PI, false)
|
|
92
|
-
ctx.fill()
|
|
93
|
-
} else if (shape === 'donut') {
|
|
94
|
-
//draw donut
|
|
95
|
-
const xc = c.x + r2 + offset.dx,
|
|
96
|
-
yc = c.y + r2 + offset.dy
|
|
97
|
-
ctx.beginPath()
|
|
98
|
-
ctx.moveTo(xc, yc)
|
|
99
|
-
ctx.arc(xc, yc, r2, 0, 2 * Math.PI)
|
|
100
|
-
ctx.arc(xc, yc, (1 - size / resolution) * r2, 0, 2 * Math.PI, true)
|
|
101
|
-
ctx.closePath()
|
|
102
|
-
ctx.fill()
|
|
103
|
-
} else if (shape === 'diamond') {
|
|
104
|
-
const s2 = size * 0.5
|
|
105
|
-
ctx.beginPath()
|
|
106
|
-
ctx.moveTo(c.x + r2 - s2, c.y + r2)
|
|
107
|
-
ctx.lineTo(c.x + r2, c.y + r2 + s2)
|
|
108
|
-
ctx.lineTo(c.x + r2 + s2, c.y + r2)
|
|
109
|
-
ctx.lineTo(c.x + r2, c.y + r2 - s2)
|
|
110
|
-
ctx.fill()
|
|
111
|
-
} else if (shape === 'triangle_up') {
|
|
112
|
-
const dr2 = (size - resolution) / 2
|
|
113
|
-
ctx.beginPath()
|
|
114
|
-
ctx.moveTo(c.x - dr2, c.y - dr2)
|
|
115
|
-
ctx.lineTo(c.x + r2, c.y + resolution + dr2)
|
|
116
|
-
ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
|
|
117
|
-
ctx.fill()
|
|
118
|
-
} else if (shape === 'triangle_down') {
|
|
119
|
-
const dr2 = (size - resolution) / 2
|
|
120
|
-
ctx.beginPath()
|
|
121
|
-
ctx.moveTo(c.x - dr2, c.y + resolution + dr2)
|
|
122
|
-
ctx.lineTo(c.x + r2, c.y - dr2)
|
|
123
|
-
ctx.lineTo(c.x + resolution + dr2, c.y + resolution + dr2)
|
|
124
|
-
ctx.fill()
|
|
125
|
-
} else if (shape === 'triangle_left') {
|
|
126
|
-
const dr2 = (size - resolution) / 2
|
|
127
|
-
ctx.beginPath()
|
|
128
|
-
ctx.moveTo(c.x + resolution + dr2, c.y + resolution + dr2)
|
|
129
|
-
ctx.lineTo(c.x - dr2, c.y + r2)
|
|
130
|
-
ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
|
|
131
|
-
ctx.fill()
|
|
132
|
-
} else if (shape === 'triangle_right') {
|
|
133
|
-
const dr2 = (size - resolution) / 2
|
|
134
|
-
ctx.beginPath()
|
|
135
|
-
ctx.moveTo(c.x - dr2, c.y - dr2)
|
|
136
|
-
ctx.lineTo(c.x + resolution + dr2, c.y + r2)
|
|
137
|
-
ctx.lineTo(c.x - dr2, c.y + resolution + dr2)
|
|
138
|
-
ctx.fill()
|
|
139
|
-
} else {
|
|
140
|
-
throw new Error('Unexpected shape:' + shape)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
//update legends
|
|
145
|
-
this.updateLegends({ viewScale: viewScale, resolution: resolution, z: z, cells: cells })
|
|
146
|
-
}
|
|
147
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { Style } from '../core/Style.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A very generic style that shows grid cells with specific color, size and shape.
|
|
8
|
+
* It can be used to show variables as cell colors, cell size, cell shape, or any combination of the three visual variables.
|
|
9
|
+
*
|
|
10
|
+
* @module style
|
|
11
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
12
|
+
*/
|
|
13
|
+
export class ShapeColorSizeStyle extends Style {
|
|
14
|
+
/** @param {object} opts */
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
super(opts)
|
|
17
|
+
opts = opts || {}
|
|
18
|
+
/** @type {(function(import('../core/Dataset.js').Cell, number, number, object):string) | string} */
|
|
19
|
+
this.color = opts.color || '#EA6BAC'
|
|
20
|
+
|
|
21
|
+
/** @type {(function(import('../core/Dataset.js').Cell, number, number, object):number) | number} */
|
|
22
|
+
this.size = opts.size || ((cell, resolution) => resolution)
|
|
23
|
+
|
|
24
|
+
/** @type {(function(import("../core/Dataset.js").Cell,number, number,object):import("../core/Style.js").Shape) | string} */
|
|
25
|
+
this.shape = opts.shape || 'square'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Draw cells as squares, with various colors and sizes.
|
|
30
|
+
*
|
|
31
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells - The grid cells to draw.
|
|
32
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas - The canvas to draw on.
|
|
33
|
+
* @param {number} resolution - Resolution of the grid.
|
|
34
|
+
* @override
|
|
35
|
+
*/
|
|
36
|
+
draw(cells, geoCanvas, resolution) {
|
|
37
|
+
//filter
|
|
38
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
39
|
+
|
|
40
|
+
//zoom
|
|
41
|
+
const z = geoCanvas.view.z
|
|
42
|
+
|
|
43
|
+
//get view scale
|
|
44
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
45
|
+
|
|
46
|
+
const r2 = resolution * 0.5
|
|
47
|
+
|
|
48
|
+
// Precompute if color, size, and shape are functions, for efficiency
|
|
49
|
+
const isColorFunction = typeof this.color === 'function'
|
|
50
|
+
const isSizeFunction = typeof this.size === 'function'
|
|
51
|
+
const isShapeFunction = typeof this.shape === 'function'
|
|
52
|
+
|
|
53
|
+
const defaultColor = this.color || 'black'
|
|
54
|
+
const defaultSize = this.size || resolution
|
|
55
|
+
const defaultShape = this.shape || 'square'
|
|
56
|
+
|
|
57
|
+
// Optimized
|
|
58
|
+
const colorFunction = isColorFunction ? this.color : null
|
|
59
|
+
const sizeFunction = isSizeFunction ? this.size : null
|
|
60
|
+
const shapeFunction = isShapeFunction ? this.shape : null
|
|
61
|
+
|
|
62
|
+
for (let c of cells) {
|
|
63
|
+
// Determine color
|
|
64
|
+
//@ts-ignore
|
|
65
|
+
const col = colorFunction ? colorFunction(c, resolution, z, viewScale) : defaultColor
|
|
66
|
+
if (!col || col === 'none') continue
|
|
67
|
+
|
|
68
|
+
// Determine size
|
|
69
|
+
//@ts-ignore
|
|
70
|
+
const size = sizeFunction ? sizeFunction(c, resolution, z, viewScale) : defaultSize
|
|
71
|
+
if (!size) continue
|
|
72
|
+
|
|
73
|
+
// Determine shape
|
|
74
|
+
//@ts-ignore
|
|
75
|
+
const shape = shapeFunction ? shapeFunction(c, resolution, z, viewScale) : defaultShape
|
|
76
|
+
if (shape === 'none') continue
|
|
77
|
+
|
|
78
|
+
//get offset
|
|
79
|
+
const offset = this.offset(c, resolution, z)
|
|
80
|
+
|
|
81
|
+
//get context
|
|
82
|
+
const ctx = geoCanvas.offscreenCtx
|
|
83
|
+
ctx.fillStyle = col
|
|
84
|
+
if (shape === 'square') {
|
|
85
|
+
//draw square
|
|
86
|
+
const d = resolution * (1 - size / resolution) * 0.5
|
|
87
|
+
ctx.fillRect(c.x + d + offset.dx, c.y + d + offset.dy, size, size)
|
|
88
|
+
} else if (shape === 'circle') {
|
|
89
|
+
//draw circle
|
|
90
|
+
ctx.beginPath()
|
|
91
|
+
ctx.arc(c.x + r2 + offset.dx, c.y + r2 + offset.dy, size * 0.5, 0, 2 * Math.PI, false)
|
|
92
|
+
ctx.fill()
|
|
93
|
+
} else if (shape === 'donut') {
|
|
94
|
+
//draw donut
|
|
95
|
+
const xc = c.x + r2 + offset.dx,
|
|
96
|
+
yc = c.y + r2 + offset.dy
|
|
97
|
+
ctx.beginPath()
|
|
98
|
+
ctx.moveTo(xc, yc)
|
|
99
|
+
ctx.arc(xc, yc, r2, 0, 2 * Math.PI)
|
|
100
|
+
ctx.arc(xc, yc, (1 - size / resolution) * r2, 0, 2 * Math.PI, true)
|
|
101
|
+
ctx.closePath()
|
|
102
|
+
ctx.fill()
|
|
103
|
+
} else if (shape === 'diamond') {
|
|
104
|
+
const s2 = size * 0.5
|
|
105
|
+
ctx.beginPath()
|
|
106
|
+
ctx.moveTo(c.x + r2 - s2, c.y + r2)
|
|
107
|
+
ctx.lineTo(c.x + r2, c.y + r2 + s2)
|
|
108
|
+
ctx.lineTo(c.x + r2 + s2, c.y + r2)
|
|
109
|
+
ctx.lineTo(c.x + r2, c.y + r2 - s2)
|
|
110
|
+
ctx.fill()
|
|
111
|
+
} else if (shape === 'triangle_up') {
|
|
112
|
+
const dr2 = (size - resolution) / 2
|
|
113
|
+
ctx.beginPath()
|
|
114
|
+
ctx.moveTo(c.x - dr2, c.y - dr2)
|
|
115
|
+
ctx.lineTo(c.x + r2, c.y + resolution + dr2)
|
|
116
|
+
ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
|
|
117
|
+
ctx.fill()
|
|
118
|
+
} else if (shape === 'triangle_down') {
|
|
119
|
+
const dr2 = (size - resolution) / 2
|
|
120
|
+
ctx.beginPath()
|
|
121
|
+
ctx.moveTo(c.x - dr2, c.y + resolution + dr2)
|
|
122
|
+
ctx.lineTo(c.x + r2, c.y - dr2)
|
|
123
|
+
ctx.lineTo(c.x + resolution + dr2, c.y + resolution + dr2)
|
|
124
|
+
ctx.fill()
|
|
125
|
+
} else if (shape === 'triangle_left') {
|
|
126
|
+
const dr2 = (size - resolution) / 2
|
|
127
|
+
ctx.beginPath()
|
|
128
|
+
ctx.moveTo(c.x + resolution + dr2, c.y + resolution + dr2)
|
|
129
|
+
ctx.lineTo(c.x - dr2, c.y + r2)
|
|
130
|
+
ctx.lineTo(c.x + resolution + dr2, c.y - dr2)
|
|
131
|
+
ctx.fill()
|
|
132
|
+
} else if (shape === 'triangle_right') {
|
|
133
|
+
const dr2 = (size - resolution) / 2
|
|
134
|
+
ctx.beginPath()
|
|
135
|
+
ctx.moveTo(c.x - dr2, c.y - dr2)
|
|
136
|
+
ctx.lineTo(c.x + resolution + dr2, c.y + r2)
|
|
137
|
+
ctx.lineTo(c.x - dr2, c.y + resolution + dr2)
|
|
138
|
+
ctx.fill()
|
|
139
|
+
} else {
|
|
140
|
+
throw new Error('Unexpected shape:' + shape)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//update legends
|
|
145
|
+
this.updateLegends({ viewScale: viewScale, resolution: resolution, z: z, cells: cells })
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -1,112 +1,112 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { SideStyle } from './SideStyle.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A style to show the sides of grid cells based on their different categories.
|
|
8
|
-
*
|
|
9
|
-
* @module style
|
|
10
|
-
* @author Julien Gaffuri
|
|
11
|
-
*/
|
|
12
|
-
export class SideCategoryStyle extends SideStyle {
|
|
13
|
-
/** @param {object} opts */
|
|
14
|
-
constructor(opts) {
|
|
15
|
-
super(opts)
|
|
16
|
-
opts = opts || {}
|
|
17
|
-
|
|
18
|
-
/** A function returning the category code of a cell.
|
|
19
|
-
* @type {function(import('../core/Dataset.js').Cell, number, number):string} */
|
|
20
|
-
this.code = opts.code
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The dictionary (string -> color) which give the color of each category.
|
|
24
|
-
* @type {object} */
|
|
25
|
-
this.color = opts.color
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
30
|
-
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
31
|
-
* @param {number} resolution
|
|
32
|
-
*/
|
|
33
|
-
draw(cells, geoCanvas, resolution) {
|
|
34
|
-
//filter
|
|
35
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
const z = geoCanvas.view.z
|
|
39
|
-
const ctx = geoCanvas.offscreenCtx
|
|
40
|
-
|
|
41
|
-
//build sides
|
|
42
|
-
|
|
43
|
-
/** @type {Array.<import('./SideStyle.js').Side>} */
|
|
44
|
-
const sides = SideStyle.buildSides(cells, resolution)
|
|
45
|
-
if (sides.length == 0) return
|
|
46
|
-
|
|
47
|
-
//get side view scale
|
|
48
|
-
const viewScale = this.viewScale ? this.viewScale(sides, resolution, z) : undefined
|
|
49
|
-
|
|
50
|
-
//draw sides
|
|
51
|
-
|
|
52
|
-
ctx.lineCap = 'butt'
|
|
53
|
-
const r2 = resolution * 0.5
|
|
54
|
-
for (let side of sides) {
|
|
55
|
-
//get category codes for both cells
|
|
56
|
-
const code1 = side.c1 ? this.code(side.c1, resolution, z) : undefined
|
|
57
|
-
const code2 = side.c2 ? this.code(side.c2, resolution, z) : undefined
|
|
58
|
-
if (code1 == code2) continue
|
|
59
|
-
|
|
60
|
-
//width
|
|
61
|
-
/** @type {number|undefined} */
|
|
62
|
-
const wG = this.width ? this.width(side, resolution, z, viewScale) : undefined
|
|
63
|
-
if (!wG || wG <= 0) continue
|
|
64
|
-
const w2 = wG * 0.5
|
|
65
|
-
|
|
66
|
-
//set width
|
|
67
|
-
ctx.lineWidth = wG
|
|
68
|
-
|
|
69
|
-
//draw segment with correct orientation
|
|
70
|
-
if (side.or === 'h') {
|
|
71
|
-
//top line
|
|
72
|
-
if (code2) {
|
|
73
|
-
ctx.beginPath()
|
|
74
|
-
ctx.strokeStyle = this.color[code2]
|
|
75
|
-
ctx.moveTo(side.x - r2, side.y + w2)
|
|
76
|
-
ctx.lineTo(side.x + r2, side.y + w2)
|
|
77
|
-
ctx.stroke()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
//bottom line
|
|
81
|
-
if (code1) {
|
|
82
|
-
ctx.beginPath()
|
|
83
|
-
ctx.strokeStyle = this.color[code1]
|
|
84
|
-
ctx.moveTo(side.x - r2, side.y - w2)
|
|
85
|
-
ctx.lineTo(side.x + r2, side.y - w2)
|
|
86
|
-
ctx.stroke()
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
//right line
|
|
90
|
-
if (code2) {
|
|
91
|
-
ctx.beginPath()
|
|
92
|
-
ctx.strokeStyle = this.color[code2]
|
|
93
|
-
ctx.moveTo(side.x + w2, side.y - r2)
|
|
94
|
-
ctx.lineTo(side.x + w2, side.y + r2)
|
|
95
|
-
ctx.stroke()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
//left line
|
|
99
|
-
if (code1) {
|
|
100
|
-
ctx.beginPath()
|
|
101
|
-
ctx.strokeStyle = this.color[code1]
|
|
102
|
-
ctx.moveTo(side.x - w2, side.y - r2)
|
|
103
|
-
ctx.lineTo(side.x - w2, side.y + r2)
|
|
104
|
-
ctx.stroke()
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
//update legends
|
|
110
|
-
this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
|
|
111
|
-
}
|
|
112
|
-
}
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { SideStyle } from './SideStyle.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A style to show the sides of grid cells based on their different categories.
|
|
8
|
+
*
|
|
9
|
+
* @module style
|
|
10
|
+
* @author Julien Gaffuri
|
|
11
|
+
*/
|
|
12
|
+
export class SideCategoryStyle extends SideStyle {
|
|
13
|
+
/** @param {object} opts */
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super(opts)
|
|
16
|
+
opts = opts || {}
|
|
17
|
+
|
|
18
|
+
/** A function returning the category code of a cell.
|
|
19
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number):string} */
|
|
20
|
+
this.code = opts.code
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The dictionary (string -> color) which give the color of each category.
|
|
24
|
+
* @type {object} */
|
|
25
|
+
this.color = opts.color
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
30
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
31
|
+
* @param {number} resolution
|
|
32
|
+
*/
|
|
33
|
+
draw(cells, geoCanvas, resolution) {
|
|
34
|
+
//filter
|
|
35
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
36
|
+
|
|
37
|
+
//
|
|
38
|
+
const z = geoCanvas.view.z
|
|
39
|
+
const ctx = geoCanvas.offscreenCtx
|
|
40
|
+
|
|
41
|
+
//build sides
|
|
42
|
+
|
|
43
|
+
/** @type {Array.<import('./SideStyle.js').Side>} */
|
|
44
|
+
const sides = SideStyle.buildSides(cells, resolution)
|
|
45
|
+
if (sides.length == 0) return
|
|
46
|
+
|
|
47
|
+
//get side view scale
|
|
48
|
+
const viewScale = this.viewScale ? this.viewScale(sides, resolution, z) : undefined
|
|
49
|
+
|
|
50
|
+
//draw sides
|
|
51
|
+
|
|
52
|
+
ctx.lineCap = 'butt'
|
|
53
|
+
const r2 = resolution * 0.5
|
|
54
|
+
for (let side of sides) {
|
|
55
|
+
//get category codes for both cells
|
|
56
|
+
const code1 = side.c1 ? this.code(side.c1, resolution, z) : undefined
|
|
57
|
+
const code2 = side.c2 ? this.code(side.c2, resolution, z) : undefined
|
|
58
|
+
if (code1 == code2) continue
|
|
59
|
+
|
|
60
|
+
//width
|
|
61
|
+
/** @type {number|undefined} */
|
|
62
|
+
const wG = this.width ? this.width(side, resolution, z, viewScale) : undefined
|
|
63
|
+
if (!wG || wG <= 0) continue
|
|
64
|
+
const w2 = wG * 0.5
|
|
65
|
+
|
|
66
|
+
//set width
|
|
67
|
+
ctx.lineWidth = wG
|
|
68
|
+
|
|
69
|
+
//draw segment with correct orientation
|
|
70
|
+
if (side.or === 'h') {
|
|
71
|
+
//top line
|
|
72
|
+
if (code2) {
|
|
73
|
+
ctx.beginPath()
|
|
74
|
+
ctx.strokeStyle = this.color[code2]
|
|
75
|
+
ctx.moveTo(side.x - r2, side.y + w2)
|
|
76
|
+
ctx.lineTo(side.x + r2, side.y + w2)
|
|
77
|
+
ctx.stroke()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//bottom line
|
|
81
|
+
if (code1) {
|
|
82
|
+
ctx.beginPath()
|
|
83
|
+
ctx.strokeStyle = this.color[code1]
|
|
84
|
+
ctx.moveTo(side.x - r2, side.y - w2)
|
|
85
|
+
ctx.lineTo(side.x + r2, side.y - w2)
|
|
86
|
+
ctx.stroke()
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
//right line
|
|
90
|
+
if (code2) {
|
|
91
|
+
ctx.beginPath()
|
|
92
|
+
ctx.strokeStyle = this.color[code2]
|
|
93
|
+
ctx.moveTo(side.x + w2, side.y - r2)
|
|
94
|
+
ctx.lineTo(side.x + w2, side.y + r2)
|
|
95
|
+
ctx.stroke()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//left line
|
|
99
|
+
if (code1) {
|
|
100
|
+
ctx.beginPath()
|
|
101
|
+
ctx.strokeStyle = this.color[code1]
|
|
102
|
+
ctx.moveTo(side.x - w2, side.y - r2)
|
|
103
|
+
ctx.lineTo(side.x - w2, side.y + r2)
|
|
104
|
+
ctx.stroke()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//update legends
|
|
110
|
+
this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
|
|
111
|
+
}
|
|
112
|
+
}
|