Skip to content

Commit

Permalink
[tmp] prototype temporal zoom
Browse files Browse the repository at this point in the history
.
  • Loading branch information
jameshadfield committed Jun 30, 2022
1 parent 483ae25 commit 48dc982
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ export const TOGGLE_MEASUREMENTS_OVERALL_MEAN = "TOGGLE_MEASUREMENTS_OVERALL_MEA
export const CHANGE_MEASUREMENTS_DISPLAY = "CHANGE_MEASUREMENTS_DISPLAY";
export const APPLY_MEASUREMENTS_FILTER = "APPLY_MEASUREMENTS_FILTER";
export const UPDATE_MEASUREMENTS_ERROR = "UPDATE_MEASUREMENTS_ERROR";
export const TOGGLE_TEMPORAL_ZOOM_FLAG = "TOGGLE_TEMPORAL_ZOOM_FLAG";
32 changes: 32 additions & 0 deletions src/components/controls/choose-zoom-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { connect } from "react-redux";
import { withTranslation } from "react-i18next";

import Toggle from "./toggle";
import { controlsWidth } from "../../util/globals";
import { TOGGLE_TEMPORAL_ZOOM_FLAG } from "../../actions/types";

@connect((state) => {
return {
treeZoomsTemporally: state.controls.treeZoomsTemporally
};
})
class ChooseZoomMode extends React.Component {
render() {
const { t } = this.props;
return (
<div style={{marginBottom: 10, width: controlsWidth, fontSize: 14}}>
<Toggle
display
on={this.props.treeZoomsTemporally}
callback={() => {
this.props.dispatch({ type: TOGGLE_TEMPORAL_ZOOM_FLAG });
}}
label={t("sidebar:Zoom Temporally")}
/>
</div>
);
}
}

export default withTranslation()(ChooseZoomMode);
2 changes: 2 additions & 0 deletions src/components/controls/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {TreeOptionsInfo, MapOptionsInfo, AnimationOptionsInfo, PanelOptionsInfo,
ExplodeTreeInfo, FrequencyInfo, MeasurementsOptionsInfo} from "./miscInfoText";
import { AnnotatedHeader } from "./annotatedHeader";
import MeasurementsOptions from "./measurementsOptions";
import ChooseZoomMode from "./choose-zoom-mode";

function Controls({mapOn, frequenciesOn, measurementsOn, mobileDisplay}) {
const { t } = useTranslation();
Expand All @@ -44,6 +45,7 @@ function Controls({mapOn, frequenciesOn, measurementsOn, mobileDisplay}) {
<FilterData measurementsOn={measurementsOn} />

<AnnotatedHeader title={t("sidebar:Tree Options")} tooltip={TreeOptionsInfo} mobile={mobileDisplay}/>
<ChooseZoomMode />
<ChooseLayout />
<ChooseMetric />
<ChooseExplodeAttr tooltip={ExplodeTreeInfo} mobile={mobileDisplay} />
Expand Down
3 changes: 2 additions & 1 deletion src/components/tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ const Tree = connect((state) => ({
canRenderBranchLabels: state.controls.canRenderBranchLabels,
tipLabelKey: state.controls.tipLabelKey,
narrativeMode: state.narrative.display,
animationPlayPauseButton: state.controls.animationPlayPauseButton
animationPlayPauseButton: state.controls.animationPlayPauseButton,
treeZoomsTemporally: state.controls.treeZoomsTemporally
}))(UnconnectedTree);

export default Tree;
17 changes: 11 additions & 6 deletions src/components/tree/phyloTree/change.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const modifySVG = function modifySVG(elemsToUpdate, svgPropsToUpdate, tra
}

/* background temporal time slice */
if (extras.timeSliceHasPotentiallyChanged) {
if (extras.timeSliceHasPotentiallyChanged || (extras.newZoomMode!==undefined)) {
this.showTemporalSlice();
}

Expand Down Expand Up @@ -258,6 +258,7 @@ export const change = function change({
/* change these things to provided value (unless undefined) */
newDistance = undefined,
newLayout = undefined,
newZoomMode = undefined,
updateLayout = undefined, // todo - this seems identical to `newLayout`
newBranchLabellingKey = undefined,
newTipLabelKey = undefined,
Expand All @@ -277,6 +278,8 @@ export const change = function change({
const nodePropsToModify = {}; /* which properties (keys) on the nodes should be updated (before the SVG) */
const svgPropsToUpdate = new Set(); /* which SVG properties shall be changed. E.g. "fill", "stroke" */
const useModifySVGInStages = newLayout; /* use modifySVGInStages rather than modifySVG. Not used often. */
const timeSliceHasPotentiallyChanged = changeVisibility || newDistance;
if (newZoomMode!==undefined) this.treeZoomsTemporally = newZoomMode;

/* calculate dt */
const idealTransitionTime = 500;
Expand Down Expand Up @@ -312,7 +315,8 @@ export const change = function change({
svgPropsToUpdate.add("stroke-width");
nodePropsToModify["stroke-width"] = branchThickness;
}
if (newDistance || newLayout || updateLayout || zoomIntoClade || svgHasChangedDimensions || changeNodeOrder) {
if (newDistance || newLayout || updateLayout || zoomIntoClade || (newZoomMode!==undefined) ||
svgHasChangedDimensions || changeNodeOrder || timeSliceHasPotentiallyChanged) {
elemsToUpdate.add(".tip").add(".branch.S").add(".branch.T").add(".branch");
elemsToUpdate.add(".vaccineCross").add(".vaccineDottedLine").add(".conf");
elemsToUpdate.add('.branchLabel').add('.tipLabel');
Expand Down Expand Up @@ -368,13 +372,15 @@ export const change = function change({
/* mapToScreen */
if (
svgPropsToUpdate.has(["stroke-width"]) ||
newDistance ||
newDistance || // technically unnecessary as part of timeSliceHas...
newLayout ||
changeNodeOrder ||
updateLayout ||
zoomIntoClade ||
svgHasChangedDimensions ||
showConfidences
showConfidences ||
(newZoomMode!==undefined) ||
timeSliceHasPotentiallyChanged // TODO could be expensive to run mapToScreen every time here...
) {
this.mapToScreen();
}
Expand All @@ -388,8 +394,7 @@ export const change = function change({
if (svgHasChangedDimensions) {
this.setClipMask();
}
const extras = { removeConfidences, showConfidences, newBranchLabellingKey };
extras.timeSliceHasPotentiallyChanged = changeVisibility || newDistance;
const extras = { removeConfidences, showConfidences, newBranchLabellingKey, timeSliceHasPotentiallyChanged, newZoomMode};
extras.hideTipLabels = animationInProgress;
if (useModifySVGInStages) {
this.modifySVGInStages(elemsToUpdate, svgPropsToUpdate, transitionTime, 1000, extras);
Expand Down
2 changes: 1 addition & 1 deletion src/components/tree/phyloTree/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ export const temporalWindowTransition = transition('temporalWindowTransition')
* add background grey rectangles to demarcate the temporal slice
*/
export const showTemporalSlice = function showTemporalSlice() {
if (this.layout !== "rect" || this.distance !== "num_date") {
if (this.layout !== "rect" || this.distance !== "num_date" || this.treeZoomsTemporally===true) {
this.hideTemporalSlice();
return;
}
Expand Down
13 changes: 13 additions & 0 deletions src/components/tree/phyloTree/layouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,19 @@ export const mapToScreen = function mapToScreen() {
nodesInDomain = nodesInDomain.filter((d) => !d.n.hasChildren);
}

/* experimental -- restrict the nodesInDomain via the time-slice */
if (this.treeZoomsTemporally===true) {
// TODO -- this works for the max time (and viz is intuitive) but for the earliest date (LHS of rect tree)
// we should be a bit smarter.
// Note that branches prior to the date cutoff have no visibility (rendered as thin lines) so it's not just
// a case of changing the tree domain like I'm prototyping here...
const early_cutoff = this.dateRange[0] - 0.1*(this.dateRange[1]-this.dateRange[0]);
nodesInDomain = nodesInDomain.filter((d) => {
const num_date = getTraitFromNode(d.n, 'num_date');
return (num_date > early_cutoff && num_date < this.dateRange[1]);
});
}

/* Compute the domains to pass to the d3 scales for the x & y axes */
let xDomain, yDomain, spanX, spanY;
if (this.layout!=="scatter" || this.scatterVariables.xContinuous) {
Expand Down
3 changes: 2 additions & 1 deletion src/components/tree/phyloTree/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ 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, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii, dateRange, scatterVariables) {
export const render = function render(svg, layout, distance, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii, dateRange, scatterVariables, treeZoomsTemporally) {
timerStart("phyloTree render()");
this.svg = svg;
this.params = Object.assign(this.params, parameters);
this.callbacks = callbacks;
this.vaccines = vaccines ? vaccines.map((d) => d.shell) : undefined;
this.dateRange = dateRange;
this.treeZoomsTemporally = treeZoomsTemporally;

/* set nodes stroke / fill */
this.nodes.forEach((d, i) => {
Expand Down
5 changes: 5 additions & 0 deletions src/components/tree/reactD3Interface/change.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export const changePhyloTreeViaPropsComparison = (mainTree, phylotree, oldProps,
}
}

if (oldProps.treeZoomsTemporally !== newProps.treeZoomsTemporally) {
args.newZoomMode = newProps.treeZoomsTemporally;
args.updateLayout = true; // unsure why this' needed
}

if (oldProps.width !== newProps.width || oldProps.height !== newProps.height) {
args.svgHasChangedDimensions = true;
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/tree/reactD3Interface/initialRender.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const renderTree = (that, main, phylotree, props) => {
treeState.nodeColors.map(getBrighterColor),
treeState.tipRadii, /* might be null */
[props.dateMinNumeric, props.dateMaxNumeric],
props.scatterVariables
props.scatterVariables,
props.treeZoomsTemporally
);
};
4 changes: 4 additions & 0 deletions src/reducers/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const getDefaultControlsState = () => {
showTangle: false,
zoomMin: undefined,
zoomMax: undefined,
treeZoomsTemporally: true,
branchLengthsToDisplay: "divAndDate",
sidebarOpen: initialSidebarState.sidebarOpen,
treeLegendOpen: undefined,
Expand Down Expand Up @@ -123,6 +124,9 @@ const Controls = (state = getDefaultControlsState(), action) => {
explodeAttr: action.explodeAttr,
colorScale: Object.assign({}, state.colorScale, { visibleLegendValues: action.visibleLegendValues })
});
case types.TOGGLE_TEMPORAL_ZOOM_FLAG: {
return Object.assign({}, state, {treeZoomsTemporally: !state.treeZoomsTemporally});
}
case types.CHANGE_BRANCH_LABEL:
return Object.assign({}, state, { selectedBranchLabel: action.value });
case types.CHANGE_LAYOUT:
Expand Down

0 comments on commit 48dc982

Please sign in to comment.