diff --git a/src/components/tree/index.ts b/src/components/tree/index.ts index 07218e725..2e08f3303 100644 --- a/src/components/tree/index.ts +++ b/src/components/tree/index.ts @@ -30,7 +30,8 @@ const Tree = connect((state: RootState) => ({ tipLabelKey: state.controls.tipLabelKey, narrativeMode: state.narrative.display, animationPlayPauseButton: state.controls.animationPlayPauseButton, - showOnlyPanels: state.controls.showOnlyPanels + showOnlyPanels: state.controls.showOnlyPanels, + performanceToggles: state.controls.performanceToggles, }))(UnconnectedTree); export default Tree; diff --git a/src/components/tree/phyloTree/change.js b/src/components/tree/phyloTree/change.js index 78fd96e1d..51a18d3cb 100644 --- a/src/components/tree/phyloTree/change.js +++ b/src/components/tree/phyloTree/change.js @@ -99,15 +99,12 @@ const createUpdateCall = (treeElem, properties) => (selection) => { const genericSelectAndModify = (svg, treeElem, updateCall, transitionTime) => { // console.log("general svg update for", treeElem); - svg.selectAll(treeElem) - .filter((d) => d.update) - .transition().duration(transitionTime) - .call(updateCall); - if (!transitionTime) { - /* https://github.com/d3/d3-timer#timerFlush */ - timerFlush(); - // console.log("\t\t--FLUSHING TIMER--"); + let selection = svg.selectAll(treeElem) + .filter((d) => d.update); + if (transitionTime) { + selection = selection.transition().duration(transitionTime); } + selection.call(updateCall); }; /* use D3 to select and modify elements, such that a given element is only ever modified _once_ @@ -271,7 +268,8 @@ export const change = function change({ branchThickness = undefined, /* other data */ focus = undefined, - scatterVariables = undefined + scatterVariables = undefined, + performanceToggles = {}, }) { // console.log("\n** phylotree.change() (time since last run:", Date.now() - this.timeLastRenderRequested, "ms) **\n\n"); timerStart("phylotree.change()"); @@ -280,10 +278,11 @@ export const change = function change({ 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. */ + /* calculate dt */ const idealTransitionTime = 500; let transitionTime = idealTransitionTime; - if ((Date.now() - this.timeLastRenderRequested) < idealTransitionTime * 2) { + if ((Date.now() - this.timeLastRenderRequested) < idealTransitionTime * 2 || performanceToggles.get("skipTreeAnimation")===true) { transitionTime = 0; } diff --git a/src/components/tree/phyloTree/labels.js b/src/components/tree/phyloTree/labels.js index 31fe9db88..41d0ca35e 100644 --- a/src/components/tree/phyloTree/labels.js +++ b/src/components/tree/phyloTree/labels.js @@ -1,4 +1,3 @@ -import { timerFlush } from "d3-timer"; import { NODE_VISIBLE } from "../../../util/globals"; import { numericToDateObject, prettifyDate } from "../../../util/dateHelpers"; import { getTraitFromNode } from "../../../util/treeMiscHelpers"; @@ -108,16 +107,16 @@ export const updateBranchLabels = function updateBranchLabels(dt) { ); const labelSize = branchLabelSize(this.params.branchLabelKey); const fontWeight = branchLabelFontWeight(this.params.branchLabelKey); - this.groups.branchLabels + let selection = this.groups.branchLabels .selectAll(".branchLabel") - .transition() - .duration(dt) - .attr("x", (d) => d.xTip - 5) + if (dt) { + selection = selection.transition().duration(dt); + } + selection.attr("x", (d) => d.xTip - 5) .attr("y", (d) => d.yTip - this.params.branchLabelPadY) .style("visibility", visibility) .style("font-weight", fontWeight) .style("font-size", labelSize); - if (!dt) timerFlush(); }; export const removeBranchLabels = function removeBranchLabels() { diff --git a/src/components/tree/reactD3Interface/change.js b/src/components/tree/reactD3Interface/change.js index 67a3b6707..d63a292ab 100644 --- a/src/components/tree/reactD3Interface/change.js +++ b/src/components/tree/reactD3Interface/change.js @@ -127,6 +127,7 @@ export const changePhyloTreeViaPropsComparison = (mainTree, phylotree, oldProps, const change = Object.keys(args).length; if (change) { args.animationInProgress = newProps.animationPlayPauseButton === "Pause"; + args.performanceToggles = newProps.performanceToggles; // console.log('\n\n** ', phylotree.id, 'changePhyloTreeViaPropsComparison **', args); phylotree.change(args); } diff --git a/src/middleware/performanceToggles.js b/src/middleware/performanceToggles.js new file mode 100644 index 000000000..86950b26d --- /dev/null +++ b/src/middleware/performanceToggles.js @@ -0,0 +1,28 @@ +import * as types from "../actions/types"; + +/** + * Performance toggles (reduxState.controls.performanceToggles) represent flags + * for which we enable/disable certain functionality in Auspice. These flags + * shouldn't be depended on, i.e. Auspice should work just fine without them + * (but may be a little slow). + */ + + +export const performanceToggles = (_store) => (next) => (action) => { + let modifiedAction; + switch (action.type) { + case types.URL_QUERY_CHANGE_WITH_COMPUTED_STATE: /* fallthrough */ + case types.CLEAN_START: { + modifiedAction = {...action}; + modifiedAction.controls.performanceToggles = calculate(action) + } + } + return next(modifiedAction || action); // send action to other middleware / reducers +}; + +function calculate({tree}) { + const toggles = new Map(); + const totalTipCount = tree?.nodes?.[0]?.fullTipCount; + toggles.set("skipTreeAnimation", totalTipCount > 4000); + return toggles; +} \ No newline at end of file diff --git a/src/reducers/controls.ts b/src/reducers/controls.ts index 5fc96bb77..d9f080d53 100644 --- a/src/reducers/controls.ts +++ b/src/reducers/controls.ts @@ -139,7 +139,8 @@ export const getDefaultControlsState = () => { measurementsDisplay: undefined, measurementsShowOverallMean: undefined, measurementsShowThreshold: undefined, - measurementsFilters: {} + measurementsFilters: {}, + performanceToggles: new Map(), }; }; diff --git a/src/store.ts b/src/store.ts index 4943b23ae..efa6d214f 100644 --- a/src/store.ts +++ b/src/store.ts @@ -3,10 +3,12 @@ import { changeURLMiddleware } from "./middleware/changeURL"; import rootReducer from "./reducers"; // import { loggingMiddleware } from "./middleware/logActions"; import { keepScatterplotStateInSync } from "./middleware/scatterplot"; +import { performanceToggles } from "./middleware/performanceToggles"; const middleware = [ keepScatterplotStateInSync, changeURLMiddleware, + performanceToggles, // loggingMiddleware ];