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.
- package/README.md +2 -3
- package/dist/gridviz.js +4971 -5654
- package/dist/gridviz.min.js +1 -1
- package/package.json +3 -2
- package/src/button/Button.js +14 -15
- package/src/button/FullscreenButton.js +14 -14
- package/src/button/ZoomButtons.js +2 -2
- package/src/{DatasetComponent.js → core/Dataset.js} +33 -12
- package/src/core/Drawable.js +60 -0
- package/src/{GeoCanvas.js → core/GeoCanvas.js} +65 -155
- package/src/core/Layer.js +24 -0
- package/src/{Legend.js → core/Legend.js} +24 -1
- package/src/core/Map.js +460 -0
- package/src/core/MultiResolutionDataset.js +96 -0
- package/src/core/Style.js +84 -0
- package/src/dataset/COGeo.js +5 -5
- package/src/dataset/CSVGrid.js +43 -41
- package/src/dataset/GeoTIFF.js +9 -14
- package/src/dataset/{LGrid.js → JSGrid.js} +9 -10
- package/src/dataset/TiledGrid.js +68 -45
- package/src/index.js +22 -29
- package/src/{BackgroundLayer.js → layer/BackgroundLayer.js} +27 -52
- package/src/{BackgroundLayerWMS.js → layer/BackgroundLayerWMS.js} +21 -45
- package/src/{LineLayer.js → layer/GeoJSONLayer.js} +22 -23
- package/src/layer/GridLayer.js +140 -0
- package/src/{LabelLayer.js → layer/LabelLayer.js} +25 -23
- package/src/legend/ColorCategoryLegend.js +9 -24
- package/src/legend/ColorDiscreteLegend.js +20 -24
- package/src/legend/ColorLegend.js +21 -33
- package/src/legend/OrientationLegend.js +90 -0
- package/src/legend/SizeLegend.js +153 -72
- package/src/style/CompositionStyle.js +71 -84
- package/src/style/ContourStyle.js +2 -36
- package/src/style/DotDensityStyle.js +50 -73
- package/src/style/IsoFenceStyle.js +59 -70
- package/src/style/JoyPlotStyle.js +41 -48
- package/src/style/LegoStyle.js +4 -4
- package/src/style/MosaicStyle.js +30 -39
- package/src/style/NinjaStarStyle.js +45 -68
- package/src/style/PillarStyle.js +70 -93
- package/src/style/SegmentStyle.js +37 -75
- package/src/style/ShapeColorSizeStyle.js +49 -98
- package/src/style/SideCategoryStyle.js +112 -0
- package/src/style/SideStyle.js +99 -133
- package/src/style/{SquareColorCatWGLStyle.js → SquareColorCategoryWebGLStyle.js} +28 -41
- package/src/style/{SquareColorWGLStyle.js → SquareColorWebGLStyle.js} +28 -49
- package/src/style/StrokeStyle.js +43 -70
- package/src/style/TanakaStyle.js +34 -132
- package/src/style/TextStyle.js +43 -64
- package/src/style/TimeSeriesStyle.js +44 -75
- package/src/utils/WebGLSquareColoringAdvanced.js +4 -4
- package/src/utils/scale.js +202 -0
- package/src/utils/stretching.js +86 -129
- package/src/utils/{Utils.js → utils.js} +15 -0
- package/src/utils/webGLUtils.js +4 -5
- package/src/utils/zoomUtils.js +30 -30
- package/src/App.js +0 -760
- package/src/Dataset.js +0 -76
- package/src/Layer.js +0 -103
- package/src/Style.js +0 -131
- package/src/dataset/GridTile.js +0 -41
- package/src/legend/SegmentOrientationLegend.js +0 -87
- package/src/legend/SegmentWidthLegend.js +0 -101
- package/src/style/CompositionStyle_.js +0 -293
- package/src/style/ShapeColorSizeStyle_.js +0 -108
- package/src/style/SideCatStyle.js +0 -172
- /package/src/{Tooltip.js → core/Tooltip.js} +0 -0
package/src/Dataset.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A grid cell.
|
|
6
|
-
* @typedef {{x: number, y: number}} Cell */
|
|
7
|
-
/**
|
|
8
|
-
* An envelope.
|
|
9
|
-
* @typedef { {xMin: number, xMax: number, yMin: number, yMax: number} } Envelope */
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* A multi resolution dataset of grid cells.
|
|
13
|
-
* It consists of different {@link DatasetComponent}s for each resolution.
|
|
14
|
-
*
|
|
15
|
-
* @abstract
|
|
16
|
-
*
|
|
17
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
18
|
-
*/
|
|
19
|
-
export class Dataset {
|
|
20
|
-
/**
|
|
21
|
-
* @param {Array.<import("./DatasetComponent").DatasetComponent>} datasetComponents The dataset components
|
|
22
|
-
* @param {Array.<number>} resolutions The resolutions of the dataset components, in CRS geographical unit
|
|
23
|
-
* @param { {preprocess?:function(Cell):boolean} } opts Options. preprocess: A function to apply on each dataset cell to prepare its values. Can be used also to select cells to keep.
|
|
24
|
-
*/
|
|
25
|
-
constructor(datasetComponents, resolutions, opts = {}) {
|
|
26
|
-
opts = opts || {}
|
|
27
|
-
|
|
28
|
-
/** The dataset components.
|
|
29
|
-
* @type {Array.<import("./DatasetComponent").DatasetComponent>} */
|
|
30
|
-
this.datasetComponents = datasetComponents
|
|
31
|
-
|
|
32
|
-
/** The resolutions of the dataset components, in CRS geographical unit.
|
|
33
|
-
* @type {Array.<number>} */
|
|
34
|
-
this.resolutions = resolutions
|
|
35
|
-
|
|
36
|
-
//there must be as many dataset components as resolutions
|
|
37
|
-
if (this.datasetComponents.length > 1 && this.datasetComponents.length != this.resolutions.length)
|
|
38
|
-
throw new Error(
|
|
39
|
-
'Uncompatible number of datasets and resolutions: ' +
|
|
40
|
-
this.datasetComponents.length +
|
|
41
|
-
' ' +
|
|
42
|
-
this.resolutions.length
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
//set dataset preprocesses if specified
|
|
46
|
-
if (opts.preprocess) this.setPrepocesses(opts.preprocess)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Set a preprocess function for all dataset components.
|
|
51
|
-
* This is a function applied on each cell after it has been loaded.
|
|
52
|
-
*
|
|
53
|
-
* @param {function(Cell):boolean} preprocess
|
|
54
|
-
* @returns {this}
|
|
55
|
-
*/
|
|
56
|
-
setPrepocesses(preprocess) {
|
|
57
|
-
for (let ds of this.datasetComponents) ds.preprocess = preprocess
|
|
58
|
-
return this
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* A function to ease the creation of datasets from their components.
|
|
63
|
-
*
|
|
64
|
-
* @param {Array.<number>} resolutions The resolutions of the dataset components, in CRS geographical unit
|
|
65
|
-
* @param {function(number):import("./DatasetComponent").DatasetComponent} resToDatasetComponent Function returning a dataset component from a resolution
|
|
66
|
-
* @param { {preprocess?:function(Cell):boolean} } opts Options. preprocess: A function to apply on each dataset cell to prepare its values
|
|
67
|
-
* @returns {Dataset}
|
|
68
|
-
*/
|
|
69
|
-
static make(resolutions, resToDatasetComponent, opts) {
|
|
70
|
-
//make dataset components
|
|
71
|
-
const dsc = []
|
|
72
|
-
for (const res of resolutions) dsc.push(resToDatasetComponent(res))
|
|
73
|
-
//make dataset
|
|
74
|
-
return new Dataset(dsc, resolutions, opts)
|
|
75
|
-
}
|
|
76
|
-
}
|
package/src/Layer.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A layer, which specifies a dataset to be shown with specified styles.
|
|
6
|
-
*
|
|
7
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
8
|
-
*/
|
|
9
|
-
export class Layer {
|
|
10
|
-
/**
|
|
11
|
-
* @param {import("./Dataset").Dataset} dataset The multi resolution dataset to show.
|
|
12
|
-
* @param {Array.<import("./Style").Style>} styles The styles, ordered in drawing order.
|
|
13
|
-
* @param {{visible?:boolean,alpha?:number,blendOperation?:GlobalCompositeOperation,minZoom?:number,maxZoom?:number,pixNb?:number,cellInfoHTML?:function(import("./Dataset").Cell):string}} opts
|
|
14
|
-
* minZoom: The minimum zoom level when to show the layer. maxZoom: The maximum zoom level when to show the layer
|
|
15
|
-
*/
|
|
16
|
-
constructor(dataset, styles, opts = {}) {
|
|
17
|
-
opts = opts || {}
|
|
18
|
-
|
|
19
|
-
/** @type {import("./Dataset").Dataset} */
|
|
20
|
-
this.dataset = dataset
|
|
21
|
-
/** @type {Array.<import("./Style").Style>} */
|
|
22
|
-
this.styles = styles
|
|
23
|
-
|
|
24
|
-
/** An attribute to specify if a layer should be drawn or not
|
|
25
|
-
* @type {boolean} */
|
|
26
|
-
this.visible = opts.visible === false ? false : true
|
|
27
|
-
|
|
28
|
-
/** A function returning the alpha (transparency/opacity), between 0.0 (fully transparent) and 1.0 (fully opaque).
|
|
29
|
-
* The function parameter is the zoom factor.
|
|
30
|
-
* (see CanvasRenderingContext2D: globalAlpha property)
|
|
31
|
-
* @type {function(number):number|undefined} */
|
|
32
|
-
this.alpha = opts.alpha
|
|
33
|
-
|
|
34
|
-
/** A function returning the blend operation. The function parameter is the zoom factor.
|
|
35
|
-
* (see CanvasRenderingContext2D: globalCompositeOperation property)
|
|
36
|
-
* @type {GlobalCompositeOperation} */
|
|
37
|
-
this.blendOperation = opts.blendOperation || (zf => "source-over")
|
|
38
|
-
|
|
39
|
-
/** The minimum zoom factor: Below this level, the layer is not shown.
|
|
40
|
-
* @type {number} */
|
|
41
|
-
this.minZoom = opts.minZoom || 0
|
|
42
|
-
|
|
43
|
-
/** The maximum zoom factor: Above this level, the layer is not shown.
|
|
44
|
-
* @type {number} */
|
|
45
|
-
this.maxZoom = opts.maxZoom || Infinity
|
|
46
|
-
|
|
47
|
-
//ensure acceptable values for the zoom limits.
|
|
48
|
-
if (this.minZoom >= this.maxZoom)
|
|
49
|
-
throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
|
|
50
|
-
|
|
51
|
-
/** Unit: number of pixels
|
|
52
|
-
* @type {number} */
|
|
53
|
-
this.pixNb = opts.pixNb || 3
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* The function returning cell information as HTML.
|
|
57
|
-
* This is typically used for tooltip information.
|
|
58
|
-
* @type {function(import("./Dataset").Cell, number):string} */
|
|
59
|
-
this.cellInfoHTML = opts.cellInfoHTML || Layer.defaultCellInfoHTML
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Return the relevant dataset component for a specified zoom factor.
|
|
64
|
-
*
|
|
65
|
-
* @param {number} zf
|
|
66
|
-
* @returns {import("./DatasetComponent").DatasetComponent|undefined}
|
|
67
|
-
* */
|
|
68
|
-
getDatasetComponent(zf) {
|
|
69
|
-
if (zf < this.minZoom || zf > this.maxZoom) return
|
|
70
|
-
|
|
71
|
-
//special case whith single component dataset
|
|
72
|
-
if (this.dataset.datasetComponents.length == 1) return this.dataset.datasetComponents[0]
|
|
73
|
-
|
|
74
|
-
const rs = this.dataset.resolutions
|
|
75
|
-
let i = 0
|
|
76
|
-
let z = rs[i] / this.pixNb
|
|
77
|
-
while (z < zf && i < rs.length) {
|
|
78
|
-
i++
|
|
79
|
-
z = rs[i] / this.pixNb
|
|
80
|
-
}
|
|
81
|
-
//if (i == 0) return this.dataset.datasetComponents[0];
|
|
82
|
-
//return this.dataset.datasetComponents[i - 1];
|
|
83
|
-
if (i == rs.length) return this.dataset.datasetComponents[rs.length - 1]
|
|
84
|
-
return this.dataset.datasetComponents[i]
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* The default function returning cell information as HTML.
|
|
89
|
-
* This is typically used for tooltip information.
|
|
90
|
-
*
|
|
91
|
-
* @param {import("./Dataset").Cell} cell
|
|
92
|
-
* @returns {string}
|
|
93
|
-
*/
|
|
94
|
-
static defaultCellInfoHTML(cell) {
|
|
95
|
-
const buf = []
|
|
96
|
-
for (const key of Object.keys(cell)) {
|
|
97
|
-
if (key === 'x') continue
|
|
98
|
-
if (key === 'y') continue
|
|
99
|
-
buf.push('<b>', key, '</b>', ' : ', cell[key], '<br>')
|
|
100
|
-
}
|
|
101
|
-
return buf.join('')
|
|
102
|
-
}
|
|
103
|
-
}
|
package/src/Style.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Statistics of a set of values
|
|
6
|
-
* @typedef {{min:number,max:number}} Stat */
|
|
7
|
-
|
|
8
|
-
/** @typedef {"square"|"circle"|"diamond"|"donut"|"none"} Shape */
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* A style, to show a grid dataset.
|
|
12
|
-
*
|
|
13
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
14
|
-
*/
|
|
15
|
-
export class Style {
|
|
16
|
-
/**
|
|
17
|
-
* @abstract
|
|
18
|
-
* @param {{filter?:function(import('./Dataset').Cell):boolean,offset?:function(import('./Dataset').Cell,number,number):{dx:number,dy:number},visible?:boolean,alpha?:function(number):number,blendOperation?:function(number):GlobalCompositeOperation,minZoom?:number,maxZoom?:number,drawFun?:function}} opts
|
|
19
|
-
*/
|
|
20
|
-
constructor(opts) {
|
|
21
|
-
opts = opts || {}
|
|
22
|
-
|
|
23
|
-
/** A filter function to apply to the cell list, to filter out some cells not to be drawn (such as for example the cells with value=0).
|
|
24
|
-
* @protected
|
|
25
|
-
* @type {function(import('./Dataset').Cell):boolean} */
|
|
26
|
-
this.filter = opts.filter || (() => true)
|
|
27
|
-
|
|
28
|
-
/** An offset. This is to alter the position of all symbols in a given direction. In geographical unit.
|
|
29
|
-
* @protected
|
|
30
|
-
* @type {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} */
|
|
31
|
-
this.offset = opts.offset || ((c, r, zf) => ({ dx: 0, dy: 0 }))
|
|
32
|
-
|
|
33
|
-
/** An attribute to specify if a style should be drawn or not
|
|
34
|
-
* @type {boolean} */
|
|
35
|
-
this.visible = opts.visible === false ? false : true
|
|
36
|
-
|
|
37
|
-
/** A function returning the alpha (transparency/opacity), between 0.0 (fully transparent) and 1.0 (fully opaque).
|
|
38
|
-
* The function parameter is the zoom factor.
|
|
39
|
-
* (see CanvasRenderingContext2D: globalAlpha property)
|
|
40
|
-
* @type {function(number):number|undefined} */
|
|
41
|
-
this.alpha = opts.alpha
|
|
42
|
-
|
|
43
|
-
/** A function returning the blend operation. The function parameter is the zoom factor.
|
|
44
|
-
* (see CanvasRenderingContext2D: globalCompositeOperation property)
|
|
45
|
-
* @type {function(number):GlobalCompositeOperation} */
|
|
46
|
-
this.blendOperation = opts.blendOperation || (zf => "source-over")
|
|
47
|
-
|
|
48
|
-
/** The minimum zoom factor: Below this level, the layer is not shown.
|
|
49
|
-
* @type {number}
|
|
50
|
-
* */
|
|
51
|
-
this.minZoom = opts.minZoom || 0
|
|
52
|
-
|
|
53
|
-
/** The maximum zoom factor: Above this level, the layer is not shown.
|
|
54
|
-
* @type {number}
|
|
55
|
-
* */
|
|
56
|
-
this.maxZoom = opts.maxZoom || Infinity
|
|
57
|
-
|
|
58
|
-
/** A draw function for the style.
|
|
59
|
-
* @type {function} */
|
|
60
|
-
this.drawFun = opts.drawFun
|
|
61
|
-
|
|
62
|
-
//ensure acceptable values for the zoom limits.
|
|
63
|
-
if (this.minZoom >= this.maxZoom)
|
|
64
|
-
throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @public
|
|
68
|
-
* @type {Array.<import("./Legend").Legend>} */
|
|
69
|
-
this.legends = []
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Draw cells.
|
|
74
|
-
*
|
|
75
|
-
* @param {Array.<import('./Dataset').Cell>} cells The cells to draw.
|
|
76
|
-
* @param {number} resolution Their resolution (in geographic unit)
|
|
77
|
-
* @param {import("./GeoCanvas").GeoCanvas} cg The canvas where to draw them.
|
|
78
|
-
* @abstract
|
|
79
|
-
*/
|
|
80
|
-
draw(cells, resolution, cg) {
|
|
81
|
-
if (this.drawFun) this.drawFun(cells, resolution, cg)
|
|
82
|
-
else throw new Error('Method draw not implemented.')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
//getters and setters
|
|
86
|
-
|
|
87
|
-
/** @returns {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} */
|
|
88
|
-
getOffset() {
|
|
89
|
-
return this.offset
|
|
90
|
-
}
|
|
91
|
-
/** @param {function(import('./Dataset').Cell,number,number):{dx:number,dy:number}} val @returns {this} */
|
|
92
|
-
setOffset(val) {
|
|
93
|
-
this.offset = val
|
|
94
|
-
return this
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Hide all legend elements of the style, if any
|
|
98
|
-
* @param {object} opts
|
|
99
|
-
* @returns {this} */
|
|
100
|
-
updateLegends(opts) {
|
|
101
|
-
for (const lg of this.legends) lg.update(opts)
|
|
102
|
-
return this
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Compute some statistics on a value of some cells.
|
|
107
|
-
* This is used to define how to draw specifically the cells within the view.
|
|
108
|
-
* TODO: compute median ?
|
|
109
|
-
*
|
|
110
|
-
* @param {Array.<import('./Dataset').Cell>} cells
|
|
111
|
-
* @param {function(import('./Dataset').Cell):number} valFun
|
|
112
|
-
* @param {boolean} ignoreZeros
|
|
113
|
-
* @returns {Stat | undefined}
|
|
114
|
-
*/
|
|
115
|
-
static getStatistics(cells, valFun, ignoreZeros) {
|
|
116
|
-
if (!cells || cells.length == 0) return undefined
|
|
117
|
-
let min = Infinity
|
|
118
|
-
let max = -Infinity
|
|
119
|
-
//let sum = 0
|
|
120
|
-
//let nb = 0
|
|
121
|
-
for (const cell of cells) {
|
|
122
|
-
const v = +valFun(cell)
|
|
123
|
-
if (ignoreZeros && !v) continue
|
|
124
|
-
if (v < min) min = v
|
|
125
|
-
if (v > max) max = v
|
|
126
|
-
//sum += v
|
|
127
|
-
//nb++
|
|
128
|
-
}
|
|
129
|
-
return { min: min, max: max }
|
|
130
|
-
}
|
|
131
|
-
}
|
package/src/dataset/GridTile.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A grid tile.
|
|
6
|
-
*
|
|
7
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
8
|
-
*/
|
|
9
|
-
export class GridTile {
|
|
10
|
-
/**
|
|
11
|
-
* @param {Array.<import("../Dataset").Cell>} cells The tile cells.
|
|
12
|
-
* @param {number} xT The X position of the tile.
|
|
13
|
-
* @param {number} yT The Y position of the tile.
|
|
14
|
-
* @param {import("./CSVGrid").GridInfo} gridInfo The grid info object.
|
|
15
|
-
*/
|
|
16
|
-
constructor(cells, xT, yT, gridInfo) {
|
|
17
|
-
/** @type {Array.<import("../Dataset").Cell>} */
|
|
18
|
-
this.cells = cells
|
|
19
|
-
/** @type {number} */
|
|
20
|
-
this.x = xT
|
|
21
|
-
/** @type {number} */
|
|
22
|
-
this.y = yT
|
|
23
|
-
|
|
24
|
-
const r = gridInfo.resolutionGeo
|
|
25
|
-
const s = gridInfo.tileSizeCell
|
|
26
|
-
|
|
27
|
-
/** @type {import("../Dataset").Envelope} */
|
|
28
|
-
this.extGeo = {
|
|
29
|
-
xMin: gridInfo.originPoint.x + r * s * this.x,
|
|
30
|
-
xMax: gridInfo.originPoint.x + r * s * (this.x + 1),
|
|
31
|
-
yMin: gridInfo.originPoint.y + r * s * this.y,
|
|
32
|
-
yMax: gridInfo.originPoint.y + r * s * (this.y + 1),
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//convert cell coordinates into geographical coordinates
|
|
36
|
-
for (let cell of this.cells) {
|
|
37
|
-
cell.x = this.extGeo.xMin + cell.x * r
|
|
38
|
-
cell.y = this.extGeo.yMin + cell.y * r
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Legend } from '../Legend.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A legend element for segment orientation.
|
|
8
|
-
*
|
|
9
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
10
|
-
*/
|
|
11
|
-
export class SegmentOrientationLegend extends Legend {
|
|
12
|
-
/** @param {Object} opts */
|
|
13
|
-
constructor(opts) {
|
|
14
|
-
super(opts)
|
|
15
|
-
opts = opts || {}
|
|
16
|
-
|
|
17
|
-
//title
|
|
18
|
-
this.title = opts.title
|
|
19
|
-
this.titleFontSize = opts.titleFontSize || '0.8em'
|
|
20
|
-
this.titleFontWeight = opts.titleFontWeight || 'bold'
|
|
21
|
-
|
|
22
|
-
//exageration
|
|
23
|
-
this.exaggerationFactor = opts.exaggerationFactor || 0.5
|
|
24
|
-
|
|
25
|
-
//color
|
|
26
|
-
this.color = opts.color || 'gray'
|
|
27
|
-
//orientation
|
|
28
|
-
this.orientation = opts.orientation || 0
|
|
29
|
-
//width
|
|
30
|
-
this.widthPix = opts.widthPix || 3
|
|
31
|
-
|
|
32
|
-
//label
|
|
33
|
-
this.labelFontSize = opts.labelFontSize || '0.8em'
|
|
34
|
-
this.labelUnitText = opts.labelUnitText || ''
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @param {{ style: import("../style/SegmentStyle").SegmentStyle, r: number, zf: number, sColor: import("../Style").Stat, sLength: import("../Style").Stat, sWidth: import("../Style").Stat }} opts
|
|
39
|
-
*/
|
|
40
|
-
update(opts) {
|
|
41
|
-
//could happen when data is still loading
|
|
42
|
-
if (!opts.sWidth) return
|
|
43
|
-
|
|
44
|
-
//clear
|
|
45
|
-
this.div.selectAll('*').remove()
|
|
46
|
-
|
|
47
|
-
const d = this.div.append('div')
|
|
48
|
-
|
|
49
|
-
//title
|
|
50
|
-
if (this.title) {
|
|
51
|
-
d.append('div')
|
|
52
|
-
.attr('class', 'title')
|
|
53
|
-
.style('font-size', this.titleFontSize)
|
|
54
|
-
.style('font-weight', this.titleFontWeight)
|
|
55
|
-
.text(this.title)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
//compute segment width and length, in pix
|
|
59
|
-
const sWidth = this.widthPix
|
|
60
|
-
const sLength = (1 * opts.r) / opts.zf
|
|
61
|
-
|
|
62
|
-
//draw SVG segment
|
|
63
|
-
const svgS = Math.max(sLength, sWidth)
|
|
64
|
-
const svg = d.append('svg').attr('width', svgS).attr('height', svgS).style('', 'inline-block')
|
|
65
|
-
|
|
66
|
-
const cos = Math.cos((-this.orientation * Math.PI) / 180)
|
|
67
|
-
const sin = Math.sin((-this.orientation * Math.PI) / 180)
|
|
68
|
-
const dc = svgS * 0.5,
|
|
69
|
-
l2 = sLength * 0.5
|
|
70
|
-
svg.append('line')
|
|
71
|
-
.attr('x1', dc - cos * l2)
|
|
72
|
-
.attr('y1', dc - sin * l2)
|
|
73
|
-
.attr('x2', dc + cos * l2)
|
|
74
|
-
.attr('y2', dc + sin * l2)
|
|
75
|
-
.style('stroke', this.color)
|
|
76
|
-
.style('stroke-width', sWidth)
|
|
77
|
-
|
|
78
|
-
//text label
|
|
79
|
-
d.append('div')
|
|
80
|
-
//show on right of svg
|
|
81
|
-
.style('display', 'inline')
|
|
82
|
-
.style('padding-left', '5px')
|
|
83
|
-
.style('font-size', this.labelFontSize)
|
|
84
|
-
//.style("font-weight", "bold")
|
|
85
|
-
.text(this.labelUnitText)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { Legend } from '../Legend.js'
|
|
5
|
-
import { format } from 'd3-format'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A legend element for segment width.
|
|
9
|
-
*
|
|
10
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
11
|
-
*/
|
|
12
|
-
export class SegmentWidthLegend extends Legend {
|
|
13
|
-
/** @param {Object} opts */
|
|
14
|
-
constructor(opts) {
|
|
15
|
-
super(opts)
|
|
16
|
-
opts = opts || {}
|
|
17
|
-
|
|
18
|
-
//title
|
|
19
|
-
this.title = opts.title
|
|
20
|
-
this.titleFontSize = opts.titleFontSize || '0.8em'
|
|
21
|
-
this.titleFontWeight = opts.titleFontWeight || 'bold'
|
|
22
|
-
|
|
23
|
-
//exageration
|
|
24
|
-
//if set to 1, the segment width in the legend will be the one of the maximum width on the map
|
|
25
|
-
this.exaggerationFactor = opts.exaggerationFactor || 0.5
|
|
26
|
-
|
|
27
|
-
//color of the segment in the legend
|
|
28
|
-
this.color = opts.color || 'gray'
|
|
29
|
-
//orientation of the segment in the legend
|
|
30
|
-
this.orientation = opts.orientation || 0
|
|
31
|
-
|
|
32
|
-
//label
|
|
33
|
-
this.labelFontSize = opts.labelFontSize || '0.8em'
|
|
34
|
-
this.labelUnitText = opts.labelUnitText || ''
|
|
35
|
-
|
|
36
|
-
//segment length in geo unit - a function of the resolution r and zoom level zf
|
|
37
|
-
this.lengthFun = opts.lengthExaggerationFactor || ((r, zf) => r)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param {{ style: import("../style/SegmentStyle").SegmentStyle, r: number, zf: number, sColor: import("../Style").Stat, sLength: import("../Style").Stat, sWidth: import("../Style").Stat }} opts
|
|
42
|
-
*/
|
|
43
|
-
update(opts) {
|
|
44
|
-
//could happen when data is still loading
|
|
45
|
-
if (!opts.sWidth) return
|
|
46
|
-
|
|
47
|
-
//clear
|
|
48
|
-
this.div.selectAll('*').remove()
|
|
49
|
-
|
|
50
|
-
const d = this.div.append('div')
|
|
51
|
-
|
|
52
|
-
//title
|
|
53
|
-
if (this.title) {
|
|
54
|
-
d.append('div')
|
|
55
|
-
.attr('class', 'title')
|
|
56
|
-
.style('font-size', this.titleFontSize)
|
|
57
|
-
.style('font-weight', this.titleFontWeight)
|
|
58
|
-
.text(this.title)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
//get segment max value
|
|
62
|
-
const value_ = opts.sWidth.max * this.exaggerationFactor
|
|
63
|
-
//make 'nice' value (power of ten, or multiple)
|
|
64
|
-
let pow10 = Math.log10(value_)
|
|
65
|
-
pow10 = Math.floor(pow10)
|
|
66
|
-
let value = Math.pow(10, pow10)
|
|
67
|
-
if (value * 8 <= value_) value *= 8
|
|
68
|
-
else if (value * 6 <= value_) value *= 6
|
|
69
|
-
else if (value * 5 <= value_) value *= 5
|
|
70
|
-
else if (value * 4 <= value_) value *= 4
|
|
71
|
-
else if (value * 2.5 <= value_) value *= 2.5
|
|
72
|
-
else if (value * 2 <= value_) value *= 2
|
|
73
|
-
else if (value * 1.5 <= value_) value *= 1.5
|
|
74
|
-
|
|
75
|
-
//compute segment width and length, in pix
|
|
76
|
-
const sWidth = opts.widthFun(value, opts.r, opts.sWidth, opts.zf) / opts.zf
|
|
77
|
-
const sLength = this.lengthFun(opts.r, opts.zf) / opts.zf
|
|
78
|
-
|
|
79
|
-
//TODO use orientation
|
|
80
|
-
|
|
81
|
-
const svg = d.append('svg').attr('width', sLength).attr('height', sWidth).style('', 'inline-block')
|
|
82
|
-
|
|
83
|
-
//<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
|
|
84
|
-
svg.append('line')
|
|
85
|
-
.attr('x1', 0)
|
|
86
|
-
.attr('y1', sWidth / 2)
|
|
87
|
-
.attr('x2', sLength)
|
|
88
|
-
.attr('y2', sWidth / 2)
|
|
89
|
-
.style('stroke', this.color)
|
|
90
|
-
.style('stroke-width', sWidth)
|
|
91
|
-
|
|
92
|
-
const valueT = format(',.2r')(value)
|
|
93
|
-
d.append('div')
|
|
94
|
-
//show on right of graphic
|
|
95
|
-
.style('display', 'inline')
|
|
96
|
-
.style('padding-left', '5px')
|
|
97
|
-
.style('font-size', this.labelFontSize)
|
|
98
|
-
//.style("font-weight", "bold")
|
|
99
|
-
.text(valueT + (this.labelUnitText ? ' ' : '') + this.labelUnitText)
|
|
100
|
-
}
|
|
101
|
-
}
|