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

Animation refactor #377

Merged
merged 11 commits into from
Jul 10, 2017
67 changes: 22 additions & 45 deletions src/components/map/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
/*eslint max-len: 0*/
import React from "react";
import d3 from "d3";
import _ from "lodash";
import { connect } from "react-redux";
import Card from "../framework/card";
import {changeDateFilter} from "../../actions/treeProperties";
Expand All @@ -25,18 +24,16 @@ import {
// datasetGuid: state.tree.datasetGuid,
treeVersion: state.tree.version,
treeLoaded: state.tree.loaded,
controls: state.controls,
splitTreeAndMap: state.controls.splitTreeAndMap,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is way cleaner

nodes: state.tree.nodes,
nodeColors: state.tree.nodeColors,
visibility: state.tree.visibility,
visibilityVersion: state.tree.visibilityVersion,
metadata: state.metadata.metadata,
browserDimensions: state.browserDimensions.browserDimensions,
colorScaleVersion: state.controls.colorScale.version,
colorBy: state.controls.colorBy,
map: state.map,
geoResolution: state.controls.geoResolution,
// mapAnimationStartDate: state.controls.mapAnimationStartDate,
mapAnimationDurationInMilliseconds: state.controls.mapAnimationDurationInMilliseconds,
mapAnimationCumulative: state.controls.mapAnimationCumulative,
mapAnimationPlayPauseButton: state.controls.mapAnimationPlayPauseButton,
Expand Down Expand Up @@ -138,7 +135,7 @@ class Map extends React.Component {
}
doComputeResponsive(nextProps) {
return computeResponsive({
horizontal: nextProps.browserDimensions.width > twoColumnBreakpoint && (this.props.controls && this.props.controls.splitTreeAndMap) ? .5 : 1,
horizontal: nextProps.browserDimensions.width > twoColumnBreakpoint && (this.props.splitTreeAndMap) ? .5 : 1,
vertical: 1.0, /* if we are in single column, full height */
browserDimensions: nextProps.browserDimensions,
sidebar: nextProps.sidebar,
Expand Down Expand Up @@ -189,7 +186,8 @@ class Map extends React.Component {
this.state.d3DOMNode,
this.state.map,
this.props.nodes,
this.props.controls
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMin),
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMax)
);

/* Set up leaflet events */
Expand Down Expand Up @@ -243,7 +241,13 @@ class Map extends React.Component {
}
respondToLeafletEvent(leafletEvent) {
if (leafletEvent.type === "moveend") { /* zooming and panning */
updateOnMoveEnd(this.state.d3elems, this.latLongs(), this.props.controls, this.props.nodes);
updateOnMoveEnd(
this.state.d3elems,
this.latLongs(),
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMin),
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMax),
this.props.nodes
);
}
}
getGeoRange() {
Expand Down Expand Up @@ -279,7 +283,13 @@ class Map extends React.Component {
) {
const latLongs = this.latLongs(); /* can't run if noMap || noDemes */
if (latLongs === null) { return; }
updateVisibility(this.state.d3elems, latLongs, this.props.controls, this.props.nodes);
updateVisibility(
this.state.d3elems,
latLongs,
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMin),
calendarToNumeric(this.props.dateFormat, this.props.dateScale, this.props.dateMax),
this.props.nodes
);
}
}
// maybeAnimateDemesAndTransmissions() {
Expand All @@ -292,7 +302,6 @@ class Map extends React.Component {
this.props.visibility,
this.props.metadata,
this.state.map,
this.props.colorBy,
this.props.geoResolution,
this.props.mapTriplicate,
this.props.nodeColors,
Expand All @@ -306,8 +315,8 @@ class Map extends React.Component {

/* initial map bounds */
if (this.props.mapTriplicate === true) {
southWest = L.latLng(-70, -540);
northEast = L.latLng(80, 540);
southWest = L.latLng(-70, -360);
northEast = L.latLng(80, 360);
} else {
southWest = L.latLng(-70, -180);
northEast = L.latLng(80, 180);
Expand Down Expand Up @@ -414,11 +423,11 @@ class Map extends React.Component {
* ANIMATE MAP (AND THAT LINE ON TREE)
*****************************************/
if (this.props.mapAnimationPlayPauseButton === "Play") {
this.animateMap();
this.props.dispatch({
type: MAP_ANIMATION_PLAY_PAUSE_BUTTON,
data: "Pause"
});
this.animateMap();
} else {
clearInterval(window.NEXTSTRAIN.mapAnimationLoop)
window.NEXTSTRAIN.mapAnimationLoop = null;
Expand All @@ -432,7 +441,7 @@ class Map extends React.Component {
resetAnimation() {
clearInterval(window.NEXTSTRAIN.mapAnimationLoop);
window.NEXTSTRAIN.mapAnimationLoop = null;
this.props.dispatch(changeDateFilter({newMin: this.props.controls.absoluteDateMin, newMax: this.props.controls.absoluteDateMax}));
this.props.dispatch(changeDateFilter({newMin: this.props.absoluteDateMin, newMax: this.props.absoluteDateMax}));
this.props.dispatch({
type: MAP_ANIMATION_PLAY_PAUSE_BUTTON,
data: "Play"
Expand Down Expand Up @@ -488,38 +497,6 @@ class Map extends React.Component {
}
}, animationTick);

// controls: state.controls,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can stay, I will clean up on the requestAnimationFrame pass

// this.props.dateMin //"2013-06-28"
// this.props.dateMax //"2016-11-21"
// this.props.absoluteDateMin //"2013-06-29"
// this.props.absoluteDateMax //"2016-11-21"
// export const CHANGE_DATE_MIN = "CHANGE_DATE_MIN";
// export const CHANGE_DATE_MAX = "CHANGE_DATE_MAX";
// export const CHANGE_ABSOLUTE_DATE_MIN = "CHANGE_ABSOLUTE_DATE_MIN";
// export const CHANGE_ABSOLUTE_DATE_MAX = "CHANGE_ABSOLUTE_DATE_MAX";

// =======OLD RAF CODE=======
// let start = null;
//
// const step = (timestamp) => {
// if (!start) start = timestamp;
//
// let progress = timestamp - start;
//
// this.props.dispatch({
// type: MAP_ANIMATION_TICK,
// data: {
// progress
// }
// })
//
// if (progress < globals.mapAnimationDurationInMilliseconds) {
// window.requestAnimationFrame(step);
// } else {
// this.props.dispatch({ type: MAP_ANIMATION_END })
// }
// }
// window.requestAnimationFrame(step);
}
render() {
// clear layers - store all markers in map state https://github.com/Leaflet/Leaflet/issues/3238#issuecomment-77061011
Expand Down
81 changes: 41 additions & 40 deletions src/util/mapHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const pathStringGenerator = d3.svg.line()
.y((d) => { return d.y })
.interpolate("basis");

export const drawDemesAndTransmissions = (latLongs, g, map, nodes, controls) => {
export const drawDemesAndTransmissions = (latLongs, g, map, nodes, numDateMin, numDateMax) => {

// define markers that are appended to the definition part of the group
let markerCount=0;
Expand Down Expand Up @@ -114,7 +114,8 @@ export const drawDemesAndTransmissions = (latLongs, g, map, nodes, controls) =>
return pathStringGenerator(
extractLineSegmentForAnimationEffect(
d.data.originToDestinationXYs,
controls,
numDateMin,
numDateMax,
d,
nodes,
i,
Expand All @@ -129,34 +130,34 @@ export const drawDemesAndTransmissions = (latLongs, g, map, nodes, controls) =>
.attr("stroke-width", (d) => { return d.data.total }) /* scale line by total number of transmissions */
// .attr("marker-mid", makeMarker);

let transmissionPathLengths = [];
transmissions[0].forEach((d, i) => {

/* https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength */
const totalPathLength = d.getTotalLength();

/*
1. Here, we make a mapping between time and geographic position for the transmission.
2. In short, make the line visible in proportion to the user selected date range, which
may not include the entire length of the line.
3. .clamp(true)
never return a value outside the date range
this would put the transmission path outside the geographic target
*/

const pathScale = d3.scale.linear()
.domain([
nodes[latLongs.transmissions[i].data.demePairIndices[0]].attr.num_date, /* origin date */
nodes[latLongs.transmissions[i].data.demePairIndices[1]].attr.num_date /* destination date */
])
.range([0, totalPathLength])
.clamp(true);

transmissionPathLengths.push({
totalPathLength,
pathScale,
})
})
// let transmissionPathLengths = [];
// transmissions[0].forEach((d, i) => {
//
// /* https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength */
// const totalPathLength = d.getTotalLength();
//
// /*
// 1. Here, we make a mapping between time and geographic position for the transmission.
// 2. In short, make the line visible in proportion to the user selected date range, which
// may not include the entire length of the line.
// 3. .clamp(true)
// never return a value outside the date range
// this would put the transmission path outside the geographic target
// */
//
// const pathScale = d3.scale.linear()
// .domain([
// nodes[latLongs.transmissions[i].data.demePairIndices[0]].attr.num_date, /* origin date */
// nodes[latLongs.transmissions[i].data.demePairIndices[1]].attr.num_date /* destination date */
// ])
// .range([0, totalPathLength])
// .clamp(true);
//
// transmissionPathLengths.push({
// totalPathLength,
// pathScale,
// })
// })

const demes = g.selectAll("demes")
.data(latLongs.demes)
Expand All @@ -172,12 +173,12 @@ export const drawDemesAndTransmissions = (latLongs, g, map, nodes, controls) =>
return {
demes,
transmissions,
transmissionPathLengths
// transmissionPathLengths
};

}

export const updateOnMoveEnd = (d3elems, latLongs, controls, nodes) => {
export const updateOnMoveEnd = (d3elems, latLongs, numDateMin, numDateMax, nodes) => {
/* map has moved or rescaled, make demes and transmissions line up */
if (d3elems) {
d3elems.demes
Expand All @@ -192,7 +193,8 @@ export const updateOnMoveEnd = (d3elems, latLongs, controls, nodes) => {
return pathStringGenerator(
extractLineSegmentForAnimationEffect(
d.data.originToDestinationXYs,
controls,
numDateMin,
numDateMax,
d,
nodes,
i,
Expand All @@ -203,15 +205,13 @@ export const updateOnMoveEnd = (d3elems, latLongs, controls, nodes) => {
}
}

const extractLineSegmentForAnimationEffect = (pair, controls, d, nodes, i, minTransmissionDate) => {
const extractLineSegmentForAnimationEffect = (pair, numDateMin, numDateMax, d, nodes, i, minTransmissionDate) => {
const originDate = nodes[d.data.demePairIndices[0]].attr.num_date;
const destinationDate = nodes[d.data.demePairIndices[1]].attr.num_date;
const userDateMin = controls.dateScale(controls.dateFormat.parse(controls.dateMin));
const userDateMax = controls.dateScale(controls.dateFormat.parse(controls.dateMax));

/* manually find the points along a Bezier curve at which we should be given the user date selection */
let start = Math.max(0.0,(userDateMin-originDate)/(destinationDate-originDate)); // clamp start at 0.0 if userDateMin gives a number <0
let end = Math.min(1.0,(userDateMax-originDate)/(destinationDate-originDate));// clamp end at 1.0 if userDateMax gives a number >1
let start = Math.max(0.0,(numDateMin-originDate)/(destinationDate-originDate)); // clamp start at 0.0 if userDateMin gives a number <0
let end = Math.min(1.0,(numDateMax-originDate)/(destinationDate-originDate));// clamp end at 1.0 if userDateMax gives a number >1

if (!_.isFinite(start)){ // For 0 branch-length transmissions, (destinationDate-originDate) is 0 --> +/- Infinity values for start and end.
start = 0.0;
Expand All @@ -227,7 +227,7 @@ const extractLineSegmentForAnimationEffect = (pair, controls, d, nodes, i, minTr



export const updateVisibility = (d3elems, latLongs, controls, nodes) => {
export const updateVisibility = (d3elems, latLongs, numDateMin, numDateMax, nodes) => {

d3elems.demes
.data(latLongs.demes)
Expand All @@ -244,7 +244,8 @@ export const updateVisibility = (d3elems, latLongs, controls, nodes) => {
return pathStringGenerator(
extractLineSegmentForAnimationEffect(
d.data.originToDestinationXYs,
controls,
numDateMin,
numDateMax,
d,
nodes,
i,
Expand Down
Loading