gridviz 2.1.13 → 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 +124 -125
- package/dist/gridviz.js +8341 -8339
- package/dist/gridviz.min.js +1 -1
- package/package.json +77 -77
- package/src/App.js +758 -758
- package/src/BackgroundLayer.js +182 -182
- package/src/BackgroundLayerWMS.js +131 -131
- package/src/Dataset.js +76 -76
- package/src/DatasetComponent.js +113 -113
- package/src/GeoCanvas.js +420 -420
- package/src/LabelLayer.js +190 -190
- package/src/Layer.js +103 -103
- package/src/Legend.js +86 -86
- package/src/LineLayer.js +150 -150
- package/src/Style.js +131 -129
- package/src/Tooltip.js +180 -180
- package/src/button/Button.js +54 -54
- package/src/button/FullscreenButton.js +98 -98
- package/src/button/ZoomButtons.js +72 -72
- package/src/dataset/COGeo.js +24 -24
- package/src/dataset/CSVGrid.js +104 -104
- package/src/dataset/GeoTIFF.js +127 -127
- package/src/dataset/GridTile.js +41 -41
- package/src/dataset/LGrid.js +54 -54
- package/src/dataset/TiledGrid.js +264 -264
- package/src/index.js +71 -71
- package/src/legend/ColorCategoryLegend.js +124 -124
- package/src/legend/ColorDiscreteLegend.js +103 -103
- package/src/legend/ColorLegend.js +128 -128
- package/src/legend/SegmentOrientationLegend.js +87 -87
- package/src/legend/SegmentWidthLegend.js +101 -101
- package/src/legend/SizeLegend.js +141 -141
- package/src/style/CompositionStyle.js +300 -300
- package/src/style/ContourStyle.js +54 -54
- package/src/style/DotDensityStyle.js +156 -156
- package/src/style/IsoFenceStyle.js +262 -262
- package/src/style/JoyPlotStyle.js +135 -135
- package/src/style/LegoStyle.js +112 -112
- package/src/style/MosaicStyle.js +107 -107
- package/src/style/NinjaStarStyle.js +125 -125
- package/src/style/PillarStyle.js +230 -230
- package/src/style/SegmentStyle.js +142 -142
- package/src/style/ShapeColorSizeStyle.js +152 -152
- package/src/style/SideCatStyle.js +172 -172
- package/src/style/SideStyle.js +216 -216
- package/src/style/SquareColorCatWGLStyle.js +120 -120
- package/src/style/SquareColorWGLStyle.js +146 -146
- package/src/style/StrokeStyle.js +131 -131
- package/src/style/TanakaStyle.js +160 -160
- package/src/style/TextStyle.js +132 -132
- package/src/style/TimeSeriesStyle.js +259 -259
- package/src/utils/Utils.js +35 -35
- package/src/utils/WebGLRectangleColoring.js +106 -106
- package/src/utils/WebGLSquareColoring.js +118 -118
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -230
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -133
- package/src/utils/WebGLSquareColoringKS.js +153 -153
- package/src/utils/stretching.js +131 -131
- package/src/utils/webGLUtils.js +71 -71
- package/src/utils/zoomUtils.js +142 -142
|
@@ -1,128 +1,128 @@
|
|
|
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 continuous color style.
|
|
9
|
-
* Inspiration: https://observablehq.com/@d3/color-legend
|
|
10
|
-
*
|
|
11
|
-
* @author Joseph Davies, Julien Gaffuri
|
|
12
|
-
*/
|
|
13
|
-
export class ColorLegend extends Legend {
|
|
14
|
-
/** @param {Object} opts */
|
|
15
|
-
constructor(opts) {
|
|
16
|
-
super(opts)
|
|
17
|
-
opts = opts || {}
|
|
18
|
-
|
|
19
|
-
this.colorRamp = opts.colorRamp
|
|
20
|
-
|
|
21
|
-
//function (t[0,1], r, s) -> v (for label text)
|
|
22
|
-
this.fun = opts.fun
|
|
23
|
-
|
|
24
|
-
this.title = opts.title
|
|
25
|
-
this.tickSize = opts.tickSize || 6
|
|
26
|
-
this.width = opts.width || 300
|
|
27
|
-
this.height = opts.height || 15
|
|
28
|
-
this.margin = opts.margin || 5
|
|
29
|
-
this.ticks = opts.ticks || Math.floor(this.width / 50)
|
|
30
|
-
this.tickFormat = opts.tickFormat || ',.0f'
|
|
31
|
-
this.tickUnit = opts.tickUnit
|
|
32
|
-
|
|
33
|
-
this.fontSize = opts.fontSize || '0.8em'
|
|
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)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param {{ style: import("../Style").Style, r: number, zf: number, sSize: import("../Style").Stat, sColor: import("../Style").Stat, sAlpha: import("../Style").Stat }} opts
|
|
42
|
-
*/
|
|
43
|
-
update(opts) {
|
|
44
|
-
//could happen when data is still loading
|
|
45
|
-
if (!opts.sColor) return
|
|
46
|
-
|
|
47
|
-
//clear
|
|
48
|
-
this.div.selectAll('*').remove()
|
|
49
|
-
|
|
50
|
-
const titleHeight = 12
|
|
51
|
-
|
|
52
|
-
const svgW = this.width + 2 * this.margin
|
|
53
|
-
const svgH = this.height + 3 * this.margin + titleHeight + this.tickSize + 10
|
|
54
|
-
const svg = this.div.append('svg').attr('width', svgW).attr('height', svgH)
|
|
55
|
-
// <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
|
|
56
|
-
|
|
57
|
-
//title
|
|
58
|
-
svg.append('text')
|
|
59
|
-
.attr('x', this.margin)
|
|
60
|
-
.attr('y', this.margin)
|
|
61
|
-
.style('font-size', '0.8em')
|
|
62
|
-
.style('font-weight', 'bold')
|
|
63
|
-
.style('alignment-baseline', 'top')
|
|
64
|
-
.style('dominant-baseline', 'hanging')
|
|
65
|
-
.style('pointer-events', 'none')
|
|
66
|
-
.text(this.title)
|
|
67
|
-
|
|
68
|
-
const g = svg
|
|
69
|
-
.append('g')
|
|
70
|
-
.attr('transform', 'translate(' + this.margin + ' ' + (2 * this.margin + titleHeight) + ')')
|
|
71
|
-
|
|
72
|
-
//draw color bar
|
|
73
|
-
const w = this.width,
|
|
74
|
-
h = this.height
|
|
75
|
-
const step = 5
|
|
76
|
-
for (let i = 0; i < w; i += step) {
|
|
77
|
-
let t = i / (w - 1)
|
|
78
|
-
if (this.invert) t = 1 - t
|
|
79
|
-
g.append('rect')
|
|
80
|
-
.attr('x', i)
|
|
81
|
-
.attr('y', 0)
|
|
82
|
-
.attr('width', step)
|
|
83
|
-
.attr('height', h)
|
|
84
|
-
.style('fill', this.colorRamp(t))
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
for (let i = 0; i < this.ticks; i++) {
|
|
88
|
-
let t = i / (this.ticks - 1)
|
|
89
|
-
|
|
90
|
-
//tick line
|
|
91
|
-
g.append('line')
|
|
92
|
-
.attr('x1', w * t)
|
|
93
|
-
.attr('y1', 0)
|
|
94
|
-
.attr('x2', w * t)
|
|
95
|
-
.attr('y2', h + this.tickSize)
|
|
96
|
-
.style('stroke', 'black')
|
|
97
|
-
|
|
98
|
-
//prepare tick label
|
|
99
|
-
g.append('text')
|
|
100
|
-
.attr('id', 'ticklabel_' + i)
|
|
101
|
-
.attr('x', w * t)
|
|
102
|
-
.attr('y', h + this.tickSize + 2)
|
|
103
|
-
.style('font-size', this.fontSize)
|
|
104
|
-
//.style("font-weight", "bold")
|
|
105
|
-
//.style("font-family", "Arial")
|
|
106
|
-
.style('text-anchor', i == 0 ? 'start' : i == this.ticks - 1 ? 'end' : 'middle')
|
|
107
|
-
.style('alignment-baseline', 'top')
|
|
108
|
-
.style('dominant-baseline', 'hanging')
|
|
109
|
-
.style('pointer-events', 'none')
|
|
110
|
-
//.text("-")
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
//update tick labels
|
|
114
|
-
|
|
115
|
-
//label text format
|
|
116
|
-
const f = this.tickFormat && this.tickFormat != 'text' ? format(this.tickFormat) : (v) => v
|
|
117
|
-
const stat = this.getStats(opts)
|
|
118
|
-
for (let i = 0; i < this.ticks; i++) {
|
|
119
|
-
let t = i / (this.ticks - 1)
|
|
120
|
-
|
|
121
|
-
const v = this.fun(t, opts.r, stat)
|
|
122
|
-
const text = (v ? f(v) : '0') + (this.tickUnit ? this.tickUnit : '')
|
|
123
|
-
|
|
124
|
-
//tick label
|
|
125
|
-
this.div.select('#' + 'ticklabel_' + i).text(text)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
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 continuous color style.
|
|
9
|
+
* Inspiration: https://observablehq.com/@d3/color-legend
|
|
10
|
+
*
|
|
11
|
+
* @author Joseph Davies, Julien Gaffuri
|
|
12
|
+
*/
|
|
13
|
+
export class ColorLegend extends Legend {
|
|
14
|
+
/** @param {Object} opts */
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
super(opts)
|
|
17
|
+
opts = opts || {}
|
|
18
|
+
|
|
19
|
+
this.colorRamp = opts.colorRamp
|
|
20
|
+
|
|
21
|
+
//function (t[0,1], r, s) -> v (for label text)
|
|
22
|
+
this.fun = opts.fun
|
|
23
|
+
|
|
24
|
+
this.title = opts.title
|
|
25
|
+
this.tickSize = opts.tickSize || 6
|
|
26
|
+
this.width = opts.width || 300
|
|
27
|
+
this.height = opts.height || 15
|
|
28
|
+
this.margin = opts.margin || 5
|
|
29
|
+
this.ticks = opts.ticks || Math.floor(this.width / 50)
|
|
30
|
+
this.tickFormat = opts.tickFormat || ',.0f'
|
|
31
|
+
this.tickUnit = opts.tickUnit
|
|
32
|
+
|
|
33
|
+
this.fontSize = opts.fontSize || '0.8em'
|
|
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)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {{ style: import("../Style").Style, r: number, zf: number, sSize: import("../Style").Stat, sColor: import("../Style").Stat, sAlpha: import("../Style").Stat }} opts
|
|
42
|
+
*/
|
|
43
|
+
update(opts) {
|
|
44
|
+
//could happen when data is still loading
|
|
45
|
+
if (!opts.sColor) return
|
|
46
|
+
|
|
47
|
+
//clear
|
|
48
|
+
this.div.selectAll('*').remove()
|
|
49
|
+
|
|
50
|
+
const titleHeight = 12
|
|
51
|
+
|
|
52
|
+
const svgW = this.width + 2 * this.margin
|
|
53
|
+
const svgH = this.height + 3 * this.margin + titleHeight + this.tickSize + 10
|
|
54
|
+
const svg = this.div.append('svg').attr('width', svgW).attr('height', svgH)
|
|
55
|
+
// <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
|
|
56
|
+
|
|
57
|
+
//title
|
|
58
|
+
svg.append('text')
|
|
59
|
+
.attr('x', this.margin)
|
|
60
|
+
.attr('y', this.margin)
|
|
61
|
+
.style('font-size', '0.8em')
|
|
62
|
+
.style('font-weight', 'bold')
|
|
63
|
+
.style('alignment-baseline', 'top')
|
|
64
|
+
.style('dominant-baseline', 'hanging')
|
|
65
|
+
.style('pointer-events', 'none')
|
|
66
|
+
.text(this.title)
|
|
67
|
+
|
|
68
|
+
const g = svg
|
|
69
|
+
.append('g')
|
|
70
|
+
.attr('transform', 'translate(' + this.margin + ' ' + (2 * this.margin + titleHeight) + ')')
|
|
71
|
+
|
|
72
|
+
//draw color bar
|
|
73
|
+
const w = this.width,
|
|
74
|
+
h = this.height
|
|
75
|
+
const step = 5
|
|
76
|
+
for (let i = 0; i < w; i += step) {
|
|
77
|
+
let t = i / (w - 1)
|
|
78
|
+
if (this.invert) t = 1 - t
|
|
79
|
+
g.append('rect')
|
|
80
|
+
.attr('x', i)
|
|
81
|
+
.attr('y', 0)
|
|
82
|
+
.attr('width', step)
|
|
83
|
+
.attr('height', h)
|
|
84
|
+
.style('fill', this.colorRamp(t))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (let i = 0; i < this.ticks; i++) {
|
|
88
|
+
let t = i / (this.ticks - 1)
|
|
89
|
+
|
|
90
|
+
//tick line
|
|
91
|
+
g.append('line')
|
|
92
|
+
.attr('x1', w * t)
|
|
93
|
+
.attr('y1', 0)
|
|
94
|
+
.attr('x2', w * t)
|
|
95
|
+
.attr('y2', h + this.tickSize)
|
|
96
|
+
.style('stroke', 'black')
|
|
97
|
+
|
|
98
|
+
//prepare tick label
|
|
99
|
+
g.append('text')
|
|
100
|
+
.attr('id', 'ticklabel_' + i)
|
|
101
|
+
.attr('x', w * t)
|
|
102
|
+
.attr('y', h + this.tickSize + 2)
|
|
103
|
+
.style('font-size', this.fontSize)
|
|
104
|
+
//.style("font-weight", "bold")
|
|
105
|
+
//.style("font-family", "Arial")
|
|
106
|
+
.style('text-anchor', i == 0 ? 'start' : i == this.ticks - 1 ? 'end' : 'middle')
|
|
107
|
+
.style('alignment-baseline', 'top')
|
|
108
|
+
.style('dominant-baseline', 'hanging')
|
|
109
|
+
.style('pointer-events', 'none')
|
|
110
|
+
//.text("-")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//update tick labels
|
|
114
|
+
|
|
115
|
+
//label text format
|
|
116
|
+
const f = this.tickFormat && this.tickFormat != 'text' ? format(this.tickFormat) : (v) => v
|
|
117
|
+
const stat = this.getStats(opts)
|
|
118
|
+
for (let i = 0; i < this.ticks; i++) {
|
|
119
|
+
let t = i / (this.ticks - 1)
|
|
120
|
+
|
|
121
|
+
const v = this.fun(t, opts.r, stat)
|
|
122
|
+
const text = (v ? f(v) : '0') + (this.tickUnit ? this.tickUnit : '')
|
|
123
|
+
|
|
124
|
+
//tick label
|
|
125
|
+
this.div.select('#' + 'ticklabel_' + i).text(text)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,87 +1,87 @@
|
|
|
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
|
+
//@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 +1,101 @@
|
|
|
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
|
-
}
|
|
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
|
+
}
|