Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PhyloTree cleanup #493

Merged
merged 10 commits into from
Feb 5, 2018
4 changes: 2 additions & 2 deletions src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Controls from "./controls/controls";
import { Entropy } from "./charts/entropy";
import Map from "./map/map";
import Info from "./info/info";
import TreeView from "./tree/treeView";
import Tree from "./tree";
import { controlsHiddenWidth, narrativeWidth, controlsWidth } from "../util/globals";
import { sidebarColor } from "../globalStyles";
import TitleBar from "./framework/title-bar";
Expand Down Expand Up @@ -106,7 +106,7 @@ class App extends React.Component {
<Background>
<Info padding={padding} />
{this.props.metadata.panels.indexOf("tree") === -1 ? null : (
<TreeView padding={padding} />
<Tree padding={padding} />
)}
{this.props.metadata.panels.indexOf("map") === -1 ? null : (
<Map padding={padding} justGotNewDatasetRenderNewMap={false} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/download/downloadModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from "react-redux";
import { DISMISS_DOWNLOAD_MODAL } from "../../actions/types";
import { materialButton, medGrey, infoPanelStyles } from "../../globalStyles";
import { stopProp } from "../tree/tipSelectedPanel";
import { stopProp } from "../tree/infoPanels/click";
import { authorString } from "../../util/stringHelpers";
import * as helpers from "./helperFunctions";
import * as icons from "../framework/svg-icons";
Expand Down
116 changes: 58 additions & 58 deletions src/components/tree/treeView.js → src/components/tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import { connect } from "react-redux";
import { select } from "d3-selection";
import { ReactSVGPanZoom } from "react-svg-pan-zoom";
import Card from "../framework/card";
import Legend from "./legend";
import Legend from "./legend/legend";
import ZoomOutIcon from "../framework/zoom-out-icon";
import ZoomInIcon from "../framework/zoom-in-icon";
import PhyloTree from "./phyloTree";
import PhyloTree from "./phyloTree/phyloTree";
import { mediumTransitionDuration } from "../../util/globals";
import InfoPanel from "./infoPanel";
import TipSelectedPanel from "./tipSelectedPanel";
import HoverInfoPanel from "./infoPanels/hover";
import TipClickedPanel from "./infoPanels/click";
import computeResponsive from "../../util/computeResponsive";
import * as funcs from "./treeViewFunctions";
import { updateStylesAndAttrs, salientPropChanges } from "./reactD3Interface";
import * as callbacks from "./reactD3Interface/callbacks";

/*
this.props.tree contains the nodes etc used to build the PhyloTree
Expand All @@ -38,7 +39,7 @@ there are actually backlinks from the phylotree tree
panelLayout: state.controls.panelLayout
};
})
class TreeView extends React.Component {
class Tree extends React.Component {
constructor(props) {
super(props);
this.Viewer = null;
Expand All @@ -49,6 +50,11 @@ class TreeView extends React.Component {
selectedTip: null,
tree: null
};
/* bind callbacks */
this.clearSelectedTip = callbacks.clearSelectedTip.bind(this);
this.resetView = callbacks.resetView.bind(this);
this.onViewerChange = callbacks.onViewerChange.bind(this);
this.handleIconClickHOF = callbacks.handleIconClickHOF.bind(this);
}
static propTypes = {
mutType: PropTypes.string.isRequired
Expand All @@ -58,7 +64,7 @@ class TreeView extends React.Component {
/* This both creates the tree (when it's loaded into redux) and
works out what to update, based upon changes to redux.control */
let tree = this.state.tree;
const changes = funcs.salientPropChanges(this.props, nextProps, tree);
const changes = salientPropChanges(this.props, nextProps, tree);
/* usefull for debugging: */
// console.log("CWRP Changes:",
// Object.keys(changes).filter((k) => !!changes[k]).reduce((o, k) => {
Expand All @@ -71,26 +77,26 @@ class TreeView extends React.Component {
} else if (changes.newData) {
tree = this.makeTree(nextProps);
/* extra (initial, once only) call to update the tree colouring */
for (const k in changes) {
for (const k in changes) { // eslint-disable-line
changes[k] = false;
}
changes.colorBy = true;
funcs.updateStylesAndAttrs(this, changes, nextProps, tree);
updateStylesAndAttrs(this, changes, nextProps, tree);
this.setState({tree});
if (this.Viewer) {
this.Viewer.fitToViewer();
}
return null; /* return to avoid an unnecessary updateStylesAndAttrs call */
}
if (tree) {
funcs.updateStylesAndAttrs(this, changes, nextProps, tree);
updateStylesAndAttrs(this, changes, nextProps, tree);
}
return null;
}

componentDidMount() {
const tree = this.makeTree(this.props);
funcs.updateStylesAndAttrs(this, {colorBy: true}, this.props, tree);
updateStylesAndAttrs(this, {colorBy: true}, this.props, tree);
this.setState({tree});
if (this.Viewer) {
this.Viewer.fitToViewer();
Expand Down Expand Up @@ -120,43 +126,42 @@ class TreeView extends React.Component {

makeTree(nextProps) {
const nodes = nextProps.tree.nodes;
if (nodes && this.refs.d3TreeElement) {
const myTree = new PhyloTree(nodes[0]);
if (nodes && this.d3ref) {
const myTree = new PhyloTree(nodes);
// https://facebook.github.io/react/docs/refs-and-the-dom.html
myTree.render(
select(this.refs.d3TreeElement),
select(this.d3ref),
this.props.layout,
this.props.distanceMeasure,
{ /* options */
grid: true,
confidence: nextProps.temporalConfidence.display,
showVaccines: !!nextProps.tree.vaccines,
branchLabels: true, //generate DOM object
showBranchLabels: false, //hide them initially -> couple to redux state
tipLabels: true, //generate DOM object
showTipLabels: true //show
branchLabels: true,
showBranchLabels: false,
tipLabels: true,
showTipLabels: true
},
{ /* callbacks */
onTipHover: funcs.onTipHover.bind(this),
onTipClick: funcs.onTipClick.bind(this),
onBranchHover: funcs.onBranchHover.bind(this),
onBranchClick: funcs.onBranchClick.bind(this),
onBranchLeave: funcs.onBranchLeave.bind(this),
onTipLeave: funcs.onTipLeave.bind(this),
branchLabel: funcs.branchLabel,
branchLabelSize: funcs.branchLabelSize,
onTipHover: callbacks.onTipHover.bind(this),
onTipClick: callbacks.onTipClick.bind(this),
onBranchHover: callbacks.onBranchHover.bind(this),
onBranchClick: callbacks.onBranchClick.bind(this),
onBranchLeave: callbacks.onBranchLeave.bind(this),
onTipLeave: callbacks.onTipLeave.bind(this),
branchLabel: callbacks.branchLabel,
branchLabelSize: callbacks.branchLabelSize,
tipLabel: (d) => d.n.strain,
tipLabelSize: funcs.tipLabelSize.bind(this)
tipLabelSize: callbacks.tipLabelSize.bind(this)
},
nextProps.tree.branchThickness, /* guarenteed to be in redux by now */
nextProps.tree.visibility,
nextProps.temporalConfidence.on, /* drawConfidence? */
nextProps.tree.vaccines
);
return myTree;
} else {
return null;
}
return null;
}

render() {
Expand All @@ -172,7 +177,7 @@ class TreeView extends React.Component {
return (
<Card center title={cardTitle}>
<Legend padding={this.props.padding}/>
<InfoPanel
<HoverInfoPanel
tree={this.state.tree}
mutType={this.props.mutType}
temporalConfidence={this.props.temporalConfidence.display}
Expand All @@ -183,8 +188,8 @@ class TreeView extends React.Component {
colorByConfidence={this.props.colorByConfidence}
colorScale={this.props.colorScale}
/>
<TipSelectedPanel
goAwayCallback={(d) => funcs.clearSelectedTip.bind(this)(d)}
<TipClickedPanel
goAwayCallback={this.clearSelectedTip}
tip={this.state.selectedTip}
metadata={this.props.metadata}
/>
Expand All @@ -202,10 +207,8 @@ class TreeView extends React.Component {
detectAutoPan={false}
background={"#FFF"}
miniaturePosition={"none"}
// onMouseDown={this.startPan.bind(this)}
onDoubleClick={funcs.resetView.bind(this)}
//onMouseUp={this.endPan.bind(this)}
onChangeValue={ funcs.onViewerChange.bind(this) }
onDoubleClick={this.resetView}
onChangeValue={this.onViewerChange}
>
<svg style={{pointerEvents: "auto"}}
width={responsive.width}
Expand All @@ -216,35 +219,32 @@ class TreeView extends React.Component {
height={responsive.height}
id={"d3TreeElement"}
style={{cursor: "default"}}
ref="d3TreeElement"
>
</g>
ref={(c) => {this.d3ref = c;}}
/>
</svg>
</ReactSVGPanZoom>
<svg width={50} height={130}
style={{position: "absolute", right: 20, bottom: 20}}
>
<defs>
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="2" dy="2" result="offsetblur"/>
<feComponentTransfer>
<feFuncA type="linear" slope="0.2"/>
</feComponentTransfer>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<svg width={50} height={130} style={{position: "absolute", right: 20, bottom: 20}}>
<defs>
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="2" dy="2" result="offsetblur"/>
<feComponentTransfer>
<feFuncA type="linear" slope="0.2"/>
</feComponentTransfer>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<ZoomInIcon
handleClick={funcs.handleIconClick.bind(this)("zoom-in")}
handleClick={this.handleIconClickHOF("zoom-in")}
active
x={10}
y={50}
/>
<ZoomOutIcon
handleClick={funcs.handleIconClick.bind(this)("zoom-out")}
handleClick={this.handleIconClickHOF("zoom-out")}
active
x={10}
y={90}
Expand All @@ -255,4 +255,4 @@ class TreeView extends React.Component {
}
}

export default TreeView;
export default Tree;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { infoPanelStyles } from "../../globalStyles";
import { prettyString, authorString } from "../../util/stringHelpers";
import { numericToCalendar } from "../../util/dateHelpers";
import { infoPanelStyles } from "../../../globalStyles";
import { prettyString, authorString } from "../../../util/stringHelpers";
import { numericToCalendar } from "../../../util/dateHelpers";
// import { getAuthor } from "../download/helperFunctions";

const styles = {
Expand All @@ -24,7 +24,7 @@ const styles = {
};

export const stopProp = (e) => {
if (!e) {e = window.event;}
if (!e) {e = window.event;} // eslint-disable-line no-param-reassign
e.cancelBubble = true;
if (e.stopPropagation) {e.stopPropagation();}
};
Expand All @@ -39,9 +39,9 @@ const item = (key, value) => (

const formatURL = (url) => {
if (url !== undefined && url.startsWith("https_")) {
url = url.replace("https_", "https:");
return url.replace("https_", "https:");
} else if (url !== undefined && url.startsWith("http_")) {
url = url.replace("http_", "http:");
return url.replace("http_", "http:");
}
return url;
};
Expand Down Expand Up @@ -79,7 +79,7 @@ const displayVaccineInfo = (d) => {
const validValue = (value) => value !== "?" && value !== undefined && value !== "undefined";
const validAttr = (attrs, key) => key in attrs && validValue(attrs[key]);

const TipSelectedPanel = ({tip, goAwayCallback, metadata}) => {
const TipClickedPanel = ({tip, goAwayCallback, metadata}) => {
if (!tip) {return null;}
const url = validAttr(tip.n.attr, "url") ? formatURL(tip.n.attr.url) : false;
const uncertainty = "num_date_confidence" in tip.n.attr && tip.n.attr.num_date_confidence[0] !== tip.n.attr.num_date_confidence[1];
Expand Down Expand Up @@ -121,4 +121,4 @@ const TipSelectedPanel = ({tip, goAwayCallback, metadata}) => {
);
};

export default TipSelectedPanel;
export default TipClickedPanel;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { infoPanelStyles } from "../../globalStyles";
import { prettyString } from "../../util/stringHelpers";
import { numericToCalendar } from "../../util/dateHelpers";
import { getTipColorAttribute } from "./treeHelpers";
import { infoPanelStyles } from "../../../globalStyles";
import { prettyString } from "../../../util/stringHelpers";
import { numericToCalendar } from "../../../util/dateHelpers";
import { getTipColorAttribute } from "../treeHelpers";

const infoLineJSX = (item, value) => (
<g>
Expand All @@ -20,8 +20,8 @@ const infoBlockJSX = (item, values) => (
<p style={{marginBottom: "-0.7em", fontWeight: "500"}}>
{item}
</p>
{values.map((k, i) => (
<p key={i} style={{fontWeight: "300", marginBottom: "-0.9em", marginLeft: "0em"}}>
{values.map((k) => (
<p key={k} style={{fontWeight: "300", marginBottom: "-0.9em", marginLeft: "0em"}}>
{k}
</p>
))}
Expand Down Expand Up @@ -69,7 +69,7 @@ const displayColorBy = (d, distanceMeasure, temporalConfidence, colorByConfidenc
if (colorByConfidence === true) {
const lkey = colorBy + "_confidence";
if (Object.keys(d.attr).indexOf(lkey) === -1) {
console.log("Error - couldn't find confidence vals for ", lkey);
console.error("Error - couldn't find confidence vals for ", lkey);
return null;
}
const vals = Object.keys(d.attr[lkey])
Expand Down Expand Up @@ -144,7 +144,7 @@ const getMutationsJSX = (d, mutType) => {
}
return infoLineJSX("No amino acid mutations", "");
}
console.log("Error parsing mutations for branch", d.strain);
console.warn("Error parsing mutations for branch", d.strain);
return null;
};

Expand Down Expand Up @@ -194,7 +194,7 @@ const getPanelStyling = (d, viewer) => {
};
if (pos.x < viewerState.viewerWidth * 0.6) {
styles.container.left = pos.x + xOffset;
}else{
} else {
styles.container.right = viewerState.viewerWidth - pos.x + xOffset;
}
if (pos.y < viewerState.viewerHeight * 0.55) {
Expand All @@ -207,11 +207,8 @@ const getPanelStyling = (d, viewer) => {

const tipDisplayColorByInfo = (d, colorBy, distanceMeasure, temporalConfidence, mutType, colorScale) => {
if (colorBy === "num_date") {
if (distanceMeasure === "num_date") {
return null;
} else {
return getBranchTimeJSX(d.n, temporalConfidence);
}
if (distanceMeasure === "num_date") return null;
return getBranchTimeJSX(d.n, temporalConfidence);
}
if (colorBy.slice(0, 2) === "gt") {
const key = mutType === "nuc" ?
Expand All @@ -236,7 +233,7 @@ const displayVaccineInfo = (d) => {
};

/* the actual component - a pure function, so we can return early if needed */
const InfoPanel = ({tree, mutType, temporalConfidence, distanceMeasure,
const HoverInfoPanel = ({tree, mutType, temporalConfidence, distanceMeasure,
hovered, viewer, colorBy, colorByConfidence, colorScale}) => {
if (!(tree && hovered)) {
return null;
Expand All @@ -257,7 +254,7 @@ const InfoPanel = ({tree, mutType, temporalConfidence, distanceMeasure,
inner = (
<g>
{getBranchDescendents(d.n)}
{/*getFrequenciesJSX(d.n, mutType)*/}
{/* getFrequenciesJSX(d.n, mutType) */}
{getMutationsJSX(d.n, mutType)}
{distanceMeasure === "div" ? getBranchDivJSX(d.n) : getBranchTimeJSX(d.n, temporalConfidence)}
{displayColorBy(d.n, distanceMeasure, temporalConfidence, colorByConfidence, colorBy)}
Expand All @@ -280,4 +277,4 @@ const InfoPanel = ({tree, mutType, temporalConfidence, distanceMeasure,
);
};

export default InfoPanel;
export default HoverInfoPanel;
Loading