diff --git a/src/marks/brush.js b/src/marks/brush.js index 057766a666..040a2b0241 100644 --- a/src/marks/brush.js +++ b/src/marks/brush.js @@ -24,6 +24,8 @@ export class Brush extends Mark { options, defaults ); + this.faceted = []; + this.clears = []; } render(index, scales, {x: X, y: Y}, dimensions) { const {marginLeft, width, marginRight, marginTop, height, marginBottom} = dimensions; @@ -31,27 +33,36 @@ export class Brush extends Mark { const top = marginTop; const right = width - marginRight; const bottom = height - marginBottom; - return create("svg:g") - .call((X && Y ? brusher : X ? brusherX : brusherY)() - .extent([[left, top], [right, bottom]]) - .on("start brush end", function(event) { - const {selection} = event; - let S = index; - if (selection) { - if (X) { - const [x0, x1] = Y ? [selection[0][0], selection[1][0]] : selection; - S = S.filter(i => x0 <= X[i] && X[i] <= x1); - } - if (Y) { - const [y0, y1] = X ? [selection[0][1], selection[1][1]] : selection; - S = S.filter(i => y0 <= Y[i] && Y[i] <= y1); - } - } - this.selection = S; - this.dispatchEvent(new Event("input", {bubbles: true})); - })) - .property("selection", index) - .node(); + const {faceted, clears} = this; + const f = faceted.push(index) - 1; + const brush = (X && Y ? brusher : X ? brusherX : brusherY)() + .extent([[left, top], [right, bottom]]) + .on("start brush end", function({selection, sourceEvent, type}) { + if (!sourceEvent) return; // cleared by a brush in a sister facet + let S = index; + if (selection) { + if (X) { + const [x0, x1] = Y ? [selection[0][0], selection[1][0]] : selection; + S = S.filter(i => x0 <= X[i] && X[i] <= x1); + } + if (Y) { + const [y0, y1] = X ? [selection[0][1], selection[1][1]] : selection; + S = S.filter(i => y0 <= Y[i] && Y[i] <= y1); + } + this.selection = S; + } else { + this.selection = faceted.flat(); + } + if (type === "start") { + for (let i = 0; i < clears.length; i++) if (i !== f) clears[i](); + } + this.dispatchEvent(new Event("input", {bubbles: true})); + }); + const g = create("svg:g") + .call(brush) + .property("selection", index); + clears.push(() => g.call(brush.clear)); + return g.node(); } } diff --git a/src/plot.js b/src/plot.js index fe9e557bc4..0248eaf768 100644 --- a/src/plot.js +++ b/src/plot.js @@ -104,7 +104,7 @@ export function plot(options = {}) { // TODO Will the name “selection” lead to a false positive on random SVG elements? if (node.selection !== undefined) { value = take(mark.data, node.selection); - node.addEventListener("input", () => figure.value = take(mark.data, node.selection)); + node.addEventListener("input", event => figure.value = take(mark.data, event.target.selection)); } svg.appendChild(node); } @@ -280,7 +280,8 @@ class Facet extends Mark { const fxMargins = fx && {marginRight: 0, marginLeft: 0, width: fx.bandwidth()}; const subdimensions = {...dimensions, ...fxMargins, ...fyMargins}; const marksValues = marksChannels.map(channels => applyScales(channels, scales)); - return create("svg:g") + let selection = []; + const node = create("svg:g") .call(g => { if (fy && axes.y) { const axis1 = axes.y, axis2 = nolabel(axis1); @@ -324,10 +325,13 @@ class Facet extends Mark { const values = marksValues[i]; const index = filter(marksFacetIndex[i], marksChannels[i], values); const node = marks[i].render(index, scales, values, subdimensions); + if (node.selection !== undefined) selection = new Set([...selection, ...node.selection]); if (node != null) this.appendChild(node); } })) .node(); + if (selection) node.selection = selection; + return node; } }