Skip to content

Commit

Permalink
[feature] Improve smoothness of animation for temporalWindow movement
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrosquall committed Mar 5, 2020
1 parent eaa847f commit a95b7ae
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 29 deletions.
53 changes: 34 additions & 19 deletions src/components/tree/phyloTree/grid.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable space-infix-ops */
import { min, max } from "d3-array";
import { transition } from "d3-transition";
import { easeLinear } from "d3-ease";
import { timerStart, timerEnd } from "../../../util/perf";
import { months } from "../../../util/globals";
import { months, animationInterpolationDuration } from "../../../util/globals";
import { numericToCalendar } from "../../../util/dateHelpers";

export const hideGrid = function hideGrid() {
Expand All @@ -19,6 +21,12 @@ export const hideGrid = function hideGrid() {
const addSVGGroupsIfNeeded = (groups, svg) => {
if (!("temporalWindow" in groups)) {
groups.temporalWindow = svg.append("g").attr("id", "temporalWindow");

// Technically rects aren't groups, but store them to avoid searching for them on each "addTemporalSlice" render.
groups.temporalWindowStart = groups.temporalWindow.append('rect')
.attr('class', 'temporalWindowStart');
groups.temporalWindowEnd = groups.temporalWindow.append('rect')
.attr('class', 'temporalWindowEnd');
}
if (!("majorGrid" in groups)) {
groups.majorGrid = svg.append("g").attr("id", "majorGrid");
Expand Down Expand Up @@ -188,7 +196,7 @@ const computeYGridPoints = (ymin, ymax) => {
*/
export const addGrid = function addGrid() {
const layout = this.layout;
addSVGGroupsIfNeeded(this.groups, this.svg);
addSVGGroupsIfNeeded(this.groups, this.svg, this.temporalWindow);
if (layout==="unrooted") return;
timerStart("addGrid");

Expand Down Expand Up @@ -334,17 +342,20 @@ export const addGrid = function addGrid() {
timerEnd("addGrid");
};


export const removeTemporalSlice = function removeTemporalSlice() {
this.groups.temporalWindow.selectAll("*").remove();
};
// d3-transition to ensure both rectangles move at the same rate
export const temporalWindowTransition = transition('temporalWindowTransition')
.duration(animationInterpolationDuration)
.ease(easeLinear); // the underlying animation uses linear interpolation, let's override the default easeCubic

/**
* add background grey rectangles to demarcate the temporal slice
*/
export const addTemporalSlice = function addTemporalSlice() {
this.removeTemporalSlice();
if (this.layout !== "rect" || this.distance !== "num_date") return;
if (this.layout !== "rect" || this.distance !== "num_date") {
this.groups.temporalWindow.style('visibility', 'hidden');
return;
}
this.groups.temporalWindow.style('visibility', 'visible');

const xWindow = [this.xScale(this.dateRange[0]), this.xScale(this.dateRange[1])];
const height = this.yScale.range()[1];
Expand All @@ -357,25 +368,29 @@ export const addTemporalSlice = function addTemporalSlice() {

/* the gray region between the root (ish) and the minimum date */
if (Math.abs(xWindow[0]-rootXPos) > minPxThreshold) { /* don't render anything less than this num of px */
this.groups.temporalWindow.append("rect")
.attr("x", rightHandTree ? xWindow[0] : 0)
.attr("width", rightHandTree ? totalWidth-xWindow[0]: xWindow[0])
.attr("y", 0)
const xEnd_start = rightHandTree ? totalWidth - xWindow[0] : xWindow[0]; // ending X coordinate of the "start" rectangle
const translateX_start = -totalWidth + xEnd_start; // translation distance for starting temporalWindow
this.groups.temporalWindowStart
.attr("height", height)
.attr("fill", fill);
.attr("width", totalWidth)
.attr("fill", fill)
.transition('temporalWindowTransition')
.attr("transform", `translate(${translateX_start},0)`);
}

/* the gray region between the maximum selected date and the last tip */
const startingX = rightHandTree ? this.params.margins.right : xWindow[1];
const xStart_end = rightHandTree ? this.params.margins.right : xWindow[1]; // starting X coordinate of the "end" rectangle
const rectWidth = rightHandTree ?
xWindow[1]-this.params.margins.right :
totalWidth-this.params.margins.right-xWindow[1];
const translateX_end = xStart_end + this.params.margins.left;

if (rectWidth > minPxThreshold) {
this.groups.temporalWindow.append("rect")
.attr("x", startingX)
.attr("width", rectWidth)
.attr("y", 0)
this.groups.temporalWindowEnd
.attr("height", height)
.attr("fill", fill);
.attr("width", totalWidth)
.attr("fill", fill)
.transition('temporalWindowTransition')
.attr("transform", `translate(${translateX_end},0)`);
}
};
21 changes: 11 additions & 10 deletions src/util/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { scaleLinear, scaleSqrt } from "d3-scale";
import { hasExtension, getExtension } from "../util/extensions";

export const colorOptions = {
"country": {"key": "country", "legendTitle": "Country", "menuItem": "country", "type": "discrete"},
"region": {"key": "region", "legendTitle": "Region", "menuItem": "region", "type": "discrete"},
"num_date": {"key": "num_date", "legendTitle": "Sampling date", "menuItem": "date", "type": "continuous"},
"ep": {"key": "ep", "legendTitle": "Epitope Mutations", "menuItem": "epitope mutations", "type": "continuous"},
"ne": {"key": "ne", "legendTitle": "Non-epitope Mutations", "menuItem": "nonepitope mutations", "type": "continuous"},
"rb": {"key": "rb", "legendTitle": "Receptor Binding Mutations", "menuItem": "RBS mutations", "type": "continuous"},
"gt": {"key": "genotype", "legendTitle": "Genotype", "menuItem": "genotype", "type": "discrete"}
country: {key: "country", legendTitle: "Country", menuItem: "country", type: "discrete"},
region: {key: "region", legendTitle: "Region", menuItem: "region", type: "discrete"},
num_date: {key: "num_date", legendTitle: "Sampling date", menuItem: "date", type: "continuous"},
ep: {key: "ep", legendTitle: "Epitope Mutations", menuItem: "epitope mutations", type: "continuous"},
ne: {key: "ne", legendTitle: "Non-epitope Mutations", menuItem: "nonepitope mutations", type: "continuous"},
rb: {key: "rb", legendTitle: "Receptor Binding Mutations", menuItem: "RBS mutations", type: "continuous"},
gt: {key: "genotype", legendTitle: "Genotype", menuItem: "genotype", type: "discrete"}
};

/* static for now, then hand rolled version of https://github.com/digidem/react-dimensions */
Expand All @@ -29,7 +29,7 @@ export const defaultDistanceMeasure = "num_date";
export const defaultDateRange = 6;
export const date_select = true;
export const file_prefix = "Zika_";
export const restrictTo = {"region": "all"};
export const restrictTo = {region: "all"};
export const time_window = 3.0;
export const fullDataTimeWindow = 1.5;
export const time_ticks = [2013.0, 2013.5, 2014.0, 2014.5, 2015.0, 2015.5, 2016.0];
Expand Down Expand Up @@ -63,6 +63,7 @@ export const slowTransitionDuration = 1400; // in milliseconds
export const animationWindowWidth = 0.075; // width of animation window relative to date slider
export const minDistanceDateSlider = 0.075;
export const animationTick = 50; // animation tick in milliseconds
export const animationInterpolationDuration = 10; // how long d3 temporalWindow transitions last in milliseconds. Must be shorter than animationTick.
export const HIColorDomain = genericDomain.map((d) => {
return Math.round(100 * (d * 3.6)) / 100;
});
Expand Down Expand Up @@ -130,8 +131,8 @@ export const colors = [
["#511EA8", "#4928B4", "#4334BF", "#4041C7", "#3F50CC", "#3F5ED0", "#416CCE", "#4379CD", "#4784C7", "#4B8FC1", "#5098B9", "#56A0AF", "#5CA7A4", "#63AC99", "#6BB18E", "#73B583", "#7CB878", "#86BB6E", "#90BC65", "#9ABD5C", "#A4BE56", "#AFBD4F", "#B9BC4A", "#C2BA46", "#CCB742", "#D3B240", "#DAAC3D", "#DFA43B", "#E39B39", "#E68F36", "#E68234", "#E67431", "#E4632E", "#E1512A", "#DF4027", "#DC2F24"]
];

export const filterAbbrFwd = {"geo": "geographic location", "all": "all"};
export const filterAbbrRev = {"geographic location": "geo", "all": "all"};
export const filterAbbrFwd = {geo: "geographic location", all: "all"};
export const filterAbbrRev = {"geographic location": "geo", all: "all"};

export const titleColors = ["#4377CD", "#5097BA", "#63AC9A", "#7CB879", "#9ABE5C", "#B9BC4A", "#D4B13F", "#E49938", "#E67030", "#DE3C26"];
export const notificationDuration = 10000;
Expand Down

0 comments on commit a95b7ae

Please sign in to comment.