js-animation.react.stories.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import React, { useState, Component, isValidElement } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { storiesOf } from '@storybook/react';
  4. import { withKnobs, text, boolean } from '@storybook/addon-knobs';
  5. import withPropsCombinations from 'react-storybook-addon-props-combinations';
  6. import noop from '../utils/noop';
  7. import { Animation } from '../index';
  8. const stories = storiesOf('semi-animation/jsAnimation-react', module);
  9. stories.addDecorator(withKnobs);
  10. class Anim extends Component {
  11. static defaultProps = {
  12. onStart: noop,
  13. onFrame: noop,
  14. onPause: noop,
  15. onResume: noop,
  16. onStop: noop,
  17. onRest: noop,
  18. };
  19. constructor(props = {}) {
  20. super(props);
  21. this.initAnimation();
  22. this.bindEvents();
  23. }
  24. bindEvents = () => {
  25. this.pause = () => {
  26. this.animation.pause();
  27. };
  28. this.stop = () => {
  29. this.animation.stop();
  30. };
  31. this.resume = () => {
  32. this.animation.resume();
  33. };
  34. this.reset = () => {
  35. this.animation.reset();
  36. this.animation.start();
  37. };
  38. this.reverse = () => {
  39. this.animation.reverse();
  40. this.animation.start();
  41. };
  42. this.end = () => {
  43. this.animation.end();
  44. }
  45. };
  46. initAnimation = () => {
  47. const props = this.props;
  48. this.animation = new Animation(
  49. {
  50. from: { ...props.from },
  51. to: { ...props.to },
  52. },
  53. {
  54. ...props.config,
  55. }
  56. );
  57. ['start', 'frame', 'pause', 'resume', 'stop', 'rest'].forEach(event => {
  58. const propName = `on${event[0].toUpperCase() + event.slice(1)}`;
  59. this.animation.on(event, props => this.props[propName](props));
  60. });
  61. };
  62. componentDidMount() {
  63. this.animation.start();
  64. }
  65. componentWillUnmount() {
  66. this.animation.destroy();
  67. }
  68. render() {
  69. let { children } = this.props;
  70. return (
  71. <div>
  72. <div>{children}</div>
  73. <div>
  74. <button onClick={this.reset}>reset</button>
  75. <button onClick={this.reverse}>reverse</button>
  76. <button onClick={this.pause}>pause</button>
  77. <button onClick={this.resume}>resume</button>
  78. <button onClick={this.end}>end</button>
  79. <button onClick={this.stop}>stop</button>
  80. </div>
  81. </div>
  82. );
  83. }
  84. }
  85. const itemStyle = {
  86. backgroundColor: 'rgb(241, 101, 101)',
  87. color: 'white',
  88. borderRadius: 4,
  89. padding: 10,
  90. textAlign: 'center',
  91. };
  92. const bigSquareStyle = {
  93. backgroundColor: 'rgb(241, 101, 101)',
  94. width: 100,
  95. height: 100,
  96. margin: 20,
  97. marginLeft: 50,
  98. borderRadius: 4,
  99. fontSize: 32,
  100. color: 'white',
  101. display: 'flex',
  102. alignItems: 'center',
  103. justifyContent: 'center',
  104. };
  105. stories.add('motion', () => {
  106. class App extends Component {
  107. constructor(props) {
  108. super(props);
  109. this.state = {
  110. value: 0,
  111. };
  112. this.onFrame = props => {
  113. const value = props.value.toFixed(2);
  114. this.setState({ value });
  115. };
  116. this.onStop = props => {
  117. console.log('onStop', props);
  118. const value = props.value.toFixed(2);
  119. this.setState({ value });
  120. };
  121. }
  122. render() {
  123. const { value } = this.state;
  124. const ratio = value / 10;
  125. // hsl(280, 43%, 62%) => hsl(0, 83%, 67%)
  126. const bgColor = `hsl(${-280 * ratio + 280}, ${40 * ratio + 43}%, ${5 * ratio + 62}%)`;
  127. const scale = `scale(${ratio}, ${ratio})`;
  128. const hsl = `hsl(${value * 25 + 60}, 90%, 50%)`;
  129. const x = 100 + 20 * value;
  130. const y = 100 + 20 * Math.cos(value);
  131. return (
  132. <Anim from={{ value: 0 }} to={{ value: 10 }} config={{ duration: 20000 }} onFrame={this.onFrame} onStop={this.onStop}>
  133. <div style={{ ...itemStyle, width: 300 }}>prop.value changed to: {value}</div>
  134. <div style={{ ...bigSquareStyle, transform: scale }}>{value}</div>
  135. <div style={{ height: 200, position: 'relative' }}>
  136. <span
  137. style={{
  138. ...itemStyle,
  139. left: x,
  140. top: y,
  141. position: 'absolute',
  142. }}
  143. >
  144. I'am a block.
  145. </span>
  146. </div>
  147. <div style={{ ...bigSquareStyle, width: 200, backgroundColor: hsl, fontSize: 16 }}>{hsl}</div>
  148. </Anim>
  149. );
  150. }
  151. }
  152. return <App />;
  153. });
  154. stories.add('bezier-easing', () => {
  155. class BezierApp extends Component {
  156. constructor(props) {
  157. super(props);
  158. this.state = {
  159. value: 0,
  160. };
  161. this.onFrame = props => {
  162. const value = props.value.toFixed(2);
  163. this.setState({ value });
  164. };
  165. }
  166. render() {
  167. let { value } = this.state;
  168. let { config = { easing: 'linear' } } = this.props;
  169. const x = 100 + 20 * value;
  170. const y = 100 + 20 * Math.cos(value);
  171. return (
  172. <div style={{ border: '1px solid gray', backgroundColor: 'tan', borderRadius: 4, marginBottom: 10 }}>
  173. <Anim from={{ value: 0 }} to={{ value: 10 }} onFrame={this.onFrame} config={config}>
  174. <div style={{ padding: 5 }}>bezier: {config.easing}</div>
  175. <div style={{ height: 200, position: 'relative' }}>
  176. <span
  177. style={{
  178. ...itemStyle,
  179. left: x,
  180. top: y,
  181. position: 'absolute',
  182. }}
  183. >
  184. I'am a block.
  185. </span>
  186. </div>
  187. </Anim>
  188. </div>
  189. );
  190. }
  191. }
  192. const prefix = 'ease';
  193. const curves = ['In', 'Out', 'InOut'];
  194. const names = ['Quad', 'Cubic', 'Quart', 'Quint', 'Sine', 'Expo', 'Circ', 'Back', 'Elastic'];
  195. const apps = [<BezierApp key={0} config={{ easing: 'linear', duration: 2000 }} />];
  196. curves.forEach((curve, curveIdx) => {
  197. names.forEach((name, nameIdx) => {
  198. let easing = `${prefix}${curve}${name}`;
  199. if (name === 'Elastic') {
  200. easing += '(1, .5)';
  201. }
  202. apps.push(<BezierApp key={`${curveIdx}-${nameIdx}`} config={{ easing, duration: 2000 }} />);
  203. });
  204. });
  205. apps.push(<BezierApp key={'mybezier-1'} config={{ easing: 'cubic-bezier(.13,.85,.82,.44)', duration: 2000 }} />);
  206. return <>{apps}</>;
  207. });
  208. stories.add('simple', () => {
  209. class App extends Component {
  210. constructor(props) {
  211. super(props);
  212. this.state = { value: 0 };
  213. this.animation = new Animation({
  214. from: { value: 0 },
  215. to: { value: 1 },
  216. });
  217. this.animation.on('frame', props => {
  218. this.setState({ value: props.value.toFixed(2) });
  219. });
  220. }
  221. componentDidMount() {
  222. this.animation.start();
  223. }
  224. componentWillUnmount() {
  225. this.animation.destroy();
  226. }
  227. render() {
  228. const { value } = this.state;
  229. return <div style={{ display: 'inline-block', transform: `scale(${value})` }}>{value}</div>;
  230. }
  231. }
  232. return <div style={{ padding: 150 }}><App/></div>
  233. })