"
6 | ],
7 | "description": "React Component to perform transitions on prop changes",
8 | "main": "dist/react-transition.js",
9 | "moduleType": [
10 | "amd",
11 | "globals",
12 | "node"
13 | ],
14 | "keywords": [
15 | "react",
16 | "transition",
17 | "reactjs",
18 | "react-component",
19 | "animation",
20 | "tween"
21 | ],
22 | "license": "MIT",
23 | "ignore": [
24 | "**/.*",
25 | "node_modules",
26 | "bower_components",
27 | "test",
28 | "tests"
29 | ],
30 | "dependencies": {
31 | "react": "~0.12.0",
32 | "d3": "~3.4.11"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | /* jshint node: true */
2 | module.exports = function(config) {
3 | config.set({
4 | basePath: '.',
5 |
6 | frameworks: ['jasmine'],
7 | browsers: ['PhantomJS'],
8 |
9 | files: [
10 | // shim to workaroud PhantomJS 1.x lack of `bind` support
11 | // see: https://github.com/ariya/phantomjs/issues/10522
12 | 'node_modules/es5-shim/es5-shim.js',
13 |
14 | // React is an external dependency of the component
15 | 'node_modules/react/dist/react-with-addons.js',
16 |
17 | 'spec/spec-helper.js',
18 | 'spec/**/*.spec.*',
19 | { pattern: 'lib/**/*', watched: true, included: false }
20 | ],
21 |
22 | preprocessors: {
23 | // add webpack as preprocessor
24 | 'spec/**/*.spec.*': ['webpack']
25 | },
26 |
27 | webpack: require('./webpack.config.js'),
28 |
29 | webpackServer: {
30 | noInfo: true
31 | },
32 |
33 | singleRun: true
34 | });
35 | };
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-transition",
3 | "version": "1.0.3",
4 | "description": "React Component to perform transitions on prop changes",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "test": "./node_modules/.bin/jsxhint lib/ spec/ && ./node_modules/.bin/jshint lib/ spec/ && ./node_modules/karma/bin/karma start karma.conf.js",
8 | "watch-test": "./node_modules/karma/bin/karma start karma.conf.js --auto-watch --no-single-run",
9 | "build": "./node_modules/.bin/webpack --config webpack.build.config.js -p",
10 | "dev": "./node_modules/.bin/webpack-dev-server --config webpack.build.config.js --inline --hot"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git@github.com:pirelenito/react-transition.git"
15 | },
16 | "keywords": [
17 | "react",
18 | "reactjs",
19 | "react-component",
20 | "transition",
21 | "animation",
22 | "tween"
23 | ],
24 | "author": "Paulo Ragonha",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/pirelenito/react-transition/issues"
28 | },
29 | "homepage": "https://github.com/pirelenito/react-transition",
30 | "devDependencies": {
31 | "css-loader": "^0.9.1",
32 | "es5-shim": "^4.1.0",
33 | "jasmine": "^2.2.1",
34 | "jasmine-core": "^2.2.0",
35 | "jshint": "^2.6.0",
36 | "jsx-loader": "^0.12.2",
37 | "jsxhint": "^0.10.0",
38 | "karma": "^0.12.31",
39 | "karma-jasmine": "^0.3.5",
40 | "karma-phantomjs-launcher": "^0.1.4",
41 | "karma-webpack": "^1.5.0",
42 | "sass-loader": "^0.4.0-beta",
43 | "style-loader": "^0.8.3",
44 | "webpack": "^1.5.3",
45 | "webpack-dev-server": "^1.7.0"
46 | },
47 | "dependencies": {
48 | "d3": "^3.5.5",
49 | "lodash.foreach": "^3.0.1",
50 | "react": "^0.12.0",
51 | "underscore": "^1.6.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React Transition example
5 |
6 |
7 |
8 |
9 |
10 |
37 |
38 |
39 |
40 |
41 |
71 |
72 | Example based on react-tween-state
73 |
74 |
75 |
--------------------------------------------------------------------------------
/lib/react-transition.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var d3 = require('d3');
3 | var forEach = require('lodash.foreach');
4 |
5 |
6 | /**
7 | Transition Component. It applies transitions on any prop change. Uses D3 interpolator functions underneath.
8 |
9 | @param props.component underlying component that will be initialized and animated
10 | @param [props.ease='linear'] easying function between transition states (available options: https://github.com/mbostock/d3/wiki/Transitions#d3_ease)
11 | @param [props.duration='500'] duration of the transition
12 |
13 | Usage:
14 |
15 | */
16 | module.exports = React.createClass({
17 | getDefaultProps: function () {
18 | return {
19 | ease: 'cubic-in-out',
20 | duration: 400
21 | };
22 | },
23 |
24 | startAnimation: function () {
25 | var start = new Date().getTime(),
26 | end = start + parseInt(this.props.duration, 10),
27 | finished = false,
28 | that = this;
29 |
30 | function animate () {
31 | if (finished || that.stopAnimation) { return; }
32 | var now = t();
33 |
34 | if (now > 1) { now = 1; finished = true; }
35 |
36 | that.animate(now);
37 | window.requestAnimationFrame(animate);
38 | }
39 |
40 | function t () {
41 | var now = new Date().getTime();
42 |
43 | return (now - start) / (end - start) || 0;
44 | }
45 |
46 | animate();
47 | },
48 |
49 | componentWillUnmount: function () {
50 | // stops the animation in progress
51 | this.stopAnimation = true;
52 | },
53 |
54 | getInitialState: function () {
55 | return this.props;
56 | },
57 |
58 | componentWillReceiveProps: function (newProps) {
59 | var that = this;
60 |
61 | var interpolators = {};
62 |
63 | forEach(newProps, function (value, propName) {
64 | if (propName === 'component' || propName === 'children' || propName === 'ease' || propName === 'duration' || propName.match(/^on(.+)/)) { return; }
65 | interpolators[propName] = d3.interpolate(that.state[propName], newProps[propName]);
66 | });
67 |
68 | this.interpolators = interpolators;
69 | this.startAnimation();
70 | },
71 |
72 | animate: function (t) {
73 | var newState = {},
74 | ease = d3.ease(this.props.ease);
75 |
76 | forEach(this.interpolators, function (interpolator, propName) {
77 | newState[propName] = interpolator(ease(t));
78 | });
79 |
80 | this.setState(newState);
81 | },
82 |
83 | render: function () {
84 | return React.createElement(this.props.component, this.state, this.props.children);
85 | }
86 | });
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Transition Component
2 |
3 | [](https://travis-ci.org/pirelenito/react-transition)
4 |
5 | [React.js](http://reactjs.com/) component that will apply transitions on any prop change. Was created to be used on drawing SVG charts with [D3](http://d3js.org/), but can be used for anything.
6 |
7 | 
8 |
9 | Check the [live demo](https://rawgit.com/pirelenito/react-transition/master/index.html).
10 |
11 | ## Usage
12 |
13 | Here is an example usage:
14 |
15 | ```js
16 |
17 | ```
18 |
19 | The `ReactTransition` component will actualy render a `div`, and it will apply the `bounce` ease function with a duration of `500` milisseconds on any [componentWillReceiveProps](http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops) of the `style` property.
20 |
21 | ## Install
22 |
23 | Install with [NPM](http://npmjs.org/):
24 |
25 | ```bash
26 | npm install react-transition
27 | ```
28 |
29 | It also is available as an UMD. Having support for [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD), [CommonJS](http://wiki.commonjs.org/wiki/CommonJS) and globals, which can be installed through [Bower](http://bower.io/):
30 |
31 | ```bash
32 | bower install react-transition
33 | ```
34 |
35 | Or simply dowloading the [dist/react-transition.js](https://raw.githubusercontent.com/pirelenito/react-transition/master/dist/react-transition.js) distribution file and add as a script tag in your HTML (it will expose a `ReactTransition` global variable) allongsite with its depencencies:
36 |
37 | ```html
38 |
39 |
40 |
41 | ```
42 |
43 | ## Easing functions
44 |
45 | [Check D3's documentation](https://github.com/mbostock/d3/wiki/Transitions#d3_ease) to see the available *easing* function. But some examples are:
46 |
47 | * linear - the identity function, t.
48 | * poly(k) - raises t to the specified power k (e.g., 3).
49 | * quad - equivalent to poly(2).
50 | * cubic - equivalent to poly(3).
51 | * sin - applies the trigonometric function sin.
52 | * exp - raises 2 to a power based on t.
53 | * circle - the quarter circle.
54 | * elastic(a, p) - simulates an elastic band;
55 | * back(s) - simulates backing into a parking space.
56 | * bounce - simulates a bouncy collision.
57 |
58 | ## Author
59 |
60 | [Paulo Ragonha](http://paulo.ragonha.me/)
61 |
62 | ## Similar work
63 |
64 | You can check [@chenglou](https://github.com/chenglou)'s approach to animation using mixins: [react-tween-state](https://github.com/chenglou/react-tween-state).
65 |
--------------------------------------------------------------------------------
/dist/react-transition.js:
--------------------------------------------------------------------------------
1 | !function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n(require("React"),require("d3")):"function"==typeof define&&define.amd?define(["React","d3"],n):"object"==typeof exports?exports.ReactTransition=n(require("React"),require("d3")):t.ReactTransition=n(t.React,t.d3)}(this,function(){return function(t){function n(e){if(r[e])return r[e].exports;var o=r[e]={exports:{},id:e,loaded:!1};return t[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var r={};return n.m=t,n.c=r,n.p="",n(0)}([function(t,n,r){t.exports=r(2)},function(t){function n(t){return"string"==typeof t?t:null==t?"":t+""}function r(t){return t&&"object"==typeof t||!1}function e(t){return"number"==typeof t&&t>-1&&t%1==0&&m>=t}function o(t){return null==t?!1:y.call(t)==c?g.test(l.call(t)):r(t)&&f.test(t)||!1}function u(t){return t=n(t),t&&p.test(t)?t.replace(a,"\\$&"):t}var i="[object Array]",c="[object Function]",f=/^\[object .+?Constructor\]$/,a=/[.*+?^${}()|[\]\/\\]/g,p=RegExp(a.source),s=Object.prototype,l=Function.prototype.toString,y=s.toString,g=RegExp("^"+u(y).replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),h=o(h=Array.isArray)&&h,m=Math.pow(2,53)-1,v=h||function(t){return r(t)&&e(t.length)&&y.call(t)==i||!1};t.exports=v},function(t,n,r){var e=r(10),o=r(11),u=r(3);t.exports=e.createClass({getDefaultProps:function(){return{ease:"cubic-in-out",duration:400}},startAnimation:function(){function t(){if(!o&&!u.stopAnimation){var r=n();r>1&&(r=1,o=!0),u.animate(r),window.requestAnimationFrame(t)}}function n(){var t=(new Date).getTime();return(t-r)/(e-r)||0}var r=(new Date).getTime(),e=r+parseInt(this.props.duration,10),o=!1,u=this;t()},componentWillUnmount:function(){this.stopAnimation=!0},getInitialState:function(){return this.props},componentWillReceiveProps:function(t){var n=this,r={};u(t,function(e,u){"component"===u||"children"===u||"ease"===u||"duration"===u||u.match(/^on(.+)/)||(r[u]=o.interpolate(n.state[u],t[u]))}),this.interpolators=r,this.startAnimation()},animate:function(t){var n={},r=o.ease(this.props.ease);u(this.interpolators,function(e,o){n[o]=e(r(t))}),this.setState(n)},render:function(){return e.createElement(this.props.component,this.state,this.props.children)}})},function(t,n,r){function e(t,n,r){return"function"==typeof n&&"undefined"==typeof r&&c(t)?o(t,n):u(t,i(n,r,3))}var o=r(4),u=r(5),i=r(9),c=r(1);t.exports=e},function(t){function n(t,n){for(var r=-1,e=t.length;++r-1&&t%1==0&&p>=t}function c(t){return f(t)?t:Object(t)}function f(t){var n=typeof t;return"function"==n||t&&"object"==n||!1}var a=r(6),p=Math.pow(2,53)-1;t.exports=e},function(t,n,r){function e(t,n){return t=+t,n=null==n?h:n,t>-1&&t%1==0&&n>t}function o(t){return"number"==typeof t&&t>-1&&t%1==0&&h>=t}function u(t){for(var n=c(t),r=n.length,u=r&&t.length,i=u&&o(u)&&(a(t)||m.nonEnumArgs&&f(t)),p=-1,s=[];++p0;++u-1&&t%1==0&&c>=t}function e(t){var e=n(t)?t.length:void 0;return r(e)&&i.call(t)==o||!1}var o="[object Arguments]",u=Object.prototype,i=u.toString,c=Math.pow(2,53)-1;t.exports=e},function(t){function n(t){return"string"==typeof t?t:null==t?"":t+""}function r(t){return t&&"object"==typeof t||!1}function e(t){return null==t?!1:s.call(t)==u?l.test(p.call(t)):r(t)&&i.test(t)||!1}function o(t){return t=n(t),t&&f.test(t)?t.replace(c,"\\$&"):t}var u="[object Function]",i=/^\[object .+?Constructor\]$/,c=/[.*+?^${}()|[\]\/\\]/g,f=RegExp(c.source),a=Object.prototype,p=Function.prototype.toString,s=a.toString,l=RegExp("^"+o(s).replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=e},function(t){function n(t,n,e){if("function"!=typeof t)return r;if("undefined"==typeof n)return t;switch(e){case 1:return function(r){return t.call(n,r)};case 3:return function(r,e,o){return t.call(n,r,e,o)};case 4:return function(r,e,o,u){return t.call(n,r,e,o,u)};case 5:return function(r,e,o,u,i){return t.call(n,r,e,o,u,i)}}return function(){return t.apply(n,arguments)}}function r(t){return t}t.exports=n},function(t){t.exports=React},function(t){t.exports=d3}])});
--------------------------------------------------------------------------------