mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-05 06:58:12 +08:00
filter on categorical with checkboxes
This commit is contained in:
@@ -5,28 +5,31 @@ import actions from "../../actions";
|
|||||||
|
|
||||||
@connect((state) => {
|
@connect((state) => {
|
||||||
return {
|
return {
|
||||||
selectedMetadata: state.selectedMetadata
|
categoricalAsBooleansMap: state.controls.categoricalAsBooleansMap
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
class CategoryValue extends React.Component {
|
class CategoryValue extends React.Component {
|
||||||
|
|
||||||
handleChange() {
|
toggleOff() {
|
||||||
console.log("dispatch", this.props.metadataField, this.props.value)
|
this.props.dispatch({
|
||||||
|
type: "categorical metadata filter deselect",
|
||||||
|
metadataField: this.props.metadataField,
|
||||||
|
value: this.props.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleOn() {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: "categorical metadata filter select",
|
||||||
|
metadataField: this.props.metadataField,
|
||||||
|
value: this.props.value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
if (!this.props.categoricalAsBooleansMap) return null
|
||||||
|
|
||||||
/* has this value for this category already been selected? */
|
const selected = this.props.categoricalAsBooleansMap[this.props.metadataField][this.props.value]
|
||||||
let selected = false;
|
|
||||||
|
|
||||||
if (!this.props.selectedMetadata) { /* there is no selected metadata */
|
|
||||||
selected = false;
|
|
||||||
} else if (
|
|
||||||
this.props.selectedMetadata[this.props.metadataField] && /* the key {Location: []} is present */
|
|
||||||
this.props.selectedMetadata[this.props.metadataField].indexOf(this.props.value) > -1 /* "Tumor" exists in {Location: ["Tumor"]} */
|
|
||||||
) {
|
|
||||||
selected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -41,7 +44,11 @@ class CategoryValue extends React.Component {
|
|||||||
margin: 0,
|
margin: 0,
|
||||||
lineHeight: "1em"
|
lineHeight: "1em"
|
||||||
}}>
|
}}>
|
||||||
<input onChange={this.handleChange.bind(this)} checked={true} type="checkbox"/> {this.props.value}
|
<input
|
||||||
|
onChange={selected ? this.toggleOff.bind(this) : this.toggleOn.bind(this)}
|
||||||
|
checked={selected}
|
||||||
|
type="checkbox"/>
|
||||||
|
{this.props.value}
|
||||||
</p>
|
</p>
|
||||||
<p style={{
|
<p style={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ const updateCellSelectionMiddleware = (store) => {
|
|||||||
const filterJustChanged =
|
const filterJustChanged =
|
||||||
action.type === "continuous selection using parallel coords brushing" ||
|
action.type === "continuous selection using parallel coords brushing" ||
|
||||||
action.type === "graph brush selection change" ||
|
action.type === "graph brush selection change" ||
|
||||||
action.type === "graph brush deselect"
|
action.type === "graph brush deselect" ||
|
||||||
|
action.type === "categorical metadata filter deselect" ||
|
||||||
|
action.type === "categorical metadata filter select"
|
||||||
;
|
;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -110,7 +112,61 @@ const updateCellSelectionMiddleware = (store) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let modifiedAction = Object.assign({}, action, {newSelection}) /* append the result of all the filters to the action the user just triggered */
|
/*
|
||||||
|
1. figure out if the users have unchecked boxes
|
||||||
|
2. put them in an array
|
||||||
|
3. filter on them
|
||||||
|
*/
|
||||||
|
|
||||||
|
let newCategoricalAsBooleansMap = s.controls.categoricalAsBooleansMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
...spread for merge: https://github.com/reactjs/redux/issues/432
|
||||||
|
|
||||||
|
we do the update here instead of the reducer because we need it for the reactive computation
|
||||||
|
*/
|
||||||
|
if (action.type === "categorical metadata filter select") {
|
||||||
|
newCategoricalAsBooleansMap = {
|
||||||
|
...s.controls.categoricalAsBooleansMap,
|
||||||
|
[action.metadataField]: {
|
||||||
|
...s.controls.categoricalAsBooleansMap[action.metadataField],
|
||||||
|
[action.value]: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (action.type === "categorical metadata filter deselect") {
|
||||||
|
newCategoricalAsBooleansMap = {
|
||||||
|
...s.controls.categoricalAsBooleansMap,
|
||||||
|
[action.metadataField]: {
|
||||||
|
...s.controls.categoricalAsBooleansMap[action.metadataField],
|
||||||
|
[action.value]: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const inactiveCategories = [];
|
||||||
|
_.each(newCategoricalAsBooleansMap, (options, category) => {
|
||||||
|
_.each(options, (isActive, option) => {
|
||||||
|
if (!isActive) {
|
||||||
|
console.log("category: ", category, "option:", option)
|
||||||
|
inactiveCategories.push({category, option})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (inactiveCategories.length > 0) {
|
||||||
|
_.each(inactiveCategories, (d) => {
|
||||||
|
_.each(newSelection, (cell, i) => {
|
||||||
|
if (cell[d.category] === d.option) {
|
||||||
|
newSelection[i]["__selected__"] = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let modifiedAction = Object.assign({}, action, {
|
||||||
|
newSelection,
|
||||||
|
newCategoricalAsBooleansMap,
|
||||||
|
}) /* append the result of all the filters to the action the user just triggered */
|
||||||
|
|
||||||
return next(modifiedAction);
|
return next(modifiedAction);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user