Skip to content

Commit

Permalink
maybeSymbolChannel
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Jan 5, 2022
1 parent 91a30c3 commit ea08e4d
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 42 deletions.
10 changes: 5 additions & 5 deletions src/mark.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,16 @@ const colors = new Set(["currentColor", "none"]);
// tuple [channel, constant] where one of the two is undefined, and the other is
// the given value. If you wish to reference a named field that is also a valid
// CSS color, use an accessor (d => d.red) instead.
export function maybeColor(value, defaultValue) {
export function maybeColorChannel(value, defaultValue) {
if (value === undefined) value = defaultValue;
return value === null ? [undefined, "none"]
: typeof value === "string" && (colors.has(value) || color(value)) ? [undefined, value]
: [value, undefined];
}

// Similar to maybeColor, this tests whether the given value is a number
// Similar to maybeColorChannel, this tests whether the given value is a number
// indicating a constant, and otherwise assumes that it’s a channel value.
export function maybeNumber(value, defaultValue) {
export function maybeNumberChannel(value, defaultValue) {
if (value === undefined) value = defaultValue;
return value === null || typeof value === "number" ? [undefined, value]
: [value, undefined];
Expand Down Expand Up @@ -204,8 +204,8 @@ export function maybeTuple(x, y) {
// A helper for extracting the z channel, if it is variable. Used by transforms
// that require series, such as moving average and normalize.
export function maybeZ({z, fill, stroke} = {}) {
if (z === undefined) ([z] = maybeColor(fill));
if (z === undefined) ([z] = maybeColor(stroke));
if (z === undefined) ([z] = maybeColorChannel(fill));
if (z === undefined) ([z] = maybeColorChannel(stroke));
return z;
}

Expand Down
6 changes: 3 additions & 3 deletions src/marks/cell.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {identity, indexOf, maybeColor, maybeTuple} from "../mark.js";
import {identity, indexOf, maybeColorChannel, maybeTuple} from "../mark.js";
import {AbstractBar} from "./bar.js";

export class Cell extends AbstractBar {
Expand Down Expand Up @@ -26,11 +26,11 @@ export function cell(data, {x, y, ...options} = {}) {
}

export function cellX(data, {x = indexOf, fill, stroke, ...options} = {}) {
if (fill === undefined && maybeColor(stroke)[0] === undefined) fill = identity;
if (fill === undefined && maybeColorChannel(stroke)[0] === undefined) fill = identity;
return new Cell(data, {...options, x, fill, stroke});
}

export function cellY(data, {y = indexOf, fill, stroke, ...options} = {}) {
if (fill === undefined && maybeColor(stroke)[0] === undefined) fill = identity;
if (fill === undefined && maybeColorChannel(stroke)[0] === undefined) fill = identity;
return new Cell(data, {...options, y, fill, stroke});
}
10 changes: 5 additions & 5 deletions src/marks/dot.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {create, path, symbolCircle} from "d3";
import {filter, positive} from "../defined.js";
import {Mark, identity, maybeNumber, maybeTuple} from "../mark.js";
import {maybeSymbol} from "../scales/symbol.js";
import {Mark, identity, maybeNumberChannel, maybeTuple} from "../mark.js";
import {maybeSymbolChannel} from "../scales/symbol.js";
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";

const defaults = {
Expand All @@ -13,9 +13,9 @@ const defaults = {
export class Dot extends Mark {
constructor(data, options = {}) {
const {x, y, r, rotate, symbol} = options;
const [vr, cr] = maybeNumber(r, 3);
const [vrotate, crotate] = maybeNumber(rotate, 0);
const [vsymbol, csymbol] = maybeSymbol(symbol);
const [vr, cr] = maybeNumberChannel(r, 3);
const [vrotate, crotate] = maybeNumberChannel(rotate, 0);
const [vsymbol, csymbol] = maybeSymbolChannel(symbol);
super(
data,
[
Expand Down
10 changes: 5 additions & 5 deletions src/marks/image.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {create} from "d3";
import {filter, positive} from "../defined.js";
import {Mark, maybeNumber, maybeTuple, string} from "../mark.js";
import {Mark, maybeNumberChannel, maybeTuple, string} from "../mark.js";
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset, impliedString} from "../style.js";

const defaults = {
Expand All @@ -24,7 +24,7 @@ function isUrl(string) {

// Disambiguates a constant src definition from a channel. A path or URL string
// is assumed to be a constant; any other string is assumed to be a field name.
function maybePath(value) {
function maybePathChannel(value) {
return typeof value === "string" && (isPath(value) || isUrl(value))
? [undefined, value]
: [value, undefined];
Expand All @@ -35,9 +35,9 @@ export class Image extends Mark {
let {x, y, width, height, src, preserveAspectRatio, crossOrigin} = options;
if (width === undefined && height !== undefined) width = height;
else if (height === undefined && width !== undefined) height = width;
const [vs, cs] = maybePath(src);
const [vw, cw] = maybeNumber(width, 16);
const [vh, ch] = maybeNumber(height, 16);
const [vs, cs] = maybePathChannel(src);
const [vw, cw] = maybeNumberChannel(width, 16);
const [vh, ch] = maybeNumberChannel(height, 16);
super(
data,
[
Expand Down
6 changes: 3 additions & 3 deletions src/marks/text.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {create} from "d3";
import {filter, nonempty} from "../defined.js";
import {Mark, indexOf, identity, string, maybeNumber, maybeTuple, numberChannel} from "../mark.js";
import {Mark, indexOf, identity, string, maybeNumberChannel, maybeTuple, numberChannel} from "../mark.js";
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyAttr, applyTransform, offset} from "../style.js";

const defaults = {
Expand All @@ -23,8 +23,8 @@ export class Text extends Mark {
dy = "0.32em",
rotate
} = options;
const [vrotate, crotate] = maybeNumber(rotate, 0);
const [vfontSize, cfontSize] = maybeNumber(fontSize);
const [vrotate, crotate] = maybeNumberChannel(rotate, 0);
const [vfontSize, cfontSize] = maybeNumberChannel(fontSize);
super(
data,
[
Expand Down
6 changes: 3 additions & 3 deletions src/marks/vector.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {create} from "d3";
import {filter} from "../defined.js";
import {Mark, identity, maybeNumber, maybeTuple, keyword} from "../mark.js";
import {Mark, identity, maybeNumberChannel, maybeTuple, keyword} from "../mark.js";
import {radians} from "../math.js";
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";

Expand All @@ -14,8 +14,8 @@ const defaults = {
export class Vector extends Mark {
constructor(data, options = {}) {
const {x, y, length, rotate, anchor = "middle"} = options;
const [vl, cl] = maybeNumber(length, 12);
const [vr, cr] = maybeNumber(rotate, 0);
const [vl, cl] = maybeNumberChannel(length, 12);
const [vr, cr] = maybeNumberChannel(rotate, 0);
super(
data,
[
Expand Down
7 changes: 5 additions & 2 deletions src/scales/ordinal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {scaleBand, scaleOrdinal, scalePoint, scaleImplicit} from "d3";
import {ordinalScheme, quantitativeScheme} from "./schemes.js";
import {ascendingDefined} from "../defined.js";
import {registry, color, symbol} from "./index.js";
import {maybeSymbol} from "./symbol.js";

export function ScaleO(scale, channels, {
type,
Expand All @@ -23,12 +24,14 @@ export function ScaleO(scale, channels, {

export function ScaleOrdinal(key, channels, {
type,
range = registry.get(key) === symbol ? symbols : undefined, // TODO map symbol names to implementations
range,
scheme = range === undefined ? type === "ordinal" ? "turbo" : "tableau10" : undefined,
unknown,
...options
}) {
if (registry.get(key) === color && scheme !== undefined) {
if (registry.get(key) === symbol) {
range = range === undefined ? symbols : Array.from(range, maybeSymbol);
} else if (registry.get(key) === color && scheme !== undefined) {
if (range !== undefined) {
const interpolate = quantitativeScheme(scheme);
const t0 = range[0], d = range[1] - range[0];
Expand Down
12 changes: 9 additions & 3 deletions src/scales/symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ function isSymbol(symbol) {
return symbol && typeof symbol.draw === "function";
}

export function maybeSymbol(symbol = symbolCircle) {
if (symbol == null) return [undefined, null];
if (isSymbol(symbol)) return [undefined, symbol];
export function maybeSymbol(symbol) {
if (symbol == null || isSymbol(symbol)) return symbol;
const value = symbols.get(`${symbol}`.toLowerCase());
if (value) return value;
throw new Error(`invalid symbol: ${symbol}`);
}

export function maybeSymbolChannel(symbol = symbolCircle) {
if (symbol == null || isSymbol(symbol)) return [undefined, symbol];
if (typeof symbol === "string") {
const value = symbols.get(`${symbol}`.toLowerCase());
if (value) return [undefined, value];
Expand Down
14 changes: 7 additions & 7 deletions src/style.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {namespaces} from "d3";
import {string, number, maybeColor, maybeNumber, title, titleGroup} from "./mark.js";
import {string, number, maybeColorChannel, maybeNumberChannel, title, titleGroup} from "./mark.js";
import {filter} from "./defined.js";

export const offset = typeof window !== "undefined" && window.devicePixelRatio > 1 ? 0 : 0.5;
Expand Down Expand Up @@ -58,11 +58,11 @@ export function styles(
if (none(defaultStroke) && !none(stroke)) defaultFill = "none";
}

const [vfill, cfill] = maybeColor(fill, defaultFill);
const [vfillOpacity, cfillOpacity] = maybeNumber(fillOpacity);
const [vstroke, cstroke] = maybeColor(stroke, defaultStroke);
const [vstrokeOpacity, cstrokeOpacity] = maybeNumber(strokeOpacity);
const [vopacity, copacity] = maybeNumber(opacity);
const [vfill, cfill] = maybeColorChannel(fill, defaultFill);
const [vfillOpacity, cfillOpacity] = maybeNumberChannel(fillOpacity);
const [vstroke, cstroke] = maybeColorChannel(stroke, defaultStroke);
const [vstrokeOpacity, cstrokeOpacity] = maybeNumberChannel(strokeOpacity);
const [vopacity, copacity] = maybeNumberChannel(opacity);

// For styles that have no effect if there is no stroke, only apply the
// defaults if the stroke is not (constant) none.
Expand All @@ -73,7 +73,7 @@ export function styles(
if (strokeMiterlimit === undefined) strokeMiterlimit = defaultStrokeMiterlimit;
}

const [vstrokeWidth, cstrokeWidth] = maybeNumber(strokeWidth);
const [vstrokeWidth, cstrokeWidth] = maybeNumberChannel(strokeWidth);

// Some marks don’t support fill (e.g., tick and rule).
if (defaultFill !== null) {
Expand Down
6 changes: 3 additions & 3 deletions src/transforms/bin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {bin as binner, extent, thresholdFreedmanDiaconis, thresholdScott, thresholdSturges, utcTickInterval} from "d3";
import {valueof, range, identity, maybeLazyChannel, maybeTuple, maybeColor, maybeValue, mid, labelof, isTemporal} from "../mark.js";
import {valueof, range, identity, maybeLazyChannel, maybeTuple, maybeColorChannel, maybeValue, mid, labelof, isTemporal} from "../mark.js";
import {coerceDate} from "../scales.js";
import {basic} from "./basic.js";
import {hasOutput, maybeEvaluator, maybeGroup, maybeOutput, maybeOutputs, maybeReduce, maybeSort, maybeSubgroup, reduceCount, reduceIdentity} from "./group.js";
Expand Down Expand Up @@ -81,8 +81,8 @@ function binn(
...options
} = inputs;
const [GZ, setGZ] = maybeLazyChannel(z);
const [vfill] = maybeColor(fill);
const [vstroke] = maybeColor(stroke);
const [vfill] = maybeColorChannel(fill);
const [vstroke] = maybeColorChannel(stroke);
const [GF = fill, setGF] = maybeLazyChannel(vfill);
const [GS = stroke, setGS] = maybeLazyChannel(vstroke);

Expand Down
6 changes: 3 additions & 3 deletions src/transforms/group.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {group as grouper, sort, sum, deviation, min, max, mean, median, mode, variance, InternSet, minIndex, maxIndex} from "d3";
import {ascendingDefined, firstof} from "../defined.js";
import {valueof, maybeColor, maybeInput, maybeTuple, maybeLazyChannel, lazyChannel, first, identity, take, labelof, range} from "../mark.js";
import {valueof, maybeColorChannel, maybeInput, maybeTuple, maybeLazyChannel, lazyChannel, first, identity, take, labelof, range} from "../mark.js";
import {basic} from "./basic.js";

// Group on {z, fill, stroke}.
Expand Down Expand Up @@ -66,8 +66,8 @@ function groupn(
...options
} = inputs;
const [GZ, setGZ] = maybeLazyChannel(z);
const [vfill] = maybeColor(fill);
const [vstroke] = maybeColor(stroke);
const [vfill] = maybeColorChannel(fill);
const [vstroke] = maybeColorChannel(stroke);
const [GF = fill, setGF] = maybeLazyChannel(vfill);
const [GS = stroke, setGS] = maybeLazyChannel(vstroke);

Expand Down

0 comments on commit ea08e4d

Please sign in to comment.