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

[tmp] prototype temporal zoom #1509

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
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