├── .editorconfig
├── .gitignore
├── .jshintrc
├── .npmignore
├── README.md
├── index.js
└── package.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Commenting this out is preferred by some people, see
24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
25 | node_modules
26 |
27 | # Users Environment Variables
28 | .lock-wscript
29 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "devel": true,
5 | "strict": true,
6 | "globalstrict": true,
7 | "curly": true,
8 | "camelcase": false,
9 | "eqeqeq": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "unused": true,
17 | "undef": true
18 | }
19 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # common
26 | .DS_Store
27 | *.xml
28 |
29 | # do not include test dir in the published module
30 | test
31 | example
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | diaporama-react
2 | =========
3 |
4 | Implement a React Component to use the [diaporama](https://github.com/gre/diaporama) library.
5 |
6 | [](https://www.npmjs.com/package/diaporama-react)
7 |
8 |
9 | ```jsx
10 | {
11 | data: PropTypes.object.isRequired,
12 | width: PropTypes.number.isRequired,
13 | height: PropTypes.number.isRequired,
14 | resolution: PropTypes.number,
15 | paused: PropTypes.bool,
16 | loop: PropTypes.bool,
17 | autoplay: PropTypes.bool,
18 | currentTime: PropTypes.number,
19 | playbackRate: PropTypes.number,
20 | onDiaporamaCreated: PropTypes.func // callback giving the diaporama instance. use-case: You can bind Events on the diaporama. See "diaporama" documentation.
21 | }
22 | ```
23 |
24 | Usage
25 | -----
26 |
27 | ## app.js
28 |
29 | ```js
30 | import React from 'react';
31 | import ReactDOM from 'react-dom';
32 | import Diaporama from 'diaporama-react';
33 |
34 | const diaporamaData = require('./diaporama.json');
35 |
36 | let props = {
37 | data: diaporamaData,
38 | width: 320,
39 | height: 240,
40 | loop: true,
41 | autoplay: true,
42 | onDiaporamaCreated: (...args) => {
43 | console.log('onDiaporamaCreated', args);
44 | }
45 | }
46 |
47 | ReactDOM.render(, document.getElementById('app'));
48 |
49 | ```
50 |
51 |
52 | ## diaporama.json
53 |
54 | Following the [diaporama JSON description schema](https://gre.gitbooks.io/diaporama/content/docs/format.html)
55 |
56 | ```json
57 | {
58 | "timeline": [
59 | {
60 | "image": "https://crossorigin.me/http://loremflickr.com/320/240/paris",
61 | "duration": 2000,
62 | "kenburns": {
63 | "from": [ 0.5, [0.5, 0.6] ],
64 | "to": [ 1, [0.5, 0.6] ]
65 | },
66 | "transitionNext": {
67 | "name": "PageCurl",
68 | "duration": 1000
69 | }
70 | },{
71 | "image": "https://crossorigin.me/http://loremflickr.com/320/240/berlin",
72 | "duration": 2000,
73 | "kenburns": {
74 | "from": [ 0.5, [0.5, 0.6] ],
75 | "to": [ 1, [0.5, 0.6] ]
76 | },
77 | "transitionNext": {
78 | "name": "PageCurl",
79 | "duration": 1000
80 | }
81 | },{
82 | "image": "https://crossorigin.me/http://loremflickr.com/320/240/barcelona",
83 | "duration": 2000,
84 | "kenburns": {
85 | "from": [ 0.5, [0.5, 0.6] ],
86 | "to": [ 1, [0.5, 0.6] ]
87 | },
88 | "transitionNext": {
89 | "name": "PageCurl",
90 | "duration": 1000
91 | }
92 | }
93 | ],
94 | "transitions": [
95 | {
96 | "glsl": "\n#ifdef GL_ES\nprecision highp float;\n#endif\nuniform sampler2D from,to;uniform float progress;uniform vec2 resolution;const float MIN_AMOUNT=-0.16;const float MAX_AMOUNT=1.3;float amount=progress*(MAX_AMOUNT-MIN_AMOUNT)+MIN_AMOUNT;const float PI=3.141592653589793;const float scale=512.0;const float sharpness=3.0;float cylinderCenter=amount;float cylinderAngle=2.0*PI*amount;const float cylinderRadius=1.0/PI/2.0;vec3 hitPoint(float hitAngle,float yc,vec3 point,mat3 rrotation){float hitPoint=hitAngle/(2.0*PI);point.y=hitPoint;return rrotation*point;}vec4 antiAlias(vec4 color1,vec4 color2,float distanc){distanc*=scale;if(distanc<0.0) return color2;if(distanc>2.0) return color1;float dd=pow(1.0-distanc/2.0,sharpness);return ((color2-color1)*dd)+color1;}float distanceToEdge(vec3 point){float dx=abs(point.x>0.5?1.0-point.x:point.x);float dy=abs(point.y>0.5?1.0-point.y:point.y);if(point.x<0.0) dx=-point.x;if(point.x>1.0) dx=point.x-1.0;if(point.y<0.0) dy=-point.y;if(point.y>1.0) dy=point.y-1.0;if((point.x<0.0||point.x>1.0)&&(point.y<0.0||point.y>1.0)) return sqrt(dx*dx+dy*dy);return min(dx,dy);}vec4 seeThrough(float yc,vec2 p,mat3 rotation,mat3 rrotation){float hitAngle=PI-(acos(yc/cylinderRadius)-cylinderAngle);vec3 point=hitPoint(hitAngle,yc,rotation*vec3(p,1.0),rrotation);if(yc<=0.0&&(point.x<0.0||point.y<0.0||point.x>1.0||point.y>1.0)){vec2 texCoord=gl_FragCoord.xy/resolution.xy;return texture2D(to,texCoord);}if(yc>0.0) return texture2D(from,p);vec4 color=texture2D(from,point.xy);vec4 tcolor=vec4(0.0);return antiAlias(color,tcolor,distanceToEdge(point));}vec4 seeThroughWithShadow(float yc,vec2 p,vec3 point,mat3 rotation,mat3 rrotation){float shadow=distanceToEdge(point)*30.0;shadow=(1.0-shadow)/3.0;if(shadow<0.0) shadow=0.0;else shadow*=amount;vec4 shadowColor=seeThrough(yc,p,rotation,rrotation);shadowColor.r-=shadow;shadowColor.g-=shadow;shadowColor.b-=shadow;return shadowColor;}vec4 backside(float yc,vec3 point){vec4 color=texture2D(from,point.xy);float gray=(color.r+color.b+color.g)/15.0;gray+=(8.0/10.0)*(pow(1.0-abs(yc/cylinderRadius),2.0/10.0)/2.0+(5.0/10.0));color.rgb=vec3(gray);return color;}vec4 behindSurface(float yc,vec3 point,mat3 rrotation){float shado=(1.0-((-cylinderRadius-yc)/amount*7.0))/6.0;shado*=1.0-abs(point.x-0.5);yc=(-cylinderRadius-cylinderRadius-yc);float hitAngle=(acos(yc/cylinderRadius)+cylinderAngle)-PI;point=hitPoint(hitAngle,yc,point,rrotation);if(yc<0.0&&point.x>=0.0&&point.y>=0.0&&point.x<=1.0&&point.y<=1.0&&(hitAngle0.5)){shado=1.0-(sqrt(pow(point.x-0.5,2.0)+pow(point.y-0.5,2.0))/(71.0/100.0));shado*=pow(-yc/cylinderRadius,3.0);shado*=0.5;}else{shado=0.0;}vec2 texCoord=gl_FragCoord.xy/resolution.xy;return vec4(texture2D(to,texCoord).rgb-shado,1.0);}void main(){vec2 texCoord=gl_FragCoord.xy/resolution.xy;const float angle=30.0*PI/180.0;float c=cos(-angle);float s=sin(-angle);mat3 rotation=mat3(c,s,0,-s,c,0,0.12,0.258,1);c=cos(angle);s=sin(angle);mat3 rrotation=mat3(c,s,0,-s,c,0,0.15,-0.5,1);vec3 point=rotation*vec3(texCoord,1.0);float yc=point.y-cylinderCenter;if(yc<-cylinderRadius){gl_FragColor=behindSurface(yc,point,rrotation);return;}if(yc>cylinderRadius){gl_FragColor=texture2D(from,texCoord);return;}float hitAngle=(acos(yc/cylinderRadius)+cylinderAngle)-PI;float hitAngleMod=mod(hitAngle,2.0*PI);if((hitAngleMod>PI&&amount<0.5)||(hitAngleMod>PI/2.0&&amount<0.0)){gl_FragColor=seeThrough(yc,texCoord,rotation,rrotation);return;}point=hitPoint(hitAngle,yc,point,rrotation);if(point.x<0.0||point.y<0.0||point.x>1.0||point.y>1.0){gl_FragColor=seeThroughWithShadow(yc,texCoord,point,rotation,rrotation);return;}vec4 color=backside(yc,point);vec4 otherColor;if(yc<0.0){float shado=1.0-(sqrt(pow(point.x-0.5,2.0)+pow(point.y-0.5,2.0))/0.71);shado*=pow(-yc/cylinderRadius,3.0);shado*=0.5;otherColor=vec4(0.0,0.0,0.0,shado);}else{otherColor=texture2D(from,texCoord);}color=antiAlias(color,otherColor,cylinderRadius-abs(yc));vec4 cl=seeThroughWithShadow(yc,texCoord,point,rotation,rrotation);float dist=distanceToEdge(point);gl_FragColor=antiAlias(color,cl,dist);}",
97 | "uniforms": {},
98 | "name": "PageCurl"
99 | }
100 | ]
101 | }
102 | ```
103 |
104 |
105 | Related Projects
106 | ---------------
107 |
108 | - [`diaporama`](https://github.com/gre/diaporama): Image/video/content slideshow engine providing high quality animation effects
109 | - [`diaporama-maker`](https://github.com/gre/diaporama-maker): application to create Diaporama slideshows.
110 | - [`kenburns`](http://github.com/gre/kenburns): KenBurns effect for the Web.
111 | - [`glsl-transition`](https://github.com/glslio/glsl-transition): Perform a GLSL Transition.
112 | - [`slide2d`](https://github.com/gre/slide2d): Express vectorial content in JSON using canvas2d directives.
113 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 | var Diaporama = require('diaporama');
5 | var PropTypes = React.PropTypes;
6 |
7 | function affectProps (obj, props) {
8 | for (var k in props) {
9 | if (k !== "onDiaporamaCreated") // blacklisting only for now. We might do whitelist instead ?
10 | obj[k] = props[k];
11 | }
12 | return obj;
13 | }
14 |
15 | var DiaporamaElement = React.createClass({
16 |
17 | displayName: 'DiaporamaElement',
18 |
19 | propTypes: {
20 | data: PropTypes.object.isRequired,
21 | width: PropTypes.number.isRequired,
22 | height: PropTypes.number.isRequired,
23 | resolution: PropTypes.number,
24 | paused: PropTypes.bool,
25 | loop: PropTypes.bool,
26 | autoplay: PropTypes.bool,
27 | currentTime: PropTypes.number,
28 | playbackRate: PropTypes.number,
29 | onDiaporamaCreated: PropTypes.func // callback giving the diaporama instance. use-case: You can bind Events on the diaporama. See "diaporama" documentation.
30 | },
31 |
32 | componentDidMount: function () {
33 | var opts = affectProps({}, this.props);
34 | this.diaporama = Diaporama(this.refs.container, opts);
35 | if (this.props.onDiaporamaCreated) {
36 | this.props.onDiaporamaCreated(this.diaporama);
37 | }
38 | },
39 |
40 | componentWillUnmount: function () {
41 | this.diaporama.destroy();
42 | },
43 |
44 | componentWillReceiveProps: function (props) {
45 | affectProps(this.diaporama, props);
46 | },
47 |
48 | shouldComponentUpdate: function () {
49 | return false;
50 | },
51 |
52 | render: function () {
53 | return ();
54 | }
55 | });
56 |
57 | module.exports = DiaporamaElement;
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diaporama-react",
3 | "version": "2.1.0",
4 | "description": "Diaporama component for React",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git@github.com:glslio/diaporama-react.git"
9 | },
10 | "keywords": [
11 | "diaporama",
12 | "react"
13 | ],
14 | "author": "Gaëtan Renaudeau",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/glslio/diaporama-react/issues"
18 | },
19 | "homepage": "https://github.com/glslio/diaporama-react",
20 | "browserify": {
21 | "transform": [
22 | "babelify"
23 | ]
24 | },
25 | "peerDependencies": {
26 | "react": "*"
27 | },
28 | "dependencies": {
29 | "babelify": "^6.1.3",
30 | "diaporama": "^2.0.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------