gridviz 2.1.12 → 2.1.14
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 +32 -33
- package/dist/gridviz.js +369 -27
- package/dist/gridviz.min.js +1 -1
- package/package.json +5 -5
- package/src/App.js +58 -5
- package/src/Style.js +7 -5
- package/src/button/Button.js +54 -0
- package/src/button/FullscreenButton.js +98 -0
- package/src/button/ZoomButtons.js +72 -0
- package/src/legend/ColorLegend.js +6 -2
- package/src/legend/SegmentWidthLegend.js +11 -7
- package/src/style/SegmentStyle.js +2 -2
- package/src/style/ShapeColorSizeStyle.js +1 -1
- package/src/style/TimeSeriesStyle.js +10 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gridviz",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.14",
|
|
4
4
|
"description": "Visualization tool for gridded statistics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"statistics",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"scripts": {
|
|
40
40
|
"start": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --config webpack.config.dev.cjs",
|
|
41
41
|
"start-dev": "webpack --config webpack.config.dev.cjs",
|
|
42
|
-
"server": "webpack serve -c webpack.config.dev.
|
|
42
|
+
"server": "webpack serve -c webpack.config.dev.cjs",
|
|
43
43
|
"doc": "./node_modules/.bin/jsdoc src/ src/dataset src/legend src/style -d docs/jsdoc",
|
|
44
44
|
"bp": "webpack --config webpack.config.prod.cjs",
|
|
45
45
|
"test": "jest"
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
"jshint": "^2.12.0",
|
|
67
67
|
"prettier": "2.8.8",
|
|
68
68
|
"puppeteer": "^9.1.1",
|
|
69
|
-
"webpack": "^5.
|
|
70
|
-
"webpack-cli": "^5.
|
|
71
|
-
"webpack-dev-server": "^4.
|
|
69
|
+
"webpack": "^5.89.0",
|
|
70
|
+
"webpack-cli": "^5.1.4",
|
|
71
|
+
"webpack-dev-server": "^4.15.1",
|
|
72
72
|
"webpack-livereload-plugin": "^3.0.2"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
package/src/App.js
CHANGED
|
@@ -14,6 +14,8 @@ import { BackgroundLayerWMS } from './BackgroundLayerWMS.js'
|
|
|
14
14
|
import { LabelLayer } from './LabelLayer.js'
|
|
15
15
|
import { LineLayer } from './LineLayer.js'
|
|
16
16
|
import { monitor, monitorDuration } from './utils/Utils.js'
|
|
17
|
+
import { ZoomButtons } from './button/ZoomButtons.js'
|
|
18
|
+
import { FullscreenButton } from './button/FullscreenButton.js'
|
|
17
19
|
|
|
18
20
|
// external imports
|
|
19
21
|
import { select } from 'd3-selection'
|
|
@@ -326,7 +328,8 @@ export class App {
|
|
|
326
328
|
//canvas.addEventListener("keydown", e => { console.log(arguments) });
|
|
327
329
|
|
|
328
330
|
//set default globalCompositeOperation
|
|
329
|
-
this.defaultGlobalCompositeOperation =
|
|
331
|
+
this.defaultGlobalCompositeOperation =
|
|
332
|
+
opts.defaultGlobalCompositeOperation || this.cg.ctx.globalCompositeOperation
|
|
330
333
|
}
|
|
331
334
|
|
|
332
335
|
/**
|
|
@@ -462,10 +465,7 @@ export class App {
|
|
|
462
465
|
* @returns {Dataset}
|
|
463
466
|
*/
|
|
464
467
|
makeLGridDataset(resolution, cells, opts) {
|
|
465
|
-
return new Dataset([new LGrid(resolution, cells),],
|
|
466
|
-
[],
|
|
467
|
-
opts
|
|
468
|
-
)
|
|
468
|
+
return new Dataset([new LGrid(resolution, cells)], [], opts)
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
/**
|
|
@@ -638,6 +638,55 @@ export class App {
|
|
|
638
638
|
return this
|
|
639
639
|
}
|
|
640
640
|
|
|
641
|
+
/**
|
|
642
|
+
* Adds a set of zoom buttons to the app
|
|
643
|
+
*
|
|
644
|
+
* @param {object} opts
|
|
645
|
+
* @returns {this}
|
|
646
|
+
*/
|
|
647
|
+
addZoomButtons(opts) {
|
|
648
|
+
// * opts.id
|
|
649
|
+
// * opts.onZoom - custom event handler function
|
|
650
|
+
// * opts.x
|
|
651
|
+
// * opts.y
|
|
652
|
+
// * opts.delta - zoom delta applied on each click
|
|
653
|
+
|
|
654
|
+
this.zoomButtons = new ZoomButtons({
|
|
655
|
+
app: this,
|
|
656
|
+
id: opts?.id || 'gridviz-zoom-buttons',
|
|
657
|
+
class: opts?.class,
|
|
658
|
+
x: opts?.x || this.w - 50,
|
|
659
|
+
y: opts?.y || 10,
|
|
660
|
+
onZoom: opts?.onZoom,
|
|
661
|
+
delta: opts?.delta || 0.2
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
return this
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Adds a fullscreen toggle button to the app
|
|
669
|
+
*
|
|
670
|
+
* @param {object} opts
|
|
671
|
+
* @returns {this}
|
|
672
|
+
*/
|
|
673
|
+
addFullscreenButton(opts) {
|
|
674
|
+
// * opts.app - the gridviz app
|
|
675
|
+
// * opts.id
|
|
676
|
+
// * opts.x
|
|
677
|
+
// * opts.y
|
|
678
|
+
|
|
679
|
+
this.fullscreenButton = new FullscreenButton({
|
|
680
|
+
app: this,
|
|
681
|
+
id: opts?.id || 'gridviz-fullscreen-button',
|
|
682
|
+
class: opts?.class,
|
|
683
|
+
x: opts?.x || this.w - 50,
|
|
684
|
+
y: opts?.y || 85,
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
return this
|
|
688
|
+
}
|
|
689
|
+
|
|
641
690
|
/** @returns {this} */
|
|
642
691
|
setViewFromURL() {
|
|
643
692
|
this.cg.setViewFromURL()
|
|
@@ -670,6 +719,10 @@ export class App {
|
|
|
670
719
|
canvas.setAttribute('width', '' + this.w)
|
|
671
720
|
canvas.setAttribute('height', '' + this.h)
|
|
672
721
|
this.redraw()
|
|
722
|
+
|
|
723
|
+
//update button positions
|
|
724
|
+
if (this.zoomButtons) this.zoomButtons.node.style.left = this.w - 50 + 'px'
|
|
725
|
+
if (this.fullscreenButton) this.fullscreenButton.node.style.left = this.w - 50 + 'px'
|
|
673
726
|
}
|
|
674
727
|
})
|
|
675
728
|
}
|
package/src/Style.js
CHANGED
|
@@ -10,15 +10,12 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* A style, to show a grid dataset.
|
|
12
12
|
*
|
|
13
|
-
* @abstract
|
|
14
|
-
*
|
|
15
13
|
* @author Joseph Davies, Julien Gaffuri
|
|
16
14
|
*/
|
|
17
15
|
export class Style {
|
|
18
16
|
/**
|
|
19
17
|
* @abstract
|
|
20
|
-
* @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}} opts
|
|
21
|
-
* minZoom: The minimum zoom level when to show the layer. maxZoom: The maximum zoom level when to show the layer
|
|
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
|
|
22
19
|
*/
|
|
23
20
|
constructor(opts) {
|
|
24
21
|
opts = opts || {}
|
|
@@ -58,6 +55,10 @@ export class Style {
|
|
|
58
55
|
* */
|
|
59
56
|
this.maxZoom = opts.maxZoom || Infinity
|
|
60
57
|
|
|
58
|
+
/** A draw function for the style.
|
|
59
|
+
* @type {function} */
|
|
60
|
+
this.drawFun = opts.drawFun
|
|
61
|
+
|
|
61
62
|
//ensure acceptable values for the zoom limits.
|
|
62
63
|
if (this.minZoom >= this.maxZoom)
|
|
63
64
|
throw new Error('Unexpected zoom limits for layer. Zoom min should be smaller than zoom max.')
|
|
@@ -77,7 +78,8 @@ export class Style {
|
|
|
77
78
|
* @abstract
|
|
78
79
|
*/
|
|
79
80
|
draw(cells, resolution, cg) {
|
|
80
|
-
|
|
81
|
+
if (this.drawFun) this.drawFun(cells, resolution, cg)
|
|
82
|
+
else throw new Error('Method draw not implemented.')
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
//getters and setters
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parent class for button elements used to interact with the gridviz viewer.
|
|
3
|
+
*
|
|
4
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
5
|
+
*/
|
|
6
|
+
export class Button {
|
|
7
|
+
/**
|
|
8
|
+
* @param {Object} opts
|
|
9
|
+
* opts.parentNode
|
|
10
|
+
* opts.id
|
|
11
|
+
* opts.title
|
|
12
|
+
* opts.class
|
|
13
|
+
* opts.onClickFunction
|
|
14
|
+
* opts.x
|
|
15
|
+
* opts.y
|
|
16
|
+
*/
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
opts = opts || {}
|
|
19
|
+
|
|
20
|
+
this.app = opts.app
|
|
21
|
+
this.parentNode = opts.parentNode || opts.app.container
|
|
22
|
+
this.id = opts.id || 'button-' + Math.random()
|
|
23
|
+
|
|
24
|
+
// create HTML node
|
|
25
|
+
this.node = document.createElement('div')
|
|
26
|
+
this.node.id = this.id
|
|
27
|
+
if (opts.title) this.node.title = opts.title
|
|
28
|
+
if (opts.class) this.node.classList.add(opts.class)
|
|
29
|
+
|
|
30
|
+
// add events
|
|
31
|
+
if (opts.onClickFunction) this.node.addEventListener('onclick', opts.onClickFunction)
|
|
32
|
+
this.node.addEventListener('mouseover', (e)=>{this.node.style.backgroundColor = 'lightgrey'})
|
|
33
|
+
this.node.addEventListener('mouseout', (e)=>{this.node.style.backgroundColor = '#ffffff'})
|
|
34
|
+
|
|
35
|
+
//set styles
|
|
36
|
+
this.node.classList.add(opts.class)
|
|
37
|
+
this.node.style.boxShadow =
|
|
38
|
+
'0 7px 8px rgba(0,47,103,.08), 0 0 22px rgba(0,47,103,.04), 0 12px 17px rgba(0,47,103,.04), 0 -4px 4px rgba(0,47,103,.04)' //.ecl-u-shadow-3
|
|
39
|
+
this.node.style.backgroundColor = '#ffffff' //.ecl-u-bg-white
|
|
40
|
+
this.node.style.position = 'absolute'
|
|
41
|
+
this.node.style.cursor = 'pointer'
|
|
42
|
+
this.node.style.display = 'flex'
|
|
43
|
+
this.node.style.justifyContent = 'center'
|
|
44
|
+
this.node.style.alignItems = 'center'
|
|
45
|
+
this.node.style.width = '30px'
|
|
46
|
+
this.node.style.height = '30px'
|
|
47
|
+
// this.node.style.padding = '4px'
|
|
48
|
+
this.node.style.top = opts.y + 'px'
|
|
49
|
+
this.node.style.left = opts.x + 'px'
|
|
50
|
+
|
|
51
|
+
// append to parent
|
|
52
|
+
this.parentNode.appendChild(this.node)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Button } from './Button.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Button for toggling fullscreen mode
|
|
5
|
+
*
|
|
6
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
7
|
+
*/
|
|
8
|
+
export class FullscreenButton extends Button {
|
|
9
|
+
/**
|
|
10
|
+
* @param {Object} opts
|
|
11
|
+
* opts.parentNode - the node that the button is appended to
|
|
12
|
+
* opts.canvas - the gridviz canvas
|
|
13
|
+
* opts.id
|
|
14
|
+
* opts.title - HTML title attribute
|
|
15
|
+
* opts.class - css class
|
|
16
|
+
* opts.onClickFunction
|
|
17
|
+
* opts.x - x position of the button
|
|
18
|
+
* opts.y - y position of the button
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// default state
|
|
22
|
+
isFullscreen = false
|
|
23
|
+
|
|
24
|
+
constructor(opts) {
|
|
25
|
+
super(opts)
|
|
26
|
+
|
|
27
|
+
// append fullscreen icon to button container
|
|
28
|
+
this.node.innerHTML = `
|
|
29
|
+
<svg
|
|
30
|
+
style="height: 1.2rem; width: 1.2rem; fill:black; margin:0;"
|
|
31
|
+
focusable="false"
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
>
|
|
34
|
+
<svg fill="#000000" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
|
|
35
|
+
<title/>
|
|
36
|
+
<g>
|
|
37
|
+
<path d="M30,0H6A5.9966,5.9966,0,0,0,0,6V30a6,6,0,0,0,12,0V12H30A6,6,0,0,0,30,0Z"/>
|
|
38
|
+
<path d="M90,0H66a6,6,0,0,0,0,12H84V30a6,6,0,0,0,12,0V6A5.9966,5.9966,0,0,0,90,0Z"/>
|
|
39
|
+
<path d="M30,84H12V66A6,6,0,0,0,0,66V90a5.9966,5.9966,0,0,0,6,6H30a6,6,0,0,0,0-12Z"/>
|
|
40
|
+
<path d="M90,60a5.9966,5.9966,0,0,0-6,6V84H66a6,6,0,0,0,0,12H90a5.9966,5.9966,0,0,0,6-6V66A5.9966,5.9966,0,0,0,90,60Z"/>
|
|
41
|
+
</g>
|
|
42
|
+
</svg>
|
|
43
|
+
</svg>
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
//save initial app dimensions
|
|
47
|
+
this.defaultHeight = this.app.h
|
|
48
|
+
this.defaultWidth = this.app.w
|
|
49
|
+
|
|
50
|
+
// event handler
|
|
51
|
+
this.node.addEventListener('click', (e) => {
|
|
52
|
+
this.onClickFunction(e)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onClickFunction(e) {
|
|
58
|
+
if (this.isFullscreen) {
|
|
59
|
+
this.closeFullscreen(containerDiv)
|
|
60
|
+
//resize canvas to default
|
|
61
|
+
this.app.h = this.defaultHeight
|
|
62
|
+
this.app.w = this.defaultWidth
|
|
63
|
+
this.isFullscreen = false
|
|
64
|
+
} else {
|
|
65
|
+
this.openFullscreen(containerDiv)
|
|
66
|
+
//resize canvas to fullscreen
|
|
67
|
+
this.app.h = window.screen.height
|
|
68
|
+
this.app.w = window.screen.width
|
|
69
|
+
this.isFullscreen = true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Open fullscreen */
|
|
74
|
+
openFullscreen(elem) {
|
|
75
|
+
if (elem.requestFullscreen) {
|
|
76
|
+
elem.requestFullscreen()
|
|
77
|
+
} else if (elem.webkitRequestFullscreen) {
|
|
78
|
+
/* Safari */
|
|
79
|
+
elem.webkitRequestFullscreen()
|
|
80
|
+
} else if (elem.msRequestFullscreen) {
|
|
81
|
+
/* IE11 */
|
|
82
|
+
elem.msRequestFullscreen()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Close fullscreen */
|
|
87
|
+
closeFullscreen() {
|
|
88
|
+
if (document.exitFullscreen) {
|
|
89
|
+
document.exitFullscreen()
|
|
90
|
+
} else if (document.webkitExitFullscreen) {
|
|
91
|
+
/* Safari */
|
|
92
|
+
document.webkitExitFullscreen()
|
|
93
|
+
} else if (document.msExitFullscreen) {
|
|
94
|
+
/* IE11 */
|
|
95
|
+
document.msExitFullscreen()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Button } from './Button.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Button for toggling fullscreen mode
|
|
6
|
+
*
|
|
7
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
8
|
+
*/
|
|
9
|
+
export class ZoomButtons extends Button {
|
|
10
|
+
/**
|
|
11
|
+
* @param {Object} opts
|
|
12
|
+
*/
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
super(opts)
|
|
15
|
+
|
|
16
|
+
this.onZoom = opts.onZoom // custom user event handler
|
|
17
|
+
this.delta = opts.delta || 0.2
|
|
18
|
+
|
|
19
|
+
// zoom in btn
|
|
20
|
+
this.zoomInBtn = document.createElement('a')
|
|
21
|
+
this.zoomInBtn.innerHTML = `<a id="zoomin" class="gridviz-zoom-button" title="Zoom in">+</a>`
|
|
22
|
+
this.zoomInBtn.title = 'Zoom in';
|
|
23
|
+
this.zoomInBtn.addEventListener('click', (e)=>{this.zoomIn(e)})
|
|
24
|
+
this.zoomInBtn.addEventListener('mouseover', (e)=>{this.zoomInBtn.style.backgroundColor = 'lightgrey'})
|
|
25
|
+
this.zoomInBtn.addEventListener('mouseout', (e)=>{this.zoomInBtn.style.backgroundColor = '#ffffff'})
|
|
26
|
+
|
|
27
|
+
// zoom out btn
|
|
28
|
+
this.zoomOutBtn = document.createElement('a')
|
|
29
|
+
this.zoomOutBtn.innerHTML = `<a id="zoomin" class="gridviz-zoom-button" title="Zoom out">-</a>`
|
|
30
|
+
this.zoomOutBtn.title = 'Zoom out';
|
|
31
|
+
this.zoomOutBtn.addEventListener('click', (e)=>{this.zoomOut(e)})
|
|
32
|
+
this.zoomOutBtn.addEventListener('mouseover', (e)=>{this.zoomOutBtn.style.backgroundColor = 'lightgrey'})
|
|
33
|
+
this.zoomOutBtn.addEventListener('mouseout', (e)=>{this.zoomOutBtn.style.backgroundColor = '#ffffff'})
|
|
34
|
+
|
|
35
|
+
//set styles
|
|
36
|
+
let btns = [this.zoomInBtn, this.zoomOutBtn]
|
|
37
|
+
btns.forEach((btn, i)=>{
|
|
38
|
+
btn.style.alignItems = 'center';
|
|
39
|
+
btn.style.justifyContent = 'center';
|
|
40
|
+
btn.style.display = 'flex';
|
|
41
|
+
btn.style.border = 'none';
|
|
42
|
+
btn.style.color = 'black';
|
|
43
|
+
btn.style.textAlign = 'center';
|
|
44
|
+
btn.style.textDecoration = 'none';
|
|
45
|
+
btn.style.padding = '4px';
|
|
46
|
+
btn.style.fontSize = '20px';
|
|
47
|
+
btn.style.fontWeight = 'bold';
|
|
48
|
+
btn.style.userSelect = 'none';
|
|
49
|
+
if (i==0) btn.style.borderBottom = '1px solid grey'
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// unset parent class height
|
|
53
|
+
this.node.style.height="unset"
|
|
54
|
+
this.node.style.display="unset"
|
|
55
|
+
|
|
56
|
+
// append to button container
|
|
57
|
+
this.node.appendChild(this.zoomInBtn)
|
|
58
|
+
this.node.appendChild(this.zoomOutBtn)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Zoom in */
|
|
62
|
+
zoomIn(e) {
|
|
63
|
+
this.app.setZoomFactor(this.app.getZoomFactor() * (1 - this.delta)).redraw()
|
|
64
|
+
if (this.onZoom) this.onZoom(e)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Zoom out */
|
|
68
|
+
zoomOut(e) {
|
|
69
|
+
this.app.setZoomFactor(this.app.getZoomFactor() * (1 + this.delta)).redraw()
|
|
70
|
+
if (this.onZoom) this.onZoom(e)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -32,10 +32,13 @@ export class ColorLegend extends Legend {
|
|
|
32
32
|
|
|
33
33
|
this.fontSize = opts.fontSize || '0.8em'
|
|
34
34
|
this.invert = opts.invert
|
|
35
|
+
|
|
36
|
+
//to be used as opts => opts.sAlpha to show legend on alpha channel
|
|
37
|
+
this.getStats = opts.getStats || (opts => opts.sColor)
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
/**
|
|
38
|
-
* @param {{ style: import("../Style").Style, r: number, zf: number, sSize: import("../Style").Stat, sColor: import("../Style").Stat }} opts
|
|
41
|
+
* @param {{ style: import("../Style").Style, r: number, zf: number, sSize: import("../Style").Stat, sColor: import("../Style").Stat, sAlpha: import("../Style").Stat }} opts
|
|
39
42
|
*/
|
|
40
43
|
update(opts) {
|
|
41
44
|
//could happen when data is still loading
|
|
@@ -111,10 +114,11 @@ export class ColorLegend extends Legend {
|
|
|
111
114
|
|
|
112
115
|
//label text format
|
|
113
116
|
const f = this.tickFormat && this.tickFormat != 'text' ? format(this.tickFormat) : (v) => v
|
|
117
|
+
const stat = this.getStats(opts)
|
|
114
118
|
for (let i = 0; i < this.ticks; i++) {
|
|
115
119
|
let t = i / (this.ticks - 1)
|
|
116
120
|
|
|
117
|
-
const v = this.fun(t, opts.r,
|
|
121
|
+
const v = this.fun(t, opts.r, stat)
|
|
118
122
|
const text = (v ? f(v) : '0') + (this.tickUnit ? this.tickUnit : '')
|
|
119
123
|
|
|
120
124
|
//tick label
|
|
@@ -21,16 +21,20 @@ export class SegmentWidthLegend extends Legend {
|
|
|
21
21
|
this.titleFontWeight = opts.titleFontWeight || 'bold'
|
|
22
22
|
|
|
23
23
|
//exageration
|
|
24
|
+
//if set to 1, the segment width in the legend will be the one of the maximum width on the map
|
|
24
25
|
this.exaggerationFactor = opts.exaggerationFactor || 0.5
|
|
25
26
|
|
|
26
|
-
//color
|
|
27
|
+
//color of the segment in the legend
|
|
27
28
|
this.color = opts.color || 'gray'
|
|
28
|
-
//orientation
|
|
29
|
+
//orientation of the segment in the legend
|
|
29
30
|
this.orientation = opts.orientation || 0
|
|
30
31
|
|
|
31
32
|
//label
|
|
32
33
|
this.labelFontSize = opts.labelFontSize || '0.8em'
|
|
33
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)
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
@@ -54,10 +58,9 @@ export class SegmentWidthLegend extends Legend {
|
|
|
54
58
|
.text(this.title)
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
//get max value
|
|
61
|
+
//get segment max value
|
|
58
62
|
const value_ = opts.sWidth.max * this.exaggerationFactor
|
|
59
|
-
|
|
60
|
-
//take 'nice' value (power of ten, or multiple)
|
|
63
|
+
//make 'nice' value (power of ten, or multiple)
|
|
61
64
|
let pow10 = Math.log10(value_)
|
|
62
65
|
pow10 = Math.floor(pow10)
|
|
63
66
|
let value = Math.pow(10, pow10)
|
|
@@ -67,10 +70,11 @@ export class SegmentWidthLegend extends Legend {
|
|
|
67
70
|
else if (value * 4 <= value_) value *= 4
|
|
68
71
|
else if (value * 2.5 <= value_) value *= 2.5
|
|
69
72
|
else if (value * 2 <= value_) value *= 2
|
|
73
|
+
else if (value * 1.5 <= value_) value *= 1.5
|
|
70
74
|
|
|
71
75
|
//compute segment width and length, in pix
|
|
72
|
-
const sWidth = opts.
|
|
73
|
-
const sLength = (
|
|
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
|
|
74
78
|
|
|
75
79
|
//TODO use orientation
|
|
76
80
|
|
|
@@ -131,11 +131,11 @@ export class SegmentStyle extends Style {
|
|
|
131
131
|
|
|
132
132
|
//update legend, if any
|
|
133
133
|
this.updateLegends({
|
|
134
|
-
|
|
134
|
+
widthFun: this.width,
|
|
135
135
|
r: r,
|
|
136
136
|
zf: zf,
|
|
137
137
|
sColor: statColor,
|
|
138
|
-
sLength: statLength,
|
|
138
|
+
//sLength: statLength,
|
|
139
139
|
sWidth: statWidth,
|
|
140
140
|
})
|
|
141
141
|
}
|
|
@@ -147,6 +147,6 @@ export class ShapeColorSizeStyle extends Style {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
//update legends
|
|
150
|
-
this.updateLegends({ style: this, r: r, zf: zf, sSize: statSize, sColor: statColor })
|
|
150
|
+
this.updateLegends({ style: this, r: r, zf: zf, sSize: statSize, sColor: statColor, sAlpha: statAlpha })
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -50,7 +50,6 @@ export class TimeSeriesStyle extends Style {
|
|
|
50
50
|
* @type {function(number,number,import("../Style.js").Stat|undefined,number):number} */
|
|
51
51
|
this.lineWidth = opts.lineWidth || ((v, r, s, zf) => 1.5 * zf)
|
|
52
52
|
|
|
53
|
-
|
|
54
53
|
/**
|
|
55
54
|
* @type {string} */
|
|
56
55
|
this.colorCol = opts.colorCol
|
|
@@ -244,6 +243,16 @@ export class TimeSeriesStyle extends Style {
|
|
|
244
243
|
|
|
245
244
|
}
|
|
246
245
|
|
|
246
|
+
//update legend, if any
|
|
247
|
+
this.updateLegends({
|
|
248
|
+
widthFun: this.lineWidth,
|
|
249
|
+
r: r,
|
|
250
|
+
zf: zf,
|
|
251
|
+
sColor: statColor,
|
|
252
|
+
//sLength: statLength,
|
|
253
|
+
sWidth: statWidth,
|
|
254
|
+
})
|
|
255
|
+
|
|
247
256
|
}
|
|
248
257
|
|
|
249
258
|
}
|