Skip to content

Instantly share code, notes, and snippets.

@virusvn
Forked from delfrrr/background.js
Created May 31, 2017 05:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save virusvn/2a97cdb9fb2248bea75c3337b2d067fa to your computer and use it in GitHub Desktop.
Save virusvn/2a97cdb9fb2248bea75c3337b2d067fa to your computer and use it in GitHub Desktop.
react-native requestAnimationFrame and d3-interpolate
//this is an example of background animation from my weather comparsion app
//you can get early build of app at http://zowni.com
//full source of background.js below
const React = require('react');
const Svg = React.createFactory(require('react-native-svg').Svg);
const {interpolate} = require('d3-interpolate');
//...
/**
* functions which returns color stop
* @returns {string[][]} colors
*/
function getStops(hourly, hourRange, useApparentTemperature) {
//...
}
React.createClass({
getInitialState() {
const {hourly, hourRange, useApparentTemperature} = this.props;
return {
stops: getStops(hourly, hourRange, useApparentTemperature)
};
},
componentWillReceiveProps(props) {
const {
hourly,
hourRange,
useApparentTemperature
} = props;
//create interpolator which will interpolate object (array of color stops this time)
//between current state and new state
const interpolator = interpolate(
this.state,
{stops: getStops(hourly, hourRange, useApparentTemperature)}
);
const start = Date.now();
const duration = 500;
//define animation step
this._animation = () => {
const now = Date.now();
let t = (now - start) / duration;
if (t > 1) {
t = 1;
}
//intepolator takes as input value from 0..1
this.setState(interpolator(t));
if (t < 1) {
//go to next animation step
requestAnimationFrame(this._animation);
}
}
//start animtion
requestAnimationFrame(this._animation);
},
render () {
const {stops} = this.state;
//...
//just draw svg rect with gradients
return Svg(
//...
);
}
});
/**
* background gradient
* @module components/background
*/
const React = require('react');
const getDimensions = require('../lib/getDimensions');
const Svg = React.createFactory(require('react-native-svg').Svg);
const Defs = React.createFactory(require('react-native-svg').Defs);
const Stop = React.createFactory(require('react-native-svg').Stop);
const connect = require('react-redux').connect;
const getColorByTemp = require('../lib/temperature-color');
const getDataPoints = require('../lib/getDataPoints');
const {interpolate} = require('d3-interpolate');
const LinearGradient = React.createFactory(
require('react-native-svg').LinearGradient
);
const Rect = React.createFactory(require('react-native-svg').Rect);
/**
* @param {ForecastDataBlock[]} hourly
* @param {number[]} hourRange
* @param {boolean} useApparentTemperature
* @returns {string[][]} colors
*/
function getStops(hourly, hourRange, useApparentTemperature) {
return hourly.map((dataBlock) => {
const points = getDataPoints(dataBlock);
if (points) {
let targetTempAr = points.map(
p => {
return useApparentTemperature ?
p.apparentTemperature :
p.temperature;
}
);
let maxTemp = Math.max(...targetTempAr.slice(...hourRange));
let minTemp = Math.min(...targetTempAr.slice(...hourRange));
return [
getColorByTemp(maxTemp),
getColorByTemp(minTemp)
]
} else {
return [
'rgb(84, 84, 84)',
'rgb(84, 84, 84)'
];
}
});
}
module.exports = connect(
(state) => {
return {
hourRange: state.hourRange,
hourly: state.hourly,
useApparentTemperature: state.useApparentTemperature
}
}
)(React.createClass({
getInitialState() {
const {hourly, hourRange, useApparentTemperature} = this.props;
return {
stops: getStops(hourly, hourRange, useApparentTemperature)
};
},
componentWillReceiveProps(props) {
const {
hourly,
hourRange,
useApparentTemperature
} = props;
const interpolator = interpolate(
this.state,
{stops: getStops(hourly, hourRange, useApparentTemperature)}
);
const start = Date.now();
const duration = 500;
this._animation = () => {
const now = Date.now();
let t = (now - start) / duration;
if (t > 1) {
t = 1;
}
this.setState(interpolator(t));
if (t < 1) {
requestAnimationFrame(this._animation);
}
}
requestAnimationFrame(this._animation);
},
render () {
const padding = 0;
let {width, curveHeight, viewHeight} = getDimensions();
width += 2 * padding;
const {stops} = this.state;
return Svg(
{
width,
height: viewHeight,
style: {
position: 'absolute',
left: -padding
}
},
Defs(null,
LinearGradient(
{
id: 'grad1',
x1: 0,
y1: 0,
x2: 0,
y2: viewHeight
},
Stop({
offset: String(1 - curveHeight / viewHeight),
stopColor: stops[0][0],
stopOpacity: 1
}),
Stop({
offset: String(1),
stopColor: stops[0][1],
stopOpacity: 1
})
),
LinearGradient(
{
id: 'grad2',
x1: 0,
y1: 0,
x2: 0,
y2: viewHeight
},
Stop({
offset: String(1 - curveHeight / viewHeight),
stopColor: stops[1][0],
stopOpacity: 1
}),
Stop({
offset: String(1),
stopColor: stops[1][1],
stopOpacity: 1
})
)
),
Rect({x: 0, y: 0, width: width / 2, height: viewHeight, fill: 'url(#grad1)'}),
Rect({x: width/2, y: 0, width: width / 2, height: viewHeight, fill: 'url(#grad2)'})
);
}
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment