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

Restore terminal branch hover/click behaviour #1753

Merged
merged 4 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Changelog

## version 2.52.0 - 2024/02/09

* Bugfix: Restore the intended behaviour when hovering or clicking on terminal branches. ([#1753](https://github.com/nextstrain/auspice/pull/1753))

## version 2.52.0 - 2024/02/09

* Sidebar filtering now contains all non-continuous metadata defined across the tree (i.e. all data within `node.node_attrs`). The traits listed in `meta.filters` are now only used to determine which filters to list in the footer of the page. ([#1743](https://github.com/nextstrain/auspice/pull/1743))
* The interaction between strain-selected modals and the corresponding strain-filter has been improved. We now preserve the strain filter state present before the node was clicked. ([#1749](https://github.com/nextstrain/auspice/issues/1749))
Expand Down
18 changes: 10 additions & 8 deletions src/components/tree/infoPanels/click.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,31 +247,33 @@ const NodeClickedPanel = ({selectedNode, nodes, clearSelectedNode, colorings, ob
const panelStyle = { ...infoPanelStyles.panel};
panelStyle.maxHeight = "70%";
const isTerminal = !node.hasChildren;
const title = isTerminal ?
const isTip = !selectedNode.isBranch;

const title = isTip ?
node.name :
isTerminal ?
`Branch leading to ${node.name}` :
"Internal branch";

return (
<div style={infoPanelStyles.modalContainer} onClick={() => clearSelectedNode(selectedNode, isTerminal)}>
<div style={infoPanelStyles.modalContainer} onClick={() => clearSelectedNode(selectedNode)}>
<div className={"panel"} style={panelStyle} onClick={(e) => stopProp(e)}>
<StrainName>{title}</StrainName>
<table>
<tbody>
{!isTerminal && item(t("Number of terminal tips"), node.fullTipCount)}
{isTerminal && <VaccineInfo node={node} t={t}/>}
{!isTip && item(t("Number of terminal tips"), node.fullTipCount)}
{isTip && <VaccineInfo node={node} t={t}/>}
<SampleDate isTerminal={isTerminal} node={node} t={t}/>
{!isTerminal && item("Node name", node.name)}
{isTerminal && <PublicationInfo node={node} t={t}/>}
{!isTip && item("Node name", node.name)}
{isTip && <PublicationInfo node={node} t={t}/>}
{getTraitsToDisplay(node).map((trait) => (
<Trait node={node} trait={trait} colorings={colorings} key={trait} isTerminal={isTerminal}/>
))}
{isTerminal && <AccessionAndUrl node={node}/>}
{isTip && <AccessionAndUrl node={node}/>}
{item("", "")}
</tbody>
</table>
<MutationTable node={node} geneSortFn={geneSortFn} isTip={isTerminal} observedMutations={observedMutations}/>
<MutationTable node={node} geneSortFn={geneSortFn} isTip={isTip} observedMutations={observedMutations}/>
<p style={infoPanelStyles.comment}>
{t("Click outside this box to go back to the tree")}
</p>
Expand Down
5 changes: 3 additions & 2 deletions src/components/tree/infoPanels/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,12 @@ const HoverInfoPanel = ({
t
}) => {
if (!selectedNode) return null
const node = selectedNode.n;
const node = selectedNode.node.n; // want the redux node, not the phylo node
const idxOfInViewRootNode = getIdxOfInViewRootNode(node);

return (
<Container node={node} panelDims={panelDims}>
{node.hasChildren===false ? (
{selectedNode.isBranch===false ? (
<>
<StrainName name={node.name}/>
<VaccineInfo node={node} t={t}/>
Expand Down
16 changes: 10 additions & 6 deletions src/components/tree/reactD3Interface/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export const onTipHover = function onTipHover(d) {
this.state.treeToo;
phylotree.svg.select("#"+getDomId("tip", d.n.name))
.attr("r", (e) => e["r"] + 4);
this.setState({hoveredNode: d});
this.setState({
hoveredNode: {node: d, isBranch: false}
});
};

export const onTipClick = function onTipClick(d) {
Expand All @@ -22,7 +24,7 @@ export const onTipClick = function onTipClick(d) {
/* The order of these two dispatches is important: the reducer handling
`SELECT_NODE` must have access to the filtering state _prior_ to these filters
being applied */
this.props.dispatch({type: SELECT_NODE, name: d.n.name, idx: d.n.arrayIdx});
this.props.dispatch({type: SELECT_NODE, name: d.n.name, idx: d.n.arrayIdx, isBranch: false});
this.props.dispatch(applyFilter("add", strainSymbol, [d.n.name]));
};

Expand All @@ -46,7 +48,9 @@ export const onBranchHover = function onBranchHover(d) {
}

/* Set the hovered state so that an info box can be displayed */
this.setState({hoveredNode: d});
this.setState({
hoveredNode: {node: d, isBranch: true}
});
};

export const onBranchClick = function onBranchClick(d) {
Expand All @@ -56,7 +60,7 @@ export const onBranchClick = function onBranchClick(d) {
/* if a branch was clicked while holding the shift key, we instead display a node-clicked modal */
if (window.event.shiftKey) {
// no need to dispatch a filter action
this.props.dispatch({type: SELECT_NODE, name: d.n.name, idx: d.n.arrayIdx})
this.props.dispatch({type: SELECT_NODE, name: d.n.name, idx: d.n.arrayIdx, isBranch: true})
return;
}

Expand Down Expand Up @@ -120,8 +124,8 @@ export const onTipLeave = function onTipLeave(d) {
};

/* clearSelectedNode when clicking to remove the node-selected modal */
export const clearSelectedNode = function clearSelectedNode(selectedNode, isTerminal) {
if (isTerminal) {
export const clearSelectedNode = function clearSelectedNode(selectedNode) {
if (!selectedNode.isBranch) {
/* perform the filtering action (if necessary) that will restore the
filtering state of the node prior to the selection */
if (!selectedNode.existingFilterState) {
Expand Down
5 changes: 1 addition & 4 deletions src/components/tree/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ class Tree extends React.Component {
/* pressing the escape key should dismiss an info modal (if one exists) */
this.handlekeydownEvent = (event) => {
if (event.key==="Escape" && this.props.selectedNode) {
this.clearSelectedNode(
this.props.selectedNode,
!this.props.tree.nodes[this.props.selectedNode.idx].hasChildren
);
this.clearSelectedNode(this.props.selectedNode);
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/reducers/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const Controls = (state: ControlsState = getDefaultControlsState(), action): Con
const existingFilterInfo = (state.filters?.[strainSymbol]||[]).find((info) => info.value===action.name);
const existingFilterState = existingFilterInfo === undefined ? null :
existingFilterInfo.active ? 'active' : 'inactive';
return {...state, selectedNode: {name: action.name, idx: action.idx, existingFilterState}};
return {...state, selectedNode: {name: action.name, idx: action.idx, existingFilterState, isBranch: action.isBranch}};
}
case types.DESELECT_NODE: {
return {...state, selectedNode: null}
Expand Down
Loading