categorical metadata selectable

This commit is contained in:
Colin Megill
2017-10-17 19:27:54 -07:00
parent 11f1f350da
commit 0c0a4124fc
3 changed files with 89 additions and 75 deletions

View File

@@ -8,38 +8,49 @@ import SectionHeader from "../framework/sectionHeader"
import createCategoryCounts from "./createCategoryCounts";
import { alphabeticallySortedValues } from "./util";
@connect((state) => {
return {
selectedMetadata: state.selectedMetadata
}
})
class Button extends React.Component {
render () {
/* has this value for this category already been selected? */
let fontWeight;
if (!this.props.selectedMetadata) { /* there is no selected metadata */
fontWeight = 400;
} 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"]} */
) {
fontWeight = 700
}
return (
<button
<div
key={this.props.i}
onClick={this.props.handleClick(this.props.category, this.props.value)}
onClick={this.props.handleClick(this.props.metadataField, this.props.value)}
style={{
border: "none",
background: "none",
color: "black",
marginRight: 3,
cursor: "pointer",
display: "flex",
fontWeight,
}}>
{this.props.value}
<span
style={{
fontFamily: globals.accentFont,
fontStyle: "italic",
color: globals.darkGrey,
fontSize: globals.tiniestFontSize,
marginLeft: 4,
position: "relative",
top: -1,
<div style={{
width: 200,
flexShrink: 0,
}}>
{this.props.value}
</div>
<span>
{this.props.count}
</span>
</button>
</div>
)
}
}
const Category = ({category, values, handleClick}) => (
const Category = ({metadataField, values, handleClick}) => (
<div style={{
display: "flex",
alignItems: "baseline",
@@ -52,7 +63,7 @@ const Category = ({category, values, handleClick}) => (
fontFamily: globals.accentFont,
fontStyle: "italic",
marginRight: 20,
}}>{category}:</p>
}}>{metadataField}:</p>
<div>
{
_.map(alphabeticallySortedValues(values), (v, i) => {
@@ -60,7 +71,7 @@ const Category = ({category, values, handleClick}) => (
<Button
key={v}
handleClick={handleClick}
category={category}
metadataField={metadataField}
count={values[v]}
value={v}
i={i} />
@@ -73,17 +84,10 @@ const Category = ({category, values, handleClick}) => (
@connect((state) => {
let ranges = null;
if (
state.cells.cells &&
state.cells.cells.data.ranges
) {
ranges = state.cells.cells.data.ranges;
}
const ranges = state.cells.cells && state.cells.cells.data.ranges ? state.cells.cells.data.ranges : null;
return {
ranges: ranges
ranges
}
})
class Categories extends React.Component {
@@ -93,9 +97,9 @@ class Categories extends React.Component {
};
}
handleClick(category, value) {
handleClick(metadataField, value) {
return () => {
this.props.dispatch({type: "category changed", data: {category, value}})
this.props.dispatch({type: "categorical metadata filter selected", metadataField, value})
}
}
render () {
@@ -113,7 +117,7 @@ class Categories extends React.Component {
<Category
handleClick={this.handleClick.bind(this)}
key={key}
category={key}
metadataField={key}
values={value.options}/>
)
} else {

View File

@@ -0,0 +1,53 @@
import uri from "urijs";
import _ from "lodash";
/************************************************************************
*************************************************************************
1. This is all of the state that will be stored in the URL query params.
1a. It is reasonably important it be kept in the same place,
because if initial load or back button etc, we'll hear about that
and manually reconstruct the state from the url, overriding whatever
we had. We could of course listen for the "url changed" type in another
reducer, if this gets messy.
1b. The data structures used here are constrained as well, as urijs
needs to be able to parse them, if arrays: https://hackernoon.com/redux-patterns-add-edit-remove-objects-in-an-array-6ee70cab2456
*************************************************************************
************************************************************************/
const selectedMetadata = (
state = {},
action
) => {
switch (action.type) {
case "url changed": {
const {url} = action;
const parsed = uri.parseQuery(window.location.search);
// console.log("onURLchange sees: ", state, parsed)
return state;
}
case "categorical metadata filter selected": {
if (!state[action.metadataField]) { /* we don't have the field, which means this is a simple insertion */
/* {} becomes {Location: ["Tumor"]} */
return Object.assign({}, state, {[action.metadataField]: [action.value]});
} else { /* we do have the field, so we need to push to a copy of the array */
const updatedField = state[action.metadataField].slice()
updatedField.push(action.value)
return Object.assign({}, state, {
/* {Location: ["Tumor"]} becomes {Location: ["Tumor", "Periphery"]} */
[action.metadataField]: updatedField
})
}
}
case "categorical metadata filter deselected": {
return Object.assign({}, state, {
})
}
default:
return state;
}
return state;
}
export default selectedMetadata;

View File

@@ -1,43 +0,0 @@
import uri from "urijs";
/************************************************************************
*************************************************************************
1. This is all of the state that will be stored in the URL query params.
1a. It is reasonably important it be kept in the same place,
because if initial load or back button etc, we'll hear about that
and manually reconstruct the state from the url, overriding whatever
we had. We could of course listen for the "url changed" type in another
reducer, if this gets messy.
1b. The data structures used here are constrained as well, as urijs
needs to be able to parse them
*************************************************************************
************************************************************************/
const url = (
state = {
selectedMetadata: {}
},
action
) => {
switch (action.type) {
case "url changed": {
const {url} = action;
// const parsed = uri.parseQuery(window.location.search);
// console.log("onURLchange sees: ", state, parsed)
return state;
}
case "category changed": {
return state;
}
default:
return state;
}
return state;
}
export default url;