diff --git a/src/actions/recomputeReduxState.js b/src/actions/recomputeReduxState.js index 7a6f90b73..2ff709fad 100644 --- a/src/actions/recomputeReduxState.js +++ b/src/actions/recomputeReduxState.js @@ -64,8 +64,8 @@ const modifyStateViaURLQuery = (state, query) => { if (query.m && state.branchLengthsToDisplay === "divAndDate") { state["distanceMeasure"] = query.m; } - if (query.z) { - state["treeZoom"] = query.z; + if (query.focus) { + state["treeFocus"] = query.focus; } if (query.c) { state["colorBy"] = query.c; diff --git a/src/actions/types.js b/src/actions/types.js index 543f46d27..87ff4c3e9 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -7,7 +7,7 @@ export const SEARCH_INPUT_CHANGE = "SEARCH_INPUT_CHANGE"; export const CHANGE_LAYOUT = "CHANGE_LAYOUT"; export const CHANGE_BRANCH_LABEL = "CHANGE_BRANCH_LABEL"; export const CHANGE_DISTANCE_MEASURE = "CHANGE_DISTANCE_MEASURE"; -export const CHANGE_TREE_ZOOM = "CHANGE_TREE_ZOOM"; +export const CHANGE_TREE_FOCUS = "CHANGE_TREE_FOCUS"; export const CHANGE_DATES_VISIBILITY_THICKNESS = "CHANGE_DATES_VISIBILITY_THICKNESS"; export const CHANGE_ABSOLUTE_DATE_MIN = "CHANGE_ABSOLUTE_DATE_MIN"; export const CHANGE_ABSOLUTE_DATE_MAX = "CHANGE_ABSOLUTE_DATE_MAX"; diff --git a/src/components/tree/index.js b/src/components/tree/index.js index 414943de2..2105aea18 100644 --- a/src/components/tree/index.js +++ b/src/components/tree/index.js @@ -15,7 +15,7 @@ const Tree = connect((state) => ({ temporalConfidence: state.controls.temporalConfidence, distanceMeasure: state.controls.distanceMeasure, explodeAttr: state.controls.explodeAttr, - treeZoom: state.controls.treeZoom, + treeFocus: state.controls.treeFocus, colorScale: state.controls.colorScale, colorings: state.metadata.colorings, genomeMap: state.entropy.genomeMap, diff --git a/src/components/tree/phyloTree/change.js b/src/components/tree/phyloTree/change.js index b7b96a4a5..6613d56af 100644 --- a/src/components/tree/phyloTree/change.js +++ b/src/components/tree/phyloTree/change.js @@ -258,7 +258,7 @@ export const change = function change({ /* change these things to provided value (unless undefined) */ newDistance = undefined, newLayout = undefined, - newTreeZoom = undefined, + newTreeFocus = undefined, updateLayout = undefined, // todo - this seems identical to `newLayout` newBranchLabellingKey = undefined, showAllBranchLabels = undefined, @@ -314,7 +314,7 @@ export const change = function change({ svgPropsToUpdate.add("stroke-width"); nodePropsToModify["stroke-width"] = branchThickness; } - if (newDistance || newLayout || newTreeZoom || updateLayout || zoomIntoClade || svgHasChangedDimensions || changeNodeOrder) { + if (newDistance || newLayout || newTreeFocus || updateLayout || zoomIntoClade || svgHasChangedDimensions || changeNodeOrder) { elemsToUpdate.add(".tip").add(".branch.S").add(".branch.T").add(".branch"); elemsToUpdate.add(".vaccineCross").add(".vaccineDottedLine").add(".conf"); elemsToUpdate.add('.branchLabel').add('.tipLabel'); @@ -360,10 +360,10 @@ export const change = function change({ /* run calculations as needed - these update properties on the phylotreeNodes (similar to updateNodesWithNewData) */ /* distance */ if (newDistance || updateLayout) this.setDistance(newDistance); - /* treeZoom */ - if (newTreeZoom || updateLayout) this.setTreeZoom(newTreeZoom); - /* layout (must run after distance and treeZoom) */ - if (newDistance || newLayout || newTreeZoom || updateLayout || changeNodeOrder) { + /* treeFocus */ + if (newTreeFocus || updateLayout) this.setTreeFocus(newTreeFocus); + /* layout (must run after distance and treeFocus) */ + if (newDistance || newLayout || newTreeFocus || updateLayout || changeNodeOrder) { this.setLayout(newLayout || this.layout, scatterVariables); } /* show confidences - set this param which actually adds the svg paths for @@ -380,7 +380,7 @@ export const change = function change({ newDistance || newLayout || changeNodeOrder || - newTreeZoom || + newTreeFocus || updateLayout || zoomIntoClade || svgHasChangedDimensions || diff --git a/src/components/tree/phyloTree/layouts.js b/src/components/tree/phyloTree/layouts.js index ed7e70daf..27d1ee053 100644 --- a/src/components/tree/phyloTree/layouts.js +++ b/src/components/tree/phyloTree/layouts.js @@ -301,7 +301,7 @@ export const calcYValues = (nodes, spacing = "even") => { // console.log("calcYValues started with ", spacing); let total = 0; /* cumulative counter of y value at tip */ let calcY; /* fn called calcY(node) to return some amount of y value at a tip */ - if (spacing.includes("zoom") && 'visibility' in nodes[0]) { + if (spacing.includes("focus") && 'visibility' in nodes[0]) { const numberOfTips = nodes.length; const numTipsVisible = nodes.filter((d) => !d.hasChildren && d.visibility === NODE_VISIBLE).length; const yPerVisible = (0.8 * numberOfTips) / numTipsVisible; @@ -334,19 +334,19 @@ export const calcYValues = (nodes, spacing = "even") => { }; /** - * assigns the attribute this.treeZoom and calls the function that - * recalculates yvalues based on treeZoom setting - * @param treeZoom -- how to zoom nodes, eg ["even", "zoom"] + * assigns the attribute this.treeFocus and calls the function that + * recalculates yvalues based on treeFocus setting + * @param treeFocus -- how to zoom nodes, eg ["even", "focus"] */ -export const setTreeZoom = function setTreeZoom(treeZoom) { - timerStart("setTreeZoom"); - if (typeof treeZoom === "undefined") { - this.treeZoom = "even"; +export const setTreeFocus = function setTreeFocus(treeFocus) { + timerStart("setTreeFocus"); + if (typeof treeFocus === "undefined") { + this.treeFocus = "even"; } else { - this.treeZoom = treeZoom; + this.treeFocus = treeFocus; } - calcYValues(this.nodes, this.treeZoom); - timerEnd("setTreeZoom"); + calcYValues(this.nodes, this.treeFocus); + timerEnd("setTreeFocus"); }; /** diff --git a/src/components/tree/phyloTree/phyloTree.js b/src/components/tree/phyloTree/phyloTree.js index abfa04973..c91224fbd 100644 --- a/src/components/tree/phyloTree/phyloTree.js +++ b/src/components/tree/phyloTree/phyloTree.js @@ -63,7 +63,7 @@ PhyloTree.prototype.updateColorBy = renderers.updateColorBy; /* C A L C U L A T E G E O M E T R I E S E T C ( M O D I F I E S N O D E S , N O T S V G ) */ PhyloTree.prototype.setDistance = layouts.setDistance; PhyloTree.prototype.setLayout = layouts.setLayout; -PhyloTree.prototype.setTreeZoom = layouts.setTreeZoom; +PhyloTree.prototype.setTreeFocus = layouts.setTreeFocus; PhyloTree.prototype.rectangularLayout = layouts.rectangularLayout; PhyloTree.prototype.scatterplotLayout = layouts.scatterplotLayout; PhyloTree.prototype.unrootedLayout = layouts.unrootedLayout; diff --git a/src/components/tree/phyloTree/renderers.js b/src/components/tree/phyloTree/renderers.js index b45c531a2..dcdb6f242 100644 --- a/src/components/tree/phyloTree/renderers.js +++ b/src/components/tree/phyloTree/renderers.js @@ -7,7 +7,7 @@ import { getEmphasizedColor } from "../../../util/colorHelpers"; * @param {d3 selection} svg -- the svg into which the tree is drawn * @param {string} layout -- the layout to be used, e.g. "rect" * @param {string} distance -- the property used as branch length, e.g. div or num_date - * @param {string} treeZoom -- how to to treat spread of yValues, e.g. "even" or "zoom" + * @param {string} treeFocus -- how to to treat spread of yValues, e.g. "even" or "focus" * @param {object} parameters -- an object that contains options that will be added to this.params * @param {object} callbacks -- an object with call back function defining mouse behavior * @param {array} branchThickness -- array of branch thicknesses (same ordering as tree nodes) @@ -22,7 +22,7 @@ import { getEmphasizedColor } from "../../../util/colorHelpers"; * @param {object} scatterVariables -- {x, y} properties to map nodes => scatterplot (only used if layout="scatter") * @return {null} */ -export const render = function render(svg, layout, distance, treeZoom, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii, dateRange, scatterVariables) { +export const render = function render(svg, layout, distance, treeFocus, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii, dateRange, scatterVariables) { timerStart("phyloTree render()"); this.svg = svg; this.params = Object.assign(this.params, parameters); @@ -43,7 +43,7 @@ export const render = function render(svg, layout, distance, treeZoom, parameter /* set x, y values & scale them to the screen */ setDisplayOrder(this.nodes); this.setDistance(distance); - this.setTreeZoom(treeZoom); + this.setTreeFocus(treeFocus); this.setLayout(layout, scatterVariables); this.mapToScreen(); diff --git a/src/components/tree/reactD3Interface/change.js b/src/components/tree/reactD3Interface/change.js index 0ad46614f..40d2642a2 100644 --- a/src/components/tree/reactD3Interface/change.js +++ b/src/components/tree/reactD3Interface/change.js @@ -49,9 +49,9 @@ export const changePhyloTreeViaPropsComparison = (mainTree, phylotree, oldProps, args.changeNodeOrder = true; } - /* change treeZoom behavior */ - if (oldProps.treeZoom !== newProps.treeZoom) { - args.newTreeZoom = newProps.treeZoom; + /* change treeFocus behavior */ + if (oldProps.treeFocus !== newProps.treeFocus) { + args.newTreeFocus = newProps.treeFocus; args.updateLayout = true; } diff --git a/src/components/tree/reactD3Interface/initialRender.js b/src/components/tree/reactD3Interface/initialRender.js index 595a41340..87b5b4b95 100644 --- a/src/components/tree/reactD3Interface/initialRender.js +++ b/src/components/tree/reactD3Interface/initialRender.js @@ -22,7 +22,7 @@ export const renderTree = (that, main, phylotree, props) => { select(ref), props.layout, props.distanceMeasure, - props.treeZoom, + props.treeFocus, { /* parameters (modifies PhyloTree's defaults) */ grid: true, confidence: props.temporalConfidence.display, diff --git a/src/components/tree/tree.js b/src/components/tree/tree.js index f3a71093e..d8158c290 100644 --- a/src/components/tree/tree.js +++ b/src/components/tree/tree.js @@ -2,7 +2,7 @@ import React from "react"; import { withTranslation } from "react-i18next"; import { FaSearchMinus } from "react-icons/fa"; import { updateVisibleTipsAndBranchThicknesses } from "../../actions/tree"; -import { CHANGE_TREE_ZOOM } from "../../actions/types"; +import { CHANGE_TREE_FOCUS } from "../../actions/types"; import Card from "../framework/card"; import Legend from "./legend/legend"; import PhyloTree from "./phyloTree/phyloTree"; @@ -40,7 +40,7 @@ class Tree extends React.Component { this.clearSelectedNode = callbacks.clearSelectedNode.bind(this); // this.handleIconClickHOF = callbacks.handleIconClickHOF.bind(this); this.redrawTree = () => { - this.props.dispatch({ type: CHANGE_TREE_ZOOM, data: "even" }); + this.props.dispatch({ type: CHANGE_TREE_FOCUS, data: "even" }); this.props.dispatch(updateVisibleTipsAndBranchThicknesses({ root: [0, 0] })); @@ -112,9 +112,17 @@ class Tree extends React.Component { } getStyles = () => { - // FIXME: double-check this - const activeResetTreeButton = true; - const activeZoomButton = true; + const activeResetTreeButton = this.props.tree.idxOfInViewRootNode !== 0 || + this.props.treeToo.idxOfInViewRootNode !== 0; + + const filteredTree = !!this.props.tree.idxOfFilteredRoot && + this.props.tree.idxOfInViewRootNode !== this.props.tree.idxOfFilteredRoot; + const filteredTreeToo = !!this.props.treeToo.idxOfFilteredRoot && + this.props.treeToo.idxOfInViewRootNode !== this.props.treeToo.idxOfFilteredRoot; + const activeZoomButton = filteredTree || filteredTreeToo; + + const activeFocusButton = true; + const treeIsZoomed = this.props.tree.idxOfInViewRootNode !== 0 || this.props.treeToo.idxOfInViewRootNode !== 0; @@ -139,6 +147,13 @@ class Tree extends React.Component { color: activeZoomButton ? darkGrey : lightGrey, pointerEvents: activeZoomButton ? "auto" : "none" }, + focusOnSelectedButton: { + zIndex: 100, + display: "inline-block", + cursor: activeFocusButton ? "pointer" : "auto", + color: activeFocusButton ? darkGrey : lightGrey, + pointerEvents: activeFocusButton ? "auto" : "none" + }, zoomOutButton: { zIndex: 100, display: "inline-block", @@ -162,20 +177,23 @@ class Tree extends React.Component { ); } - zoomToSelected = () => { - // if currently set to "even", start at "zoom" - let treeZoomData = "zoom"; - if (this.props.treeZoom.includes("zoom")) { - // if currently at "zoom", increment to "zoom-2" - if (!this.props.treeZoom.includes("-")) { - treeZoomData = "zoom-2"; + focusOnSelected = () => { + // if currently set to "even", start at "focus" + let treeFocusData = "focus"; + if (this.props.treeFocus.includes("focus")) { + // if currently at "focus", increment to "focus-2" + if (!this.props.treeFocus.includes("-")) { + treeFocusData = "focus-2"; } else { - // if currently at "zoom-2", increment to "zoom-3", etc... - const increment = parseInt(this.props.treeZoom.split('-')[1], 10) + 1; - treeZoomData = "zoom-" + increment.toString(); + // if currently at "focus-2", increment to "focus-3", etc... + const increment = parseInt(this.props.treeFocus.split('-')[1], 10) + 1; + treeFocusData = "focus-" + increment.toString(); } } - this.props.dispatch({ type: CHANGE_TREE_ZOOM, data: treeZoomData }); + this.props.dispatch({ type: CHANGE_TREE_FOCUS, data: treeFocusData }); + }; + + zoomToSelected = () => { this.props.dispatch(updateVisibleTipsAndBranchThicknesses({ root: [this.props.tree.idxOfFilteredRoot, this.props.treeToo.idxOfFilteredRoot] })); @@ -266,6 +284,12 @@ class Tree extends React.Component { > {t("Zoom to Selected")} +