gridviz 3.0.38 → 3.0.39
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/dist/gridviz.js +103 -50
- package/dist/gridviz.min.js +1 -1
- package/package.json +1 -1
- package/src/button/Button.js +2 -1
- package/src/button/FullscreenButton.js +2 -0
- package/src/button/ZoomButtons.js +3 -2
- package/src/core/GeoCanvas.js +34 -38
- package/src/core/Legend.js +3 -0
- package/src/core/Map.js +5 -1
- package/src/core/Tooltip.js +3 -0
- package/src/layer/GridLayer.js +2 -1
- package/src/legend/ColorCategoryLegend.js +4 -0
- package/src/legend/ColorDiscreteLegend.js +1 -0
- package/src/legend/ColorLegend.js +2 -2
- package/src/legend/OrientationLegend.js +2 -1
- package/src/legend/SizeLegend.js +5 -0
- package/src/legend/TernaryLegend.js +4 -2
- package/src/utils/scale.js +30 -1
package/package.json
CHANGED
package/src/button/Button.js
CHANGED
|
@@ -30,7 +30,8 @@ export class Button {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (opts.title) this.div.attr('title', opts.title)
|
|
33
|
-
|
|
33
|
+
this.div.classed('gridviz-button', true)
|
|
34
|
+
if (opts.class) for (const c of String(opts.class).split(/\s+/)) if (c) this.div.classed(c, true)
|
|
34
35
|
|
|
35
36
|
// add events
|
|
36
37
|
if (opts.onClickFunction) this.div.on('click', opts.onClickFunction)
|
|
@@ -24,10 +24,12 @@ export class FullscreenButton extends Button {
|
|
|
24
24
|
|
|
25
25
|
constructor(opts) {
|
|
26
26
|
super(opts)
|
|
27
|
+
this.div.classed('gridviz-fullscreen-button', true)
|
|
27
28
|
|
|
28
29
|
// append fullscreen icon to button container
|
|
29
30
|
this.div.node().innerHTML = `
|
|
30
31
|
<svg
|
|
32
|
+
class="gridviz-fullscreen-icon"
|
|
31
33
|
style="height: 1.2rem; width: 1.2rem; fill:black; margin:0;"
|
|
32
34
|
focusable="false"
|
|
33
35
|
aria-hidden="true"
|
|
@@ -15,11 +15,12 @@ export class ZoomButtons extends Button {
|
|
|
15
15
|
|
|
16
16
|
this.onZoom = opts.onZoom // custom user event handler
|
|
17
17
|
this.delta = opts.delta || 0.2
|
|
18
|
+
this.div.classed('gridviz-zoom-buttons', true)
|
|
18
19
|
|
|
19
20
|
// Create zoom in button
|
|
20
21
|
this.zoomInBtn = document.createElement('a')
|
|
21
22
|
this.zoomInBtn.id = 'zoom-in'
|
|
22
|
-
this.zoomInBtn.className = 'gridviz-zoom-button'
|
|
23
|
+
this.zoomInBtn.className = 'gridviz-zoom-button gridviz-zoom-button--in'
|
|
23
24
|
this.zoomInBtn.title = 'Zoom in'
|
|
24
25
|
this.zoomInBtn.textContent = '+'
|
|
25
26
|
this.zoomInBtn.addEventListener('click', (e) => {
|
|
@@ -35,7 +36,7 @@ export class ZoomButtons extends Button {
|
|
|
35
36
|
// Create zoom out button
|
|
36
37
|
this.zoomOutBtn = document.createElement('a')
|
|
37
38
|
this.zoomOutBtn.id = 'zoom-out'
|
|
38
|
-
this.zoomOutBtn.className = 'gridviz-zoom-button'
|
|
39
|
+
this.zoomOutBtn.className = 'gridviz-zoom-button gridviz-zoom-button--out'
|
|
39
40
|
this.zoomOutBtn.title = 'Zoom out'
|
|
40
41
|
this.zoomOutBtn.textContent = '-'
|
|
41
42
|
this.zoomOutBtn.addEventListener('click', (e) => {
|
package/src/core/GeoCanvas.js
CHANGED
|
@@ -114,6 +114,7 @@ export class GeoCanvas {
|
|
|
114
114
|
this.canvasSave.dx = 0
|
|
115
115
|
this.canvasSave.dy = 0
|
|
116
116
|
this.canvasSave.f = 1
|
|
117
|
+
this.canvasSave.view = { x: this.view.x, y: this.view.y, z: this.view.z }
|
|
117
118
|
if (this.onZoomStartFun) this.onZoomStartFun(e)
|
|
118
119
|
})
|
|
119
120
|
.on('end', (e) => {
|
|
@@ -179,7 +180,7 @@ export class GeoCanvas {
|
|
|
179
180
|
this.zoomExtent = opts.zoomExtent || [0, Infinity]
|
|
180
181
|
|
|
181
182
|
/** Canvas state, to be used to avoid unnecessary redraws on zoom/pan
|
|
182
|
-
* @type {{c:HTMLCanvasElement|null,dx:number,dy:number,f:number}} */
|
|
183
|
+
* @type {{c:HTMLCanvasElement|null,dx:number,dy:number,f:number,view?:{x:number,y:number,z:number}}} */
|
|
183
184
|
this.canvasSave = { c: null, dx: 0, dy: 0, f: 1 }
|
|
184
185
|
}
|
|
185
186
|
|
|
@@ -200,21 +201,7 @@ export class GeoCanvas {
|
|
|
200
201
|
this.updateExtentGeo()
|
|
201
202
|
|
|
202
203
|
if (this.canvasSave.c) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// Update saved canvas offset
|
|
206
|
-
this.canvasSave.dx -= dxGeo * scale
|
|
207
|
-
this.canvasSave.dy += dyGeo * scale
|
|
208
|
-
|
|
209
|
-
// clear canvas
|
|
210
|
-
this.clear(this.backgroundColor)
|
|
211
|
-
|
|
212
|
-
// this doesnt work on mobile https://github.com/eurostat/gridviz/issues/98
|
|
213
|
-
//this.ctx.drawImage(this.canvasSave.c, this.canvasSave.dx, this.canvasSave.dy)
|
|
214
|
-
this.offscreenCtx.drawImage(this.canvasSave.c, this.canvasSave.dx, this.canvasSave.dy)
|
|
215
|
-
|
|
216
|
-
// Render the offscreen canvas to the visible context
|
|
217
|
-
this.ctx.drawImage(this.offscreenCtx.canvas, 0, 0)
|
|
204
|
+
this._drawSnapshot()
|
|
218
205
|
} else {
|
|
219
206
|
console.log('no canvas save')
|
|
220
207
|
}
|
|
@@ -258,29 +245,38 @@ export class GeoCanvas {
|
|
|
258
245
|
this._drawZoomFrame(f, xGeo, yGeo)
|
|
259
246
|
}
|
|
260
247
|
|
|
261
|
-
_drawZoomFrame(
|
|
248
|
+
_drawZoomFrame() {
|
|
262
249
|
// zoom in on the current canvas state
|
|
263
|
-
if (this.canvasSave.c)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
250
|
+
if (this.canvasSave.c) this._drawSnapshot()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Draw the canvas saved when the pan/zoom started where it belongs in the current view.
|
|
255
|
+
* It is placed from the two views (the one it was taken at and the current one) rather than
|
|
256
|
+
* accumulated from each step: the zoom anchor follows the mouse, and an accumulation that
|
|
257
|
+
* assumes it stays put leaves the picture away from where the final redraw puts it.
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
_drawSnapshot() {
|
|
261
|
+
const sv = this.canvasSave.view
|
|
262
|
+
const f = sv ? sv.z / this.view.z : 1
|
|
263
|
+
// where the saved canvas' top left corner is in the current view
|
|
264
|
+
const dx = sv ? (sv.x - (this.w * 0.5) * sv.z - this.view.x) / this.view.z + this.w * 0.5 : 0
|
|
265
|
+
const dy = sv ? this.h * 0.5 - (sv.y + (this.h * 0.5) * sv.z - this.view.y) / this.view.z : 0
|
|
266
|
+
this.canvasSave.f = f
|
|
267
|
+
this.canvasSave.dx = dx
|
|
268
|
+
this.canvasSave.dy = dy
|
|
269
|
+
|
|
270
|
+
this.clear(this.backgroundColor)
|
|
271
|
+
// this doesnt work on mobile https://github.com/eurostat/gridviz/issues/98 : drawn on the offscreen canvas first
|
|
272
|
+
this.offscreenCtx.drawImage(
|
|
273
|
+
this.canvasSave.c,
|
|
274
|
+
dx,
|
|
275
|
+
dy,
|
|
276
|
+
f * this.canvasSave.c.width,
|
|
277
|
+
f * this.canvasSave.c.height
|
|
278
|
+
)
|
|
279
|
+
this.ctx.drawImage(this.offscreenCanvas, 0, 0, this.canvas.width, this.canvas.height)
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
/**
|
package/src/core/Legend.js
CHANGED
|
@@ -127,6 +127,9 @@ export class Legend {
|
|
|
127
127
|
highlight(colors) {
|
|
128
128
|
if (!this.interactive || !this.style_) return
|
|
129
129
|
const before = this.style_.highlightColors
|
|
130
|
+
// flag the legend while hovered, so that the map's redraw leaves its element in place:
|
|
131
|
+
// a hovered element that is detached and appended again never gets its mouseleave
|
|
132
|
+
if (this.div) this.div.attr('data-gridviz-hovered', colors && colors.length ? '' : null)
|
|
130
133
|
this.style_.setHighlight(colors)
|
|
131
134
|
// nothing to redraw when the highlight didn't change (mouse moving between a swatch's parts)
|
|
132
135
|
if (before === null && this.style_.highlightColors === null) return
|
package/src/core/Map.js
CHANGED
|
@@ -46,6 +46,7 @@ export class Map {
|
|
|
46
46
|
console.error('Cannot find gridviz container element.')
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
|
+
this.container.classList.add('gridviz-map')
|
|
49
50
|
|
|
50
51
|
//https://css-tricks.com/absolute-positioning-inside-relative-positioning/
|
|
51
52
|
this.container.style.position = 'relative' // container element must have relative positioning
|
|
@@ -174,6 +175,7 @@ export class Map {
|
|
|
174
175
|
*/
|
|
175
176
|
initialiseCanvas() {
|
|
176
177
|
const canvas = document.createElement('canvas')
|
|
178
|
+
canvas.classList.add('gridviz-canvas')
|
|
177
179
|
canvas.setAttribute('width', '' + this.w)
|
|
178
180
|
canvas.setAttribute('height', '' + this.h)
|
|
179
181
|
this.container.appendChild(canvas)
|
|
@@ -184,6 +186,7 @@ export class Map {
|
|
|
184
186
|
this.legend = select(this.container)
|
|
185
187
|
.append('div') // Create a new container
|
|
186
188
|
.attr('id', 'gridviz-legend')
|
|
189
|
+
.classed('gridviz-legends', true)
|
|
187
190
|
.style('position', 'absolute')
|
|
188
191
|
.style('width', 'auto')
|
|
189
192
|
.style('height', 'auto')
|
|
@@ -241,7 +244,8 @@ export class Map {
|
|
|
241
244
|
|
|
242
245
|
//remove legend elements: the legends themselves only, not what is inside them
|
|
243
246
|
//(a legend keeps its content while one of its swatches is hovered, see Style.updateLegends)
|
|
244
|
-
|
|
247
|
+
//except the one being hovered, which would lose its mouseleave (see Legend.highlight)
|
|
248
|
+
if (this.legend) this.legend.selectAll(':scope > *:not([data-gridviz-hovered])').remove()
|
|
245
249
|
|
|
246
250
|
//clear
|
|
247
251
|
this.geoCanvas.initCanvasTransform()
|
package/src/core/Tooltip.js
CHANGED
|
@@ -75,6 +75,9 @@ export class Tooltip {
|
|
|
75
75
|
this.tooltip.style('left', '0')
|
|
76
76
|
this.tooltip.style('top', '0')
|
|
77
77
|
|
|
78
|
+
// a tooltip element given by the user gets the class too
|
|
79
|
+
this.tooltip.classed('gridviz-tooltip', true)
|
|
80
|
+
|
|
78
81
|
// aria-labels (thanks to wahlatlas)
|
|
79
82
|
this.tooltip.attr('role', 'tooltip').attr('aria-live', 'polite')
|
|
80
83
|
}
|
package/src/layer/GridLayer.js
CHANGED
|
@@ -137,7 +137,8 @@ export class GridLayer extends Layer {
|
|
|
137
137
|
// so that hovering a swatch can highlight the cells of the style on the map
|
|
138
138
|
lg.style_ = style
|
|
139
139
|
lg.redraw = () => (geoCanvas.redraw ? geoCanvas.redraw() : undefined)
|
|
140
|
-
|
|
140
|
+
// a hovered legend is still in place (see Map.redrawNow): moving it would lose its mouseleave
|
|
141
|
+
if (lg.div.node().parentNode !== legendComp.node()) legendComp.node().append(lg.div.node())
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
@@ -64,9 +64,11 @@ export class ColorCategoryLegend extends Legend {
|
|
|
64
64
|
const h = this.dimension.h || 15
|
|
65
65
|
const w = this.dimension.w || 20
|
|
66
66
|
d.append('div')
|
|
67
|
+
.classed('gridviz-legend-symbol-wrapper', true)
|
|
67
68
|
.style('display', 'inline')
|
|
68
69
|
|
|
69
70
|
.append('svg')
|
|
71
|
+
.classed('gridviz-legend-graphic', true)
|
|
70
72
|
.attr('width', w + 2 * sw)
|
|
71
73
|
.attr('height', h + 2 * sw)
|
|
72
74
|
|
|
@@ -83,9 +85,11 @@ export class ColorCategoryLegend extends Legend {
|
|
|
83
85
|
const r = this.dimension.r || 8
|
|
84
86
|
const h = 2 * r + 2 * sw
|
|
85
87
|
d.append('div')
|
|
88
|
+
.classed('gridviz-legend-symbol-wrapper', true)
|
|
86
89
|
.style('display', 'inline')
|
|
87
90
|
|
|
88
91
|
.append('svg')
|
|
92
|
+
.classed('gridviz-legend-graphic', true)
|
|
89
93
|
.attr('width', h)
|
|
90
94
|
.attr('height', h)
|
|
91
95
|
|
|
@@ -54,10 +54,10 @@ export class ColorLegend extends Legend {
|
|
|
54
54
|
const width = this.availableWidth(this.width)
|
|
55
55
|
const svgW = width + 2 * this.margin
|
|
56
56
|
const svgH = this.height + this.margin + this.tickSize + 10
|
|
57
|
-
const svg = this.div.append('svg').attr('width', svgW).attr('height', svgH)
|
|
57
|
+
const svg = this.div.append('svg').classed('gridviz-legend-graphic', true).attr('width', svgW).attr('height', svgH)
|
|
58
58
|
// <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
|
|
59
59
|
|
|
60
|
-
const g = svg.append('g').attr('transform', 'translate(' + this.margin + ' ' + 0 + ')')
|
|
60
|
+
const g = svg.append('g').classed('gridviz-legend-bar', true).attr('transform', 'translate(' + this.margin + ' ' + 0 + ')')
|
|
61
61
|
|
|
62
62
|
//draw color bar
|
|
63
63
|
const w = width,
|
|
@@ -48,13 +48,14 @@ export class OrientationLegend extends Legend {
|
|
|
48
48
|
|
|
49
49
|
//draw SVG segment
|
|
50
50
|
const svgS = Math.max(lengthPix, widthPix)
|
|
51
|
-
const svg = d.append('svg').attr('width', svgS).attr('height', svgS).style('', 'inline-block')
|
|
51
|
+
const svg = d.append('svg').classed('gridviz-legend-graphic', true).attr('width', svgS).attr('height', svgS).style('', 'inline-block')
|
|
52
52
|
|
|
53
53
|
const cos = Math.cos((-this.orientation * Math.PI) / 180)
|
|
54
54
|
const sin = Math.sin((-this.orientation * Math.PI) / 180)
|
|
55
55
|
const dc = svgS * 0.5,
|
|
56
56
|
l2 = lengthPix * 0.5
|
|
57
57
|
svg.append('line')
|
|
58
|
+
.classed('gridviz-legend-symbol', true)
|
|
58
59
|
.attr('x1', dc - cos * l2)
|
|
59
60
|
.attr('y1', dc - sin * l2)
|
|
60
61
|
.attr('x2', dc + cos * l2)
|
package/src/legend/SizeLegend.js
CHANGED
|
@@ -71,6 +71,7 @@ export class SizeLegend extends Legend {
|
|
|
71
71
|
const svg = () =>
|
|
72
72
|
d
|
|
73
73
|
.append('svg')
|
|
74
|
+
.classed('gridviz-legend-graphic', true)
|
|
74
75
|
.attr('width', sizePix + this.strokeWidth + 2)
|
|
75
76
|
.attr('height', sizePix + this.strokeWidth + 2)
|
|
76
77
|
.style('', 'inline-block')
|
|
@@ -78,6 +79,7 @@ export class SizeLegend extends Legend {
|
|
|
78
79
|
if (this.shape === 'square') {
|
|
79
80
|
svg()
|
|
80
81
|
.append('rect')
|
|
82
|
+
.classed('gridviz-legend-symbol', true)
|
|
81
83
|
.attr('x', 0)
|
|
82
84
|
.attr('y', 0)
|
|
83
85
|
.attr('width', sizePix)
|
|
@@ -90,6 +92,7 @@ export class SizeLegend extends Legend {
|
|
|
90
92
|
const r = (sizePix + this.strokeWidth) * 0.5
|
|
91
93
|
svg()
|
|
92
94
|
.append('circle')
|
|
95
|
+
.classed('gridviz-legend-symbol', true)
|
|
93
96
|
.attr('cx', r + 1)
|
|
94
97
|
.attr('cy', r + 1)
|
|
95
98
|
.attr('r', r)
|
|
@@ -109,6 +112,7 @@ export class SizeLegend extends Legend {
|
|
|
109
112
|
|
|
110
113
|
const svg = d
|
|
111
114
|
.append('svg')
|
|
115
|
+
.classed('gridviz-legend-graphic', true)
|
|
112
116
|
.attr('width', lengthPix)
|
|
113
117
|
.attr('height', sizePix)
|
|
114
118
|
.style('', 'inline-block')
|
|
@@ -116,6 +120,7 @@ export class SizeLegend extends Legend {
|
|
|
116
120
|
//TODO orientation
|
|
117
121
|
//<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
|
|
118
122
|
svg.append('line')
|
|
123
|
+
.classed('gridviz-legend-symbol', true)
|
|
119
124
|
.attr('x1', 0)
|
|
120
125
|
.attr('y1', sizePix / 2)
|
|
121
126
|
.attr('x2', lengthPix)
|
|
@@ -57,6 +57,7 @@ export class TernaryLegend extends Legend {
|
|
|
57
57
|
//make svg element
|
|
58
58
|
const svg = this.div
|
|
59
59
|
.append('svg')
|
|
60
|
+
.classed('gridviz-legend-graphic', true)
|
|
60
61
|
.attr('width', w + selectionStrokeWidth)
|
|
61
62
|
.attr('height', h + 4 * padding + 2 * fontSize)
|
|
62
63
|
|
|
@@ -88,6 +89,7 @@ export class TernaryLegend extends Legend {
|
|
|
88
89
|
//triangle group
|
|
89
90
|
const g = svg
|
|
90
91
|
.append('g')
|
|
92
|
+
.classed('gridviz-legend-triangle', true)
|
|
91
93
|
.attr(
|
|
92
94
|
'transform',
|
|
93
95
|
'translate(' +
|
|
@@ -108,7 +110,7 @@ export class TernaryLegend extends Legend {
|
|
|
108
110
|
.style('cursor', this.interactive ? 'pointer' : null)
|
|
109
111
|
.on('mouseover', function (e) {
|
|
110
112
|
/*this.parentNode.appendChild(this); select(this).attr("stroke-width", selectionStrokeWidth);*/
|
|
111
|
-
select(this).attr('fill', selectionColor)
|
|
113
|
+
select(this).classed('gridviz-legend-swatch--active', true).attr('fill', selectionColor)
|
|
112
114
|
// show only the cells of this class on the map
|
|
113
115
|
legend.highlight([color])
|
|
114
116
|
if (!tt || !text) return
|
|
@@ -118,7 +120,7 @@ export class TernaryLegend extends Legend {
|
|
|
118
120
|
})
|
|
119
121
|
.on('mouseout', function () {
|
|
120
122
|
/*select(this).attr("stroke-width", 0);*/
|
|
121
|
-
select(this).attr('fill', color)
|
|
123
|
+
select(this).classed('gridviz-legend-swatch--active', false).attr('fill', color)
|
|
122
124
|
legend.highlight(null)
|
|
123
125
|
if (tt) tt.hide()
|
|
124
126
|
})
|
package/src/utils/scale.js
CHANGED
|
@@ -16,10 +16,33 @@ import { scaleQuantile } from 'd3-scale'
|
|
|
16
16
|
* @module utils
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The inverse of a stretching function, within [0,1]: its own invert function if it has one,
|
|
21
|
+
* else found by bisection (a stretching is increasing).
|
|
22
|
+
* @param {function(number):number} stretching
|
|
23
|
+
* @param {number} t
|
|
24
|
+
* @returns {number}
|
|
25
|
+
*/
|
|
26
|
+
const invertStretching = (stretching, t) => {
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
if (stretching.invert) return stretching.invert(t)
|
|
29
|
+
let lo = 0,
|
|
30
|
+
hi = 1
|
|
31
|
+
for (let i = 0; i < 50; i++) {
|
|
32
|
+
const mid = (lo + hi) / 2
|
|
33
|
+
if (stretching(mid) < t) lo = mid
|
|
34
|
+
else hi = mid
|
|
35
|
+
}
|
|
36
|
+
return (lo + hi) / 2
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
/**
|
|
20
40
|
* Generic function for view scale - continuous or discrete
|
|
21
41
|
*
|
|
22
42
|
* @param {{ valueFunction:function(import("../core/Dataset").Cell):number, minValue?:number, minSizePix?:number, maxSizeFactor?:number, range?:[number, number], domain?:[number, number], stretching?:function(number):number, classNumber?:number}} opts
|
|
43
|
+
* The scale has an invert(t) function, like the one of viewScaleColor: it returns the value of the domain
|
|
44
|
+
* for a t within [0,1] (what a legend needs to write its labels).
|
|
45
|
+
*
|
|
23
46
|
* @returns {function(Array.<import("../core/Dataset").Cell>):Scale}
|
|
24
47
|
*/
|
|
25
48
|
export const viewScale = (opts) => {
|
|
@@ -38,7 +61,7 @@ export const viewScale = (opts) => {
|
|
|
38
61
|
domainMin = domain[0]
|
|
39
62
|
const rangeSize = range[1] - range[0],
|
|
40
63
|
rangeMin = range[0]
|
|
41
|
-
|
|
64
|
+
const scale = (t) => {
|
|
42
65
|
//scale to [0,1]
|
|
43
66
|
t = (t - domainMin) / domainSize
|
|
44
67
|
//stretch
|
|
@@ -48,6 +71,12 @@ export const viewScale = (opts) => {
|
|
|
48
71
|
//scale to range
|
|
49
72
|
return rangeMin + t * rangeSize
|
|
50
73
|
}
|
|
74
|
+
//the domain value for a position t within [0,1], as the invert of viewScaleColor
|
|
75
|
+
scale.invert = (t) => {
|
|
76
|
+
if (stretching) t = invertStretching(stretching, t)
|
|
77
|
+
return domainMin + t * domainSize
|
|
78
|
+
}
|
|
79
|
+
return scale
|
|
51
80
|
}
|
|
52
81
|
}
|
|
53
82
|
|