diff --git a/README.md b/README.md index 9024eaf..ed9aef3 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,14 @@ x.invert(-160); // 10, clamped to domain If *clamp* is not specified, returns whether or not the scale currently clamps values to within the range. +# continuous.low([value]) · [Source](https://github.com/d3/d3-scale/blob/master/src/continuous.js), [Examples](https://observablehq.com/@d3/continuous-scales) + +If *value* is specified, sets the output value for values lower than the lower bound of the domain and returns this scale. If *value* is undefined, interpolation or clamping may happen. If *value* is not specified, returns the current low value, which defaults to undefined. + +# continuous.high([value]) · [Source](https://github.com/d3/d3-scale/blob/master/src/continuous.js), [Examples](https://observablehq.com/@d3/continuous-scales) + +If *value* is specified, sets the output value for values higher than the upper bound of the domain and returns this scale. If *value* is undefined, interpolation or clamping may happen. If *value* is not specified, returns the current high value, which defaults to undefined. + # continuous.unknown([value]) · [Source](https://github.com/d3/d3-scale/blob/master/src/continuous.js), [Examples](https://observablehq.com/@d3/continuous-scales) If *value* is specified, sets the output value of the scale for undefined (or NaN) input values and returns this scale. If *value* is not specified, returns the current unknown value, which defaults to undefined. diff --git a/src/continuous.js b/src/continuous.js index d932095..0149d2e 100644 --- a/src/continuous.js +++ b/src/continuous.js @@ -15,12 +15,6 @@ function normalize(a, b) { : constant(isNaN(b) ? NaN : 0.5); } -function clamper(a, b) { - var t; - if (a > b) t = a, a = b, b = t; - return function(x) { return Math.max(a, Math.min(b, x)); }; -} - // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1]. // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b]. function bimap(domain, range, interpolate) { @@ -69,25 +63,37 @@ export function transformer() { transform, untransform, unknown, - clamp = identity, + low, + high, + min, + max, + clamp, piecewise, output, input; function rescale() { var n = Math.min(domain.length, range.length); - if (clamp !== identity) clamp = clamper(domain[0], domain[n - 1]); + min = domain[0]; + max = domain[n - 1]; + if (max < min) ([min, max] = [max, min]); + if (clamp) clamp = x => x < min ? min : x > max ? max : x; piecewise = n > 2 ? polymap : bimap; output = input = null; return scale; } function scale(x) { - return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x))); + const tr = clamp ? x => transform(clamp(x)) : transform; + return x == null || isNaN(x = +x) ? unknown + : low !== undefined && x < min ? low + : high !== undefined && x > max ? high + : (output || (output = piecewise(domain.map(transform), range, interpolate)))(tr(x)); } scale.invert = function(y) { - return clamp(untransform((input || (input = piecewise(range, domain.map(transform), interpolateNumber)))(y))); + const x = untransform((input || (input = piecewise(range, domain.map(transform), interpolateNumber)))(y)); + return clamp ? clamp(x) : x; }; scale.domain = function(_) { @@ -103,7 +109,7 @@ export function transformer() { }; scale.clamp = function(_) { - return arguments.length ? (clamp = _ ? true : identity, rescale()) : clamp !== identity; + return arguments.length ? (clamp = !!_, rescale()) : !!clamp; }; scale.interpolate = function(_) { @@ -114,6 +120,14 @@ export function transformer() { return arguments.length ? (unknown = _, scale) : unknown; }; + scale.low = function(_) { + return arguments.length ? (low = _, scale) : low; + }; + + scale.high = function(_) { + return arguments.length ? (high = _, scale) : high; + }; + return function(t, u) { transform = t, untransform = u; return rescale();