Skip to content

Commit

Permalink
Merge pull request #253 from nextstrain/controls-to-map
Browse files Browse the repository at this point in the history
Map responds to controls
  • Loading branch information
jameshadfield authored Mar 17, 2017
2 parents d89efe2 + c92b0fd commit 88cdf06
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 167 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"react-transform-catch-errors": "^1.0.0",
"react-transform-hmr": "^1.0.1",
"redbox-react": "1.1.1",
"redux-devtools": "^3.3.2",
"rimraf": "^2.4.3",
"run-sequence": "~0.3.6",
"style-loader": "^0.13.2",
Expand All @@ -43,6 +44,7 @@
"color": "^0.7.3",
"d3": "^3.5.17",
"express-static-gzip": "^0.2.2",
"history": "^4.6.0",
"lodash": "4.16.4",
"moment": "^2.14.1",
"moment-range": "^2.2.0",
Expand Down
107 changes: 53 additions & 54 deletions src/actions/treeProperties.js
Original file line number Diff line number Diff line change
@@ -1,98 +1,97 @@
import { calcTipVisibility,
calcTipRadii,
calcTipCounts,
calcBranchThickness } from "../util/treeHelpers";
import { calcVisibility,
calcTipRadii,
calcTipCounts,
makeParentVisible,
calcBranchThickness } from "../util/treeHelpers";
import * as types from "./types";

const updateTipVisibility = () => {
const updateVisibility = () => {
return (dispatch, getState) => {
const { tree, controls } = getState();
dispatch({
type: types.UPDATE_TIP_VISIBILITY,
data: calcTipVisibility(tree, controls),
version: tree.tipVisibilityVersion + 1
data: calcVisibility(tree, controls),
version: tree.visibilityVersion + 1
});
};
};

/* this must be called AFTER tipVisibility is updated */
/* this must be called AFTER Visibility is updated */
const updateBranchThickness = (idxOfInViewRootNode = 0) => {
return (dispatch, getState) => {
const { tree } = getState();
if (tree.nodes) {
/* step 1: recalculate tipCounts over the tree
note that the tips (actually the nodes) already have
d["tip-visible"] set (from calcTipVisibility) */
calcTipCounts(tree.nodes[0]);
/* step 1: recalculate tipCounts over the tree */
calcTipCounts(tree.nodes[0], tree.visibility);
/* step 2: re-calculate branchThickness & dispatch*/
dispatch({
type: types.UPDATE_BRANCH_THICKNESS,
data: calcBranchThickness(tree.nodes, idxOfInViewRootNode),
version: tree.branchThicknessVersion + 1
type: types.UPDATE_BRANCH_THICKNESS,
data: calcBranchThickness(tree.nodes, tree.visibility, idxOfInViewRootNode),
version: tree.branchThicknessVersion + 1
});
}
};
};

export const restrictTreeToSingleTip = function (tipIdx) {
/* this fn causes things to fall out of sync with the "inView" attr of nodes
you should run updateVisibleTipsAndBranchThicknesses to get things back in sync */
return (dispatch, getState) => {
const { tree } = getState();
// console.log("restrict")
const vis = tree.nodes.map((d, idx) => {
d["tip-visible"] = idx === tipIdx ? 1 : 0;
return idx === tipIdx ? "visible" : "hidden";
});
dispatch({
type: types.UPDATE_TIP_VISIBILITY,
data: vis,
version: tree.tipVisibilityVersion + 1
});
dispatch(updateBranchThickness());
};
/* this fn causes things to fall out of sync with the "inView" attr of nodes
you should run updateVisibleTipsAndBranchThicknesses to get things back in sync */
return (dispatch, getState) => {
const { tree } = getState();
/* make the tip and all the parents down to the root visibile */
const visibility = new Array(tree.nodes.length);
visibility.fill(false);
visibility[tipIdx] = true;
makeParentVisible(visibility, tree.nodes[tipIdx]);
dispatch({
type: types.UPDATE_TIP_VISIBILITY,
data: visibility.map((cv) => cv ? "visible" : "hidden"),
version: tree.visibilityVersion + 1
});
dispatch(updateBranchThickness());
};
};

export const updateVisibleTipsAndBranchThicknesses = function () {
/* this fn doesn't need arguments as it relies on the "inView" attr of nodes */
return (dispatch, getState) => {
const { tree, controls } = getState();
dispatch({
type: types.UPDATE_TIP_VISIBILITY,
data: calcTipVisibility(tree, controls),
version: tree.tipVisibilityVersion + 1
});
dispatch(updateBranchThickness());
};
/* this fn doesn't need arguments as it relies on the "inView" attr of nodes */
return (dispatch, getState) => {
const { tree, controls } = getState();
dispatch({
type: types.UPDATE_TIP_VISIBILITY,
data: calcVisibility(tree, controls),
version: tree.visibilityVersion + 1
});
dispatch(updateBranchThickness());
};
};

/* when tip max / min changes, we need to (a) update the controls reducer
with the new value(s), (b) update the tree tipVisibility */
with the new value(s), (b) update the tree visibility */
export const changeDateFilter = function (newMin, newMax) {
return (dispatch, getState) => {
// console.log("changeDateFilter", newMin, newMax)
const { tree } = getState();
// console.log("changeDateFilter", newMin, newMax)
const { tree } = getState();
if (newMin) {
dispatch({type: types.CHANGE_DATE_MIN, data: newMin});
}
if (newMax) {
dispatch({type: types.CHANGE_DATE_MAX, data: newMax});
}
/* initially, the tree isn't loaded, so don't bother trying to do things */
if (tree.loadStatus === 2) {
dispatch(updateTipVisibility());
dispatch(updateBranchThickness());
}
/* initially, the tree isn't loaded, so don't bother trying to do things */
if (tree.loadStatus === 2) {
dispatch(updateVisibility());
dispatch(updateBranchThickness());
}
};
};

/* zoomToClade takes care of setting tipVis and branchThickness.
Note that the zooming / tree stuff is done imperitively by phyloTree */
export const zoomToClade = function (idxOfInViewRootNode) {
return (dispatch) => {
dispatch(updateTipVisibility());
dispatch(updateBranchThickness(idxOfInViewRootNode));
};
return (dispatch) => {
dispatch(updateVisibility());
dispatch(updateBranchThickness(idxOfInViewRootNode));
};
};

const updateTipRadii = () => {
Expand Down Expand Up @@ -132,7 +131,7 @@ export const applyFilterQuery = (filterType, fields, values) => {
// filterType,
fields,
values});
dispatch(updateTipVisibility());
dispatch(updateVisibility());
dispatch(updateBranchThickness());
};
};
19 changes: 9 additions & 10 deletions src/components/controls/date-range-inputs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ moment.updateLocale("en", {
}
});

export const calendarToNumeric = (calDate) => {
const unixDate = moment(calDate).unix(); // number of seconds since 1970
return 1970 + (unixDate / 365.2425 / 24 / 3600);
};

@connect((state) => {
return {
dateMin: state.controls.dateMin,
Expand Down Expand Up @@ -52,12 +57,6 @@ class DateRangeInputs extends React.Component {
return moment.unix(unixDate).format("YYYY-MM-DD");
}

calendarToNumeric(calDate) {
const unixDate = moment(calDate).unix(); // number of seconds since 1970
return 1970 + (unixDate / 365.2425 / 24 / 3600);
}


updateFromPicker(ref, momentDate) {
// a momentDate is received from DatePicker
let newRange;
Expand Down Expand Up @@ -146,10 +145,10 @@ class DateRangeInputs extends React.Component {
const selectedMin = this.props.dateMin;
const selectedMax = this.props.dateMax;

const absoluteMinNumDate = this.calendarToNumeric(absoluteMin);
const absoluteMaxNumDate = this.calendarToNumeric(absoluteMax);
const selectedMinNumDate = this.calendarToNumeric(selectedMin);
const selectedMaxNumDate = this.calendarToNumeric(selectedMax);
const absoluteMinNumDate = calendarToNumeric(absoluteMin);
const absoluteMaxNumDate = calendarToNumeric(absoluteMax);
const selectedMinNumDate = calendarToNumeric(selectedMin);
const selectedMaxNumDate = calendarToNumeric(selectedMax);

return (
<div>
Expand Down
37 changes: 21 additions & 16 deletions src/components/map/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import getLatLongs from "../../util/mapHelpersLatLong";
return {
datasetGuid: state.tree.datasetGuid,
nodes: state.tree.nodes,
visibility: state.tree.visibility,
visibilityVersion: state.tree.visibilityVersion,
metadata: state.metadata.metadata,
browserDimensions: state.browserDimensions.browserDimensions,
colorScale: state.controls.colorScale,
Expand Down Expand Up @@ -132,11 +134,13 @@ class Map extends React.Component {
// nextProps.datasetGuid &&
// this.props.datasetGuid !== nextProps.datasetGuid // and the dataset has changed
*/

const mapIsDrawn = !!this.state.map;
const somethingChanged = (this.props.colorBy !== nextProps.colorBy || this.props.geoResolution !== nextProps.geoResolution || this.props.visibilityVersion !== nextProps.visibilityVersion); // prevProps.colorBy !== /* */

if (
(this.state.map &&
this.props.colorBy !== nextProps.colorBy) || // prevProps.colorBy !== /* */
(this.state.map &&
this.props.geoResolution !== nextProps.geoResolution)
mapIsDrawn &&
somethingChanged
) {
this.state.d3DOMNode.selectAll("*").remove();

Expand All @@ -149,16 +153,19 @@ class Map extends React.Component {
}
}
maybeDrawDemesAndTransmissions(prevProps) {

const mapIsDrawn = !!this.state.map;
const allDataPresent = !!(this.props.colorScale && this.props.colorScale.version !== prevProps.colorScale.version && this.props.metadata && this.props.nodes && this.state.responsive && this.state.d3DOMNode);
const demesAbsent = !this.state.demes;
// const newColorScale = this.props.colorScale.version !== prevProps.colorScale.version;
// const newGeoResolution = this.props.geoResolution !== prevProps.geoResolution;
// const initialVisibilityVersion = this.props.visibilityVersion === 1; /* see tree reducer, we set this to 1 after tree comes back */
// const newVisibilityVersion = this.props.visibilityVersion !== prevProps.visibilityVersion;

if (
this.props.colorScale &&
this.state.map && /* we have already drawn the map */
this.props.metadata && /* we have the data we need */
this.props.nodes &&
this.state.responsive &&
this.state.d3DOMNode &&
!this.state.demes && /* we haven't already drawn demes */
(this.props.colorScale.version !== prevProps.colorScale.version ||
this.props.geoResolution !== prevProps.geoResolution)
mapIsDrawn &&
allDataPresent &&
demesAbsent
) {
/* data structures to feed to d3 latLongs = { tips: [{}, {}], transmissions: [{}, {}] } */
if (!this.state.boundsSet){ //we are doing the initial render -> set map to the range of the data
Expand All @@ -184,13 +191,11 @@ class Map extends React.Component {
});
}
}

respondToLeafletEvent(leafletEvent) {
if (leafletEvent.type === "moveend") { /* zooming and panning */
updateOnMoveEnd(this.state.d3elems, this.latLongs());
}
}

getGeoRange() {
const latitudes = [];
const longitudes = [];
Expand All @@ -212,7 +217,6 @@ class Map extends React.Component {
const west = Math.min(180, maxLng + lngRange*0.2);
return [L.latLng(south,west), L.latLng(north, east)];
}

maybeUpdateDemesAndTransmissions() {
/* todo */
}
Expand All @@ -222,6 +226,7 @@ class Map extends React.Component {
latLongs() {
return getLatLongs(
this.props.nodes,
this.props.visibility,
this.props.metadata,
this.state.map,
this.props.colorBy,
Expand Down
18 changes: 6 additions & 12 deletions src/components/tree/treeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ import BranchSelectedPanel from "./branchSelectedPanel";
import TipSelectedPanel from "./tipSelectedPanel";
import { connect } from "react-redux";
import computeResponsive from "../../util/computeResponsive";
import { getGenotype } from "../../util/getGenotype";
import { arrayInEquality,
branchThickness,
tipRadii,
tipVisibility,
nodeColor} from "../../util/treeHelpers";
import { zoomToClade,
restrictTreeToSingleTip,
updateVisibleTipsAndBranchThicknesses} from "../../actions/treeProperties";
Expand Down Expand Up @@ -135,10 +129,10 @@ class TreeView extends React.Component {
const branchAttrToUpdate = {};
const branchStyleToUpdate = {};

if (nextProps.tree.tipVisibilityVersion &&
this.props.tree.tipVisibilityVersion !== nextProps.tree.tipVisibilityVersion) {
// console.log("tipVisibilityVersion change detected", this.props.tree.tipVisibilityVersion, nextProps.tree.tipVisibilityVersion)
tipStyleToUpdate["visibility"] = nextProps.tree.tipVisibility;
if (nextProps.tree.visibilityVersion &&
this.props.tree.visibilityVersion !== nextProps.tree.visibilityVersion) {
// console.log("visibilityVersion change detected", this.props.tree.visibilityVersion, nextProps.tree.visibilityVersion)
tipStyleToUpdate["visibility"] = nextProps.tree.visibility;
}
if (nextProps.tree.tipRadiiVersion &&
this.props.tree.tipRadiiVersion !== nextProps.tree.tipRadiiVersion) {
Expand Down Expand Up @@ -269,7 +263,7 @@ class TreeView extends React.Component {
},
/* branch Thicknesses - guarenteed to be in redux by now */
nextProps.tree.branchThickness,
nextProps.tree.tipVisibility
nextProps.tree.visibility
);
return myTree;
} else {
Expand Down Expand Up @@ -442,7 +436,7 @@ class TreeView extends React.Component {
}
// call phyloTree to zoom out, this rerenders the geometry
this.state.tree.zoomToParent(mediumTransitionDuration);
// wait and reset tipVisibility
// wait and reset visibility
this.timeout = setTimeout(makeCallBack(), mediumTransitionDuration);
}
}
Expand Down
Loading

0 comments on commit 88cdf06

Please sign in to comment.