Skip to content

Commit e0fb5a1

Browse files
committed
universal channel filter
1 parent 4db8fe9 commit e0fb5a1

File tree

19 files changed

+51
-81
lines changed

19 files changed

+51
-81
lines changed

src/defined.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ export function nonempty(x) {
1616
return x != null && `${x}` !== "";
1717
}
1818

19-
export function filter(index, ...channels) {
20-
for (const c of channels) {
21-
if (c) index = index.filter(i => defined(c[i]));
22-
}
23-
return index;
24-
}
25-
2619
export function finite(x) {
2720
return isFinite(x) ? x : NaN;
2821
}

src/facet.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {cross, difference, groups, InternMap} from "d3";
22
import {create} from "d3";
33
import {Mark, first, second, markify, where} from "./mark.js";
4+
import {filter} from "./plot.js";
45
import {applyScales} from "./scales.js";
5-
import {filterStyles} from "./style.js";
66

77
export function facets(data, {x, y, ...options}, marks) {
88
return x === undefined && y === undefined
@@ -119,13 +119,8 @@ class Facet extends Mark {
119119
const marksFacetIndex = marksIndexByFacet.get(key);
120120
for (let i = 0; i < marks.length; ++i) {
121121
const values = marksValues[i];
122-
const index = filterStyles(marksFacetIndex[i], values);
123-
const node = marks[i].render(
124-
index,
125-
scales,
126-
values,
127-
subdimensions
128-
);
122+
const index = filter(marksFacetIndex[i], marksChannels[i], values);
123+
const node = marks[i].render(index, scales, values, subdimensions);
129124
if (node != null) this.appendChild(node);
130125
}
131126
}))

src/mark.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ export class Mark {
5858
}
5959

6060
// TODO Type coercion?
61-
function Channel(data, {scale, type, value, hint}) {
61+
function Channel(data, {scale, type, value, filter, hint}) {
6262
return {
6363
scale,
6464
type,
6565
value: valueof(data, value),
6666
label: labelof(value),
67+
filter,
6768
hint
6869
};
6970
}
@@ -279,8 +280,11 @@ export function maybeValue(value) {
279280
return value === undefined || isOptions(value) ? value : {value};
280281
}
281282

283+
// Coerces the given channel values (if any) to numbers. This is useful when
284+
// values will be interpolated into other code, such as an SVG transform, and
285+
// where we don’t wish to allow unexpected behavior for weird input.
282286
export function numberChannel(source) {
283-
return {
287+
return source == null ? null : {
284288
transform: data => valueof(data, source, Float64Array),
285289
label: labelof(source)
286290
};

src/marks/area.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ export class Area extends Mark {
1717
super(
1818
data,
1919
[
20-
{name: "x1", value: x1, scale: "x"},
21-
{name: "y1", value: y1, scale: "y"},
22-
{name: "x2", value: x2, scale: "x", optional: true},
23-
{name: "y2", value: y2, scale: "y", optional: true},
20+
{name: "x1", value: x1, filter: null, scale: "x"},
21+
{name: "y1", value: y1, filter: null, scale: "y"},
22+
{name: "x2", value: x2, filter: null, scale: "x", optional: true},
23+
{name: "y2", value: y2, filter: null, scale: "y", optional: true},
2424
{name: "z", value: maybeZ(options), optional: true}
2525
],
2626
options,

src/marks/bar.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {create} from "d3";
2-
import {filter} from "../defined.js";
32
import {Mark, number} from "../mark.js";
43
import {isCollapsed} from "../scales.js";
54
import {applyDirectStyles, applyIndirectStyles, applyTransform, impliedString, applyAttr, applyChannelStyles} from "../style.js";
@@ -20,9 +19,8 @@ export class AbstractBar extends Mark {
2019
this.rx = impliedString(rx, "auto"); // number or percentage
2120
this.ry = impliedString(ry, "auto");
2221
}
23-
render(I, scales, channels, dimensions) {
22+
render(index, scales, channels, dimensions) {
2423
const {dx, dy, rx, ry} = this;
25-
const index = filter(I, ...this._positions(channels));
2624
return create("svg:g")
2725
.call(applyIndirectStyles, this)
2826
.call(this._transform, scales, dx, dy)
@@ -75,9 +73,6 @@ export class BarX extends AbstractBar {
7573
_transform(selection, {x}, dx, dy) {
7674
selection.call(applyTransform, x, null, dx, dy);
7775
}
78-
_positions({x1: X1, x2: X2, y: Y}) {
79-
return [X1, X2, Y];
80-
}
8176
_x({x}, {x1: X1, x2: X2}, {marginLeft}) {
8277
const {insetLeft} = this;
8378
return isCollapsed(x) ? marginLeft + insetLeft : i => Math.min(X1[i], X2[i]) + insetLeft;
@@ -104,9 +99,6 @@ export class BarY extends AbstractBar {
10499
_transform(selection, {y}, dx, dy) {
105100
selection.call(applyTransform, null, y, dx, dy);
106101
}
107-
_positions({y1: Y1, y2: Y2, x: X}) {
108-
return [Y1, Y2, X];
109-
}
110102
_y({y}, {y1: Y1, y2: Y2}, {marginTop}) {
111103
const {insetTop} = this;
112104
return isCollapsed(y) ? marginTop + insetTop : i => Math.min(Y1[i], Y2[i]) + insetTop;

src/marks/cell.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ export class Cell extends AbstractBar {
1515
_transform() {
1616
// noop
1717
}
18-
_positions({x: X, y: Y}) {
19-
return [X, Y];
20-
}
2118
}
2219

2320
export function cell(data, {x, y, ...options} = {}) {

src/marks/dot.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {create, path, symbolCircle} from "d3";
2-
import {filter, positive} from "../defined.js";
2+
import {positive} from "../defined.js";
33
import {Mark, identity, maybeNumberChannel, maybeTuple} from "../mark.js";
44
import {maybeSymbolChannel} from "../scales/symbol.js";
55
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";
@@ -21,7 +21,7 @@ export class Dot extends Mark {
2121
[
2222
{name: "x", value: x, scale: "x", optional: true},
2323
{name: "y", value: y, scale: "y", optional: true},
24-
{name: "r", value: vr, scale: "r", optional: true},
24+
{name: "r", value: vr, scale: "r", filter: positive, optional: true},
2525
{name: "rotate", value: vrotate, optional: true},
2626
{name: "symbol", value: vsymbol, scale: "symbol", optional: true}
2727
],
@@ -47,7 +47,7 @@ export class Dot extends Mark {
4747
}
4848
}
4949
render(
50-
I,
50+
index,
5151
{x, y},
5252
channels,
5353
{width, height, marginTop, marginRight, marginBottom, marginLeft}
@@ -56,8 +56,6 @@ export class Dot extends Mark {
5656
const {dx, dy} = this;
5757
const cx = (marginLeft + width - marginRight) / 2;
5858
const cy = (marginTop + height - marginBottom) / 2;
59-
let index = filter(I, X, Y, A, S);
60-
if (R) index = index.filter(i => positive(R[i]));
6159
const circle = this.symbol === symbolCircle;
6260
return create("svg:g")
6361
.call(applyIndirectStyles, this)

src/marks/image.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {create} from "d3";
2-
import {filter, positive} from "../defined.js";
2+
import {positive} from "../defined.js";
33
import {Mark, maybeNumberChannel, maybeTuple, string} from "../mark.js";
44
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset, impliedString} from "../style.js";
55

@@ -43,8 +43,8 @@ export class Image extends Mark {
4343
[
4444
{name: "x", value: x, scale: "x", optional: true},
4545
{name: "y", value: y, scale: "y", optional: true},
46-
{name: "width", value: vw, optional: true},
47-
{name: "height", value: vh, optional: true},
46+
{name: "width", value: vw, filter: positive, optional: true},
47+
{name: "height", value: vh, filter: positive, optional: true},
4848
{name: "src", value: vs, optional: true}
4949
],
5050
options,
@@ -57,15 +57,12 @@ export class Image extends Mark {
5757
this.crossOrigin = string(crossOrigin);
5858
}
5959
render(
60-
I,
60+
index,
6161
{x, y},
6262
channels,
6363
{width, height, marginTop, marginRight, marginBottom, marginLeft}
6464
) {
6565
const {x: X, y: Y, width: W, height: H, src: S} = channels;
66-
let index = filter(I, X, Y, S);
67-
if (W) index = index.filter(i => positive(W[i]));
68-
if (H) index = index.filter(i => positive(H[i]));
6966
const cx = (marginLeft + width - marginRight) / 2;
7067
const cy = (marginTop + height - marginBottom) / 2;
7168
const {dx, dy} = this;

src/marks/line.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export class Line extends Mark {
1717
super(
1818
data,
1919
[
20-
{name: "x", value: x, scale: "x"},
21-
{name: "y", value: y, scale: "y"},
20+
{name: "x", value: x, filter: null, scale: "x"},
21+
{name: "y", value: y, filter: null, scale: "y"},
2222
{name: "z", value: maybeZ(options), optional: true}
2323
],
2424
options,

src/marks/link.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {create, path} from "d3";
2-
import {filter} from "../defined.js";
32
import {Mark} from "../mark.js";
43
import {Curve} from "../curve.js";
54
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";
@@ -26,10 +25,9 @@ export class Link extends Mark {
2625
);
2726
this.curve = Curve(curve);
2827
}
29-
render(I, {x, y}, channels) {
28+
render(index, {x, y}, channels) {
3029
const {x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1} = channels;
3130
const {dx, dy} = this;
32-
const index = filter(I, X1, Y1, X2, Y2);
3331
return create("svg:g")
3432
.call(applyIndirectStyles, this)
3533
.call(applyTransform, x, y, offset + dx, offset + dy)

0 commit comments

Comments
 (0)