textfx.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /**
  2. * TextFx.js
  3. * http://www.codrops.com
  4. *
  5. * Licensed under the MIT license.
  6. * http://www.opensource.org/licenses/mit-license.php
  7. *
  8. * Copyright 2016, Codrops
  9. * http://www.codrops.com
  10. */
  11. ;(function(window) {
  12. 'use strict';
  13. /**
  14. * Equation of a line.
  15. */
  16. function lineEq(y2, y1, x2, x1, currentVal) {
  17. // y = mx + b
  18. var m = (y2 - y1) / (x2 - x1),
  19. b = y1 - m * x1;
  20. return m * currentVal + b;
  21. }
  22. function TextFx(el) {
  23. this.el = el;
  24. this._init();
  25. }
  26. TextFx.prototype.effects = {
  27. 'fx1' : {
  28. in: {
  29. duration: 1000,
  30. delay: function(el, index) { return 75+index*40; },
  31. easing: 'easeOutElastic',
  32. elasticity: 650,
  33. opacity: {
  34. value: 1,
  35. easing: 'easeOutExpo',
  36. },
  37. translateY: ['50%','0%']
  38. },
  39. out: {
  40. duration: 400,
  41. delay: function(el, index) { return index*40; },
  42. easing: 'easeOutExpo',
  43. opacity: 0,
  44. translateY: '-100%'
  45. }
  46. },
  47. 'fx2' : {
  48. in: {
  49. duration: 700,
  50. delay: function(el, index) { return index*50; },
  51. easing: 'easeOutCirc',
  52. opacity: 1,
  53. translateX: function(el, index) {
  54. return [(50+index*10),0]
  55. }
  56. },
  57. out: {
  58. duration: 0,
  59. opacity: 0
  60. }
  61. },
  62. 'fx3' : {
  63. in: {
  64. duration: 800,
  65. delay: function(el, index) { return index*50; },
  66. easing: 'easeOutElastic',
  67. opacity: 1,
  68. translateY: function(el, index) {
  69. return index%2 === 0 ? ['-80%', '0%'] : ['80%', '0%'];
  70. }
  71. },
  72. out: {
  73. duration: 800,
  74. delay: function(el, index) { return index*50; },
  75. easing: 'easeOutExpo',
  76. opacity: 0,
  77. translateY: function(el, index) {
  78. return index%2 === 0 ? '80%' : '-80%';
  79. }
  80. }
  81. },
  82. 'fx4' : {
  83. in: {
  84. duration: 700,
  85. delay: function(el, index) { return (el.parentNode.children.length-index-1)*80; },
  86. easing: 'easeOutElastic',
  87. opacity: 1,
  88. translateY: function(el, index) {
  89. return index%2 === 0 ? ['-80%', '0%'] : ['80%', '0%'];
  90. },
  91. rotateZ: [90,0]
  92. },
  93. out: {
  94. duration: 500,
  95. delay: function(el, index) { return (el.parentNode.children.length-index-1)*80; },
  96. easing: 'easeOutExpo',
  97. opacity: 0,
  98. translateY: function(el, index) {
  99. return index%2 === 0 ? '80%' : '-80%';
  100. },
  101. rotateZ: function(el, index) {
  102. return index%2 === 0 ? -25 : 25;
  103. }
  104. }
  105. },
  106. 'fx5' : {
  107. perspective: 1000,
  108. in: {
  109. duration: 700,
  110. delay: function(el, index) { return 550+index*50; },
  111. easing: 'easeOutQuint',
  112. opacity: {
  113. value: 1,
  114. easing: 'linear',
  115. },
  116. translateY: ['-150%','0%'],
  117. rotateY: [180,0]
  118. },
  119. out: {
  120. duration: 700,
  121. delay: function(el, index) { return index*60; },
  122. easing: 'easeInQuint',
  123. opacity: {
  124. value: 0,
  125. easing: 'linear',
  126. },
  127. translateY: '150%',
  128. rotateY: -180
  129. }
  130. },
  131. 'fx6' : {
  132. in: {
  133. duration: 600,
  134. easing: 'easeOutQuart',
  135. opacity: 1,
  136. translateY: function(el, index) {
  137. return index%2 === 0 ? ['-40%', '0%'] : ['40%', '0%'];
  138. },
  139. rotateZ: [10,0]
  140. },
  141. out: {
  142. duration: 0,
  143. opacity: 0
  144. }
  145. },
  146. 'fx7' : {
  147. in: {
  148. duration: 250,
  149. delay: function(el, index) { return 200+index*25; },
  150. easing: 'easeOutCubic',
  151. opacity: 1,
  152. translateY: ['-50%','0%']
  153. },
  154. out: {
  155. duration: 250,
  156. delay: function(el, index) { return index*25; },
  157. easing: 'easeOutCubic',
  158. opacity: 0,
  159. translateY: '50%'
  160. }
  161. },
  162. 'fx8' : {
  163. in: {
  164. duration: 400,
  165. delay: function(el, index) { return 150+(el.parentNode.children.length-index-1)*20; },
  166. easing: 'easeOutQuad',
  167. opacity: 1,
  168. translateY: ['100%','0%']
  169. },
  170. out: {
  171. duration: 400,
  172. delay: function(el, index) { return (el.parentNode.children.length-index-1)*20; },
  173. easing: 'easeInOutQuad',
  174. opacity: 0,
  175. translateY: '-100%'
  176. }
  177. },
  178. 'fx9' : {
  179. perspective: 1000,
  180. origin: '50% 100%',
  181. in: {
  182. duration: 400,
  183. delay: function(el, index) { return index*50; },
  184. easing: 'easeOutSine',
  185. opacity: 1,
  186. rotateY: [-90,0]
  187. },
  188. out: {
  189. duration: 200,
  190. delay: function(el, index) { return index*50; },
  191. easing: 'easeOutSine',
  192. opacity: 0,
  193. rotateY: 45
  194. }
  195. },
  196. 'fx10' : {
  197. in: {
  198. duration: 1000,
  199. delay: function(el, index) { return 100+index*30; },
  200. easing: 'easeOutElastic',
  201. elasticity: anime.random(400, 700),
  202. opacity: 1,
  203. rotateZ: function(el, index) {
  204. return [anime.random(20,40),0];
  205. }
  206. },
  207. out: {
  208. duration: 0,
  209. opacity: 0
  210. }
  211. },
  212. 'fx11' : {
  213. perspective: 1000,
  214. origin: '50% 100%',
  215. in: {
  216. duration: 400,
  217. delay: function(el, index) { return 200+index*20; },
  218. easing: 'easeOutExpo',
  219. opacity: 1,
  220. rotateY: [-90,0]
  221. },
  222. out: {
  223. duration: 400,
  224. delay: function(el, index) { return index*20; },
  225. easing: 'easeOutExpo',
  226. opacity: 0,
  227. rotateY: 90
  228. }
  229. },
  230. 'fx12' : {
  231. perspective: 1000,
  232. origin: '50% 100%',
  233. in: {
  234. duration: 400,
  235. delay: function(el, index) { return 200+index*30; },
  236. easing: 'easeOutExpo',
  237. opacity: 1,
  238. rotateX: [90,0]
  239. },
  240. out: {
  241. duration: 400,
  242. delay: function(el, index) { return index*30; },
  243. easing: 'easeOutExpo',
  244. opacity: 0,
  245. rotateX: -90
  246. }
  247. },
  248. 'fx13' : {
  249. in: {
  250. duration: 800,
  251. easing: 'easeOutExpo',
  252. opacity: 1,
  253. translateY: function(el, index) {
  254. var p = el.parentNode,
  255. lastElOffW = p.lastElementChild.offsetWidth,
  256. firstElOffL = p.firstElementChild.offsetLeft,
  257. w = p.offsetWidth - lastElOffW - firstElOffL - (p.offsetWidth - lastElOffW - p.lastElementChild.offsetLeft),
  258. tyVal = lineEq(0, 200, firstElOffL + w/2, firstElOffL, el.offsetLeft);
  259. return [Math.abs(tyVal)+50+'%','0%'];
  260. },
  261. rotateZ: function(el, index) {
  262. var p = el.parentNode,
  263. lastElOffW = p.lastElementChild.offsetWidth,
  264. firstElOffL = p.firstElementChild.offsetLeft,
  265. w = p.offsetWidth - lastElOffW - p.firstElementChild.offsetLeft - (p.offsetWidth - lastElOffW - p.lastElementChild.offsetLeft),
  266. rz = lineEq(90, -90,firstElOffL + w, firstElOffL, el.offsetLeft);
  267. return [rz,0];
  268. }
  269. },
  270. out: {
  271. duration: 500,
  272. easing: 'easeOutExpo',
  273. opacity: 0,
  274. translateY: '-150%'
  275. }
  276. },
  277. 'fx14' : {
  278. in: {
  279. duration: 500,
  280. easing: 'easeOutExpo',
  281. delay: function(el, index) { return 200+index*30; },
  282. opacity: 1,
  283. rotateZ: [20,0],
  284. translateY: function(el, index) {
  285. var p = el.parentNode,
  286. lastElOffW = p.lastElementChild.offsetWidth,
  287. firstElOffL = p.firstElementChild.offsetLeft,
  288. w = p.offsetWidth - lastElOffW - firstElOffL - (p.offsetWidth - lastElOffW - p.lastElementChild.offsetLeft),
  289. tyVal = lineEq(-130, -60, firstElOffL+w, firstElOffL, el.offsetLeft);
  290. return [Math.abs(tyVal)+'%','0%'];
  291. }
  292. },
  293. out: {
  294. duration: 400,
  295. easing: 'easeOutExpo',
  296. delay: function(el, index) { return (el.parentNode.children.length-index-1)*30; },
  297. opacity: 0,
  298. rotateZ: 20,
  299. translateY: function(el, index) {
  300. var p = el.parentNode,
  301. lastElOffW = p.lastElementChild.offsetWidth,
  302. firstElOffL = p.firstElementChild.offsetLeft,
  303. w = p.offsetWidth - lastElOffW - firstElOffL - (p.offsetWidth - lastElOffW - p.lastElementChild.offsetLeft),
  304. tyVal = lineEq(-60, -130, firstElOffL+w, firstElOffL, el.offsetLeft);
  305. return tyVal+'%';
  306. }
  307. }
  308. },
  309. 'fx15' : {
  310. perspective: 1000,
  311. in: {
  312. duration: 400,
  313. delay: function(el, index) { return 100+index*50; },
  314. easing: 'easeOutExpo',
  315. opacity: 1,
  316. rotateX: [110,0]
  317. },
  318. out: {
  319. duration: 400,
  320. delay: function(el, index) { return index*50; },
  321. easing: 'easeOutExpo',
  322. opacity: 0,
  323. rotateX: -110
  324. }
  325. },
  326. 'fx16' : {
  327. in: {
  328. duration: function(el, index) { return anime.random(800,1000) },
  329. delay: function(el, index) { return anime.random(0,75) },
  330. easing: 'easeInOutExpo',
  331. opacity: 1,
  332. translateY: ['-300%','0%'],
  333. rotateZ: function(el, index) { return [anime.random(-50,50), 0]; }
  334. },
  335. out: {
  336. duration: function(el, index) { return anime.random(800,1000) },
  337. delay: function(el, index) { return anime.random(0,80) },
  338. easing: 'easeInOutExpo',
  339. opacity: 0,
  340. translateY: '300%',
  341. rotateZ: function(el, index) { return anime.random(-50,50); }
  342. }
  343. },
  344. 'fx17' : {
  345. in: {
  346. duration: 650,
  347. easing: 'easeOutQuint',
  348. delay: function(el, index) { return 450+(el.parentNode.children.length-index-1)*30; },
  349. opacity: 1,
  350. translateX: function(el, index) {
  351. return [-1*el.offsetLeft,0];
  352. }
  353. },
  354. out: {
  355. duration: 1,
  356. delay: 400,
  357. opacity: 0
  358. }
  359. },
  360. 'fx18' : {
  361. in: {
  362. duration: 800,
  363. delay: function(el, index) { return 600+index*150; },
  364. easing: 'easeInOutQuint',
  365. opacity: 1,
  366. scaleY: [8,1],
  367. scaleX: [0.5,1],
  368. translateY: ['-100%','0%']
  369. },
  370. out: {
  371. duration: 800,
  372. delay: function(el, index) { return index*150; },
  373. easing: 'easeInQuint',
  374. opacity: 0,
  375. scaleY: {
  376. value: 8,
  377. delay: function(el, index) { return 100+index*150; },
  378. },
  379. scaleX: 0.5,
  380. translateY: '100%'
  381. }
  382. }
  383. };
  384. TextFx.prototype._init = function() {
  385. // Split word(s) into letters/spans.
  386. charming(this.el, {classPrefix: 'letter'});
  387. this.letters = [].slice.call(this.el.querySelectorAll('span'));
  388. this.lettersTotal = this.letters.length;
  389. };
  390. TextFx.prototype.show = function(effect, callback) {
  391. arguments.length ? this._animate('in', effect, callback) : this.letters.forEach(function(letter) { letter.style.opacity = 1; });
  392. };
  393. TextFx.prototype.hide = function(effect, callback) {
  394. if( arguments.length ) {
  395. this._animate('out', effect, callback);
  396. }
  397. else {
  398. anime.remove(this.letters);
  399. this.letters.forEach(function(letter) { letter.style.opacity = 0; })
  400. }
  401. };
  402. TextFx.prototype._animate = function(direction, effect, callback) {
  403. var effecSettings = typeof effect === 'string' ? this.effects[effect] : effect;
  404. if( effecSettings.perspective != undefined ) {
  405. this.el.style.WebkitPerspective = this.el.style.perspective = effecSettings.perspective + 'px';
  406. }
  407. if( effecSettings.origin != undefined ) {
  408. this.letters.forEach(function(letter) {
  409. letter.style.WebkitTransformOrigin = letter.style.transformOrigin = effecSettings.origin;
  410. });
  411. }
  412. // Custom effect
  413. var iscustom = this._checkCustomFx(direction, effect, callback);
  414. var animOpts = effecSettings[direction];
  415. animOpts.targets = this.letters;
  416. if( !iscustom ) {
  417. animOpts.complete = callback;
  418. }
  419. anime(animOpts);
  420. };
  421. /**
  422. * Extra stuff for an effect.. this is just an example for effect 17.
  423. * TODO! (for now, just some quick way to implement something different only for fx17)
  424. */
  425. TextFx.prototype._checkCustomFx = function(direction, effect, callback) {
  426. var custom = typeof effect === 'string' && effect === 'fx17' && direction === 'out';
  427. if( custom ) {
  428. var tmp = document.createElement('div');
  429. tmp.style.width = tmp.style.height = '100%';
  430. tmp.style.top = tmp.style.left = 0;
  431. tmp.style.background = '#e24b1e';
  432. tmp.style.position = 'absolute';
  433. tmp.style.WebkitTransform = tmp.style.transform = 'scale3d(0,1,1)';
  434. tmp.style.WebkitTransformOrigin = tmp.style.transformOrigin = '0% 50%';
  435. this.el.appendChild(tmp);
  436. var self = this;
  437. anime({
  438. targets: tmp,
  439. duration: 400,
  440. easing: 'easeInOutCubic',
  441. scaleX: [0,1],
  442. complete: function() {
  443. tmp.style.WebkitTransformOrigin = tmp.style.transformOrigin = '100% 50%';
  444. anime({
  445. targets: tmp,
  446. duration: 400,
  447. easing: 'easeInOutCubic',
  448. scaleX: [1,0],
  449. complete: function() {
  450. self.el.removeChild(tmp);
  451. if( typeof callback === 'function' ) {
  452. callback();
  453. }
  454. }
  455. });
  456. }
  457. });
  458. }
  459. return custom;
  460. };
  461. window.TextFx = TextFx;
  462. })(window);