diff --git a/d3.parcoords.js b/d3.parcoords.js index 8fe8659..347d036 100644 --- a/d3.parcoords.js +++ b/d3.parcoords.js @@ -159,7 +159,7 @@ function getset(obj,state,events) { }; function extend(target, source) { - for (key in source) { + for (var key in source) { target[key] = source[key]; } return target; @@ -457,7 +457,8 @@ pc.renderBrushed.queue = function() { } else { brushedQueue([]); // This is needed to clear the currently brushed items } -};function compute_cluster_centroids(d) { +}; +function compute_cluster_centroids(d) { var clusterCentroids = d3.map(); var clusterCounts = d3.map(); @@ -1042,28 +1043,28 @@ pc.brushMode = function(mode) { // brush mode: 1D-Axes (function() { - var brushes = {}; + var brushes = {}; - function is_brushed(p) { - return !brushes[p].empty(); - } + function is_brushed(p) { + return !brushes[p].empty(); + } // data within extents function selected() { var actives = d3.keys(__.dimensions).filter(is_brushed), extents = actives.map(function(p) { return brushes[p].extent(); }); - // We don't want to return the full data set when there are no axes brushed. - // Actually, when there are no axes brushed, by definition, no items are - // selected. So, let's avoid the filtering and just return false. - //if (actives.length === 0) return false; + // We don't want to return the full data set when there are no axes brushed. + // Actually, when there are no axes brushed, by definition, no items are + // selected. So, let's avoid the filtering and just return false. + //if (actives.length === 0) return false; - // Resolves broken examples for now. They expect to get the full dataset back from empty brushes - if (actives.length === 0) return __.data; + // Resolves broken examples for now. They expect to get the full dataset back from empty brushes + if (actives.length === 0) return __.data; - // test if within range - var within = { - "date": function(d,p,dimension) { + // test if within range + var within = { + "date": function(d,p,dimension) { if (typeof __.dimensions[p].yscale.rangePoints === "function") { // if it is ordinal return extents[dimension][0] <= __.dimensions[p].yscale(d[p]) && __.dimensions[p].yscale(d[p]) <= extents[dimension][1] } else { @@ -1135,7 +1136,10 @@ pc.brushMode = function(mode) { brush.extent(extents[d]); //redraw the brush - brush(brushSelections[d]); + brushSelections[d] + .transition() + .duration(0) + .call(brush); //fire some events brush.event(brushSelections[d]); @@ -1144,6 +1148,8 @@ pc.brushMode = function(mode) { //redraw the chart pc.renderBrushed(); + + return pc; } } @@ -1157,60 +1163,78 @@ pc.brushMode = function(mode) { d3.event.sourceEvent.stopPropagation(); } }) - .on("brush", function() { - brushUpdated(selected()); - }) - .on("brushend", function() { - events.brushend.call(pc, __.brushed); - }); - - brushes[axis] = brush; - return brush; - }; - function brushReset(dimension) { - __.brushed = false; - if (g) { - g.selectAll('.brush') - .each(function(d) { - d3.select(this).call( - brushes[d].clear() - ); - }); - pc.renderBrushed(); - } - return this; - }; - - function install() { - if (!g) pc.createAxes(); + .on("brush", function() { + brushUpdated(selected()); + }) + .on("brushend", function() { + events.brushend.call(pc, __.brushed); + }); - // Add and store a brush for each axis. - g.append("svg:g") - .attr("class", "brush") - .each(function(d) { - d3.select(this).call(brushFor(d)); - }) - .selectAll("rect") - .style("visibility", null) - .attr("x", -15) - .attr("width", 30); + brushes[axis] = brush; + return brush; + }; + + function brushReset(dimension) { + if (dimension===undefined) { + __.brushed = false; + if (g) { + g.selectAll('.brush') + .each(function(d) { + d3.select(this) + .transition() + .duration(0) + .call(brushes[d].clear()); + }); + pc.renderBrushed(); + } + } + else { + if (g) { + g.selectAll('.brush') + .each(function(d) { + if (d!=dimension) return; + d3.select(this) + .transition() + .duration(0) + .call(brushes[d].clear()); + brushes[d].event(d3.select(this)); + }); + pc.renderBrushed(); + } + } + return this; + }; - pc.brushExtents = brushExtents; - pc.brushReset = brushReset; - return pc; - }; + function install() { + if (!g) pc.createAxes(); - brush.modes["1D-axes"] = { - install: install, - uninstall: function() { - g.selectAll(".brush").remove(); - brushes = {}; - delete pc.brushExtents; - delete pc.brushReset; - }, - selected: selected, - brushState: brushExtents - } + // Add and store a brush for each axis. + g.append("svg:g") + .attr("class", "brush") + .each(function(d) { + d3.select(this).call(brushFor(d)); + }) + .selectAll("rect") + .style("visibility", null) + .attr("x", -15) + .attr("width", 30); + + pc.brushExtents = brushExtents; + pc.brushReset = brushReset; + return pc; + }; + + brush.modes["1D-axes"] = { + install: install, + uninstall: function() { + g.selectAll(".brush").remove(); + brushes = {}; + delete pc.brushExtents; + delete pc.brushReset; + }, + selected: selected, + brushState: brushExtents + } })(); // brush mode: 2D-strums // bl.ocks.org/syntagmatic/5441022 diff --git a/examples/setterForBrushes.html b/examples/setterForBrushes.html index 0169ad1..7cb040a 100644 --- a/examples/setterForBrushes.html +++ b/examples/setterForBrushes.html @@ -9,7 +9,7 @@

Demonstrates a parallel coordinates plot a pre-set 1D-axes brush.

diff --git a/src/brushes/1D.js b/src/brushes/1D.js index ce6262a..5a1bafd 100644 --- a/src/brushes/1D.js +++ b/src/brushes/1D.js @@ -1,28 +1,28 @@ // brush mode: 1D-Axes (function() { - var brushes = {}; + var brushes = {}; - function is_brushed(p) { - return !brushes[p].empty(); - } + function is_brushed(p) { + return !brushes[p].empty(); + } // data within extents function selected() { var actives = d3.keys(__.dimensions).filter(is_brushed), extents = actives.map(function(p) { return brushes[p].extent(); }); - // We don't want to return the full data set when there are no axes brushed. - // Actually, when there are no axes brushed, by definition, no items are - // selected. So, let's avoid the filtering and just return false. - //if (actives.length === 0) return false; + // We don't want to return the full data set when there are no axes brushed. + // Actually, when there are no axes brushed, by definition, no items are + // selected. So, let's avoid the filtering and just return false. + //if (actives.length === 0) return false; - // Resolves broken examples for now. They expect to get the full dataset back from empty brushes - if (actives.length === 0) return __.data; + // Resolves broken examples for now. They expect to get the full dataset back from empty brushes + if (actives.length === 0) return __.data; - // test if within range - var within = { - "date": function(d,p,dimension) { + // test if within range + var within = { + "date": function(d,p,dimension) { if (typeof __.dimensions[p].yscale.rangePoints === "function") { // if it is ordinal return extents[dimension][0] <= __.dimensions[p].yscale(d[p]) && __.dimensions[p].yscale(d[p]) <= extents[dimension][1] } else { @@ -94,7 +94,10 @@ brush.extent(extents[d]); //redraw the brush - brush(brushSelections[d]); + brushSelections[d] + .transition() + .duration(0) + .call(brush); //fire some events brush.event(brushSelections[d]); @@ -103,6 +106,8 @@ //redraw the chart pc.renderBrushed(); + + return pc; } } @@ -116,58 +121,76 @@ d3.event.sourceEvent.stopPropagation(); } }) - .on("brush", function() { - brushUpdated(selected()); - }) - .on("brushend", function() { - events.brushend.call(pc, __.brushed); - }); + .on("brush", function() { + brushUpdated(selected()); + }) + .on("brushend", function() { + events.brushend.call(pc, __.brushed); + }); - brushes[axis] = brush; - return brush; - }; - function brushReset(dimension) { - __.brushed = false; - if (g) { - g.selectAll('.brush') - .each(function(d) { - d3.select(this).call( - brushes[d].clear() - ); - }); - pc.renderBrushed(); - } - return this; - }; + brushes[axis] = brush; + return brush; + }; + + function brushReset(dimension) { + if (dimension===undefined) { + __.brushed = false; + if (g) { + g.selectAll('.brush') + .each(function(d) { + d3.select(this) + .transition() + .duration(0) + .call(brushes[d].clear()); + }); + pc.renderBrushed(); + } + } + else { + if (g) { + g.selectAll('.brush') + .each(function(d) { + if (d!=dimension) return; + d3.select(this) + .transition() + .duration(0) + .call(brushes[d].clear()); + brushes[d].event(d3.select(this)); + }); + pc.renderBrushed(); + } + } + return this; + }; - function install() { - if (!g) pc.createAxes(); - - // Add and store a brush for each axis. - g.append("svg:g") - .attr("class", "brush") - .each(function(d) { - d3.select(this).call(brushFor(d)); - }) - .selectAll("rect") - .style("visibility", null) - .attr("x", -15) - .attr("width", 30); - - pc.brushExtents = brushExtents; - pc.brushReset = brushReset; - return pc; - }; + function install() { + if (!g) pc.createAxes(); - brush.modes["1D-axes"] = { - install: install, - uninstall: function() { - g.selectAll(".brush").remove(); - brushes = {}; - delete pc.brushExtents; - delete pc.brushReset; - }, - selected: selected, - brushState: brushExtents - } + // Add and store a brush for each axis. + g.append("svg:g") + .attr("class", "brush") + .each(function(d) { + d3.select(this).call(brushFor(d)); + }) + .selectAll("rect") + .style("visibility", null) + .attr("x", -15) + .attr("width", 30); + + pc.brushExtents = brushExtents; + pc.brushReset = brushReset; + return pc; + }; + + brush.modes["1D-axes"] = { + install: install, + uninstall: function() { + g.selectAll(".brush").remove(); + brushes = {}; + delete pc.brushExtents; + delete pc.brushReset; + }, + selected: selected, + brushState: brushExtents + } })(); diff --git a/src/events.js b/src/events.js index 9558895..08bf533 100644 --- a/src/events.js +++ b/src/events.js @@ -95,7 +95,7 @@ function getset(obj,state,events) { }; function extend(target, source) { - for (key in source) { + for (var key in source) { target[key] = source[key]; } return target; diff --git a/src/render.js b/src/render.js index 839acfe..726bc75 100644 --- a/src/render.js +++ b/src/render.js @@ -76,4 +76,4 @@ pc.renderBrushed.queue = function() { } else { brushedQueue([]); // This is needed to clear the currently brushed items } -}; \ No newline at end of file +};