From e14169e84738ef0ffaefcc297f3aeb02db4ba8a6 Mon Sep 17 00:00:00 2001 From: Colin Megill Date: Thu, 12 Apr 2018 21:05:17 -0700 Subject: [PATCH] crossfilter --- src/components/continuous/histogramBrush.js | 22 +++++++-- .../updateCellSelectionMiddleware.js | 49 ++++++++++++++++++- src/reducers/controls.js | 13 +++++ 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/src/components/continuous/histogramBrush.js b/src/components/continuous/histogramBrush.js index 3cf78ef8..9be46c5e 100644 --- a/src/components/continuous/histogramBrush.js +++ b/src/components/continuous/histogramBrush.js @@ -42,8 +42,23 @@ class HistogramBrush extends React.Component { componentDidUpdate() { } - onBrush(e) { - console.log('brushed', e) + onBrush(selection, x) { + return () => { + if (d3.event.selection) { + this.props.dispatch({ + type: "continuous metadata histogram brush", + selection: this.props.metadataField, + range: [x(d3.event.selection[0]), x(d3.event.selection[1])] + }); + } else { + this.props.dispatch({ + type: "continuous metadata histogram brush", + selection: this.props.metadataField, + range: null + }); + } + + } } drawHistogram(svgRef) { @@ -77,13 +92,12 @@ class HistogramBrush extends React.Component { .attr("height", function(d) { return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length); }); if (!this.state.brush && !this.state.axis) { - console.log('whee') const brush = d3.select(svgRef) .append('g') .attr('class', 'brush') .call( d3.brushX() - .on('end', this.onBrush) + .on('end', this.onBrush(this.props.metadataField, x.invert).bind(this)) ) const xAxis = d3.select(svgRef) diff --git a/src/middleware/updateCellSelectionMiddleware.js b/src/middleware/updateCellSelectionMiddleware.js index 45b50c40..da40c092 100644 --- a/src/middleware/updateCellSelectionMiddleware.js +++ b/src/middleware/updateCellSelectionMiddleware.js @@ -26,6 +26,7 @@ const updateCellSelectionMiddleware = (store) => { /* this is a hardcoded map of the things we need to keep an eye on and update global cell selection in response to */ const filterJustChanged = action.type === "continuous selection using parallel coords brushing" || + action.type === "continuous metadata histogram brush" || action.type === "graph brush selection change" || action.type === "graph brush deselect" || action.type === "categorical metadata filter deselect" || @@ -114,6 +115,49 @@ const updateCellSelectionMiddleware = (store) => { }) } + /* + Continuous histograms ___---^^^^--[------__]__---___ + + Create newContinuousUserDefinedRanges + Filter based on them + */ + + let newContinuousUserDefinedRanges = s.controls.continuousUserDefinedRanges; + + + /* check if this is the action and take care of that metadata field */ + if (action.type === "continuous metadata histogram brush") { + /* + was this a deselect? if so it will be null + was it a select? set the new range [20, 50] + we overload this because it is less if statements thru the whole system + but it's invisible here, thus comment. + */ + newContinuousUserDefinedRanges[action.selection] = action.range; + } + + let activeContinuousHistogramFilters = []; + + _.each(newContinuousUserDefinedRanges, (value, key, i) => { + if (value !== null) { + activeContinuousHistogramFilters.push(key) + } + }) + + /* see if there are others from previous... */ + if (activeContinuousHistogramFilters.length > 0) { + _.each(activeContinuousHistogramFilters, (key) => { + _.each(newSelection, (cell, i) => { + if ( + +cell[key] < newContinuousUserDefinedRanges[key][0] || + +cell[key] > newContinuousUserDefinedRanges[key][1] + ) { + newSelection[i]["__selected__"] = false; + } + }) + }) + } + /* 1. figure out if the users have unchecked boxes 2. put them in an array @@ -183,18 +227,19 @@ const updateCellSelectionMiddleware = (store) => { if (inactiveCategories.length > 0) { _.each(inactiveCategories, (d) => { _.each(newSelection, (cell, i) => { - if (""+cell[d.category] === ""+d.option) { /* nums and strings to strings */ + if (""+cell[d.category] === ""+d.option) { /* nums and strings to strings -__- */ newSelection[i]["__selected__"] = false; } }) }) } - + let modifiedAction = Object.assign({}, action, { newSelection, newCategoricalAsBooleansMap, + newContinuousUserDefinedRanges, }) /* append the result of all the filters to the action the user just triggered */ return next(modifiedAction); diff --git a/src/reducers/controls.js b/src/reducers/controls.js index e318edf5..7384df58 100644 --- a/src/reducers/controls.js +++ b/src/reducers/controls.js @@ -42,6 +42,7 @@ const Controls = (state = { we mutate this map in the actions below */ const categoricalAsBooleansMap = {}; + const continuousUserDefinedRanges = {}; _.each(action.data.data.ranges, (value, key) => { if ( key !== "CellName" && @@ -52,13 +53,20 @@ const Controls = (state = { optionsAsBooleans[_key] = true; }) categoricalAsBooleansMap[key] = optionsAsBooleans; + } else if ( + key !== "CellName" && + value.range + ) { + continuousUserDefinedRanges[key] = null; } }) + return Object.assign({}, state, { allCellsOnClient: action.data.data, currentCellSelection, graphMap, categoricalAsBooleansMap, + continuousUserDefinedRanges, graphBrushSelection: null, /* if we are getting new cells from the server, the layout (probably? definitely?) just changed, so this is now irrelevant, and we WILL need to call a function to reset state of this kind when cells success happens */ }); /* * * * * * * * * * * * * * * * * * @@ -84,6 +92,11 @@ const Controls = (state = { graphBrushSelection: null, currentCellSelection: action.newSelection /* this comes from middleware */ }) + case "continuous metadata histogram brush": + return Object.assign({}, state, { + newContinuousUserDefinedRanges: action.newContinuousUserDefinedRanges, /* this has already been applied in middleware but store it for next time */ + currentCellSelection: action.newSelection /* this comes from middleware */ + }) case "change opacity deselected cells in 2d graph background": return Object.assign({}, state, { opacityForDeselectedCells: action.data,