Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scale.high/low #258

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -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.

<a name="continuous_low" href="#continuous_low">#</a> <i>continuous</i>.<b>low</b>([<i>value</i>]) · [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.

<a name="continuous_high" href="#continuous_high">#</a> <i>continuous</i>.<b>high</b>([<i>value</i>]) · [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.

<a name="continuous_unknown" href="#continuous_unknown">#</a> <i>continuous</i>.<b>unknown</b>([<i>value</i>]) · [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.
Expand Down
36 changes: 25 additions & 11 deletions src/continuous.js
Expand Up @@ -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) {
Expand Down Expand Up @@ -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(_) {
Expand All @@ -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(_) {
Expand All @@ -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();
Expand Down