favico.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /**
  2. * @license MIT or GPL-2.0
  3. * @fileOverview Favico animations
  4. * @author Miroslav Magda, http://blog.ejci.net
  5. * @source: https://github.com/ejci/favico.js
  6. * @version 0.3.10
  7. */
  8. /**
  9. * Create new favico instance
  10. * @param {Object} Options
  11. * @return {Object} Favico object
  12. * @example
  13. * var favico = new Favico({
  14. * bgColor : '#d00',
  15. * textColor : '#fff',
  16. * fontFamily : 'sans-serif',
  17. * fontStyle : 'bold',
  18. * type : 'circle',
  19. * position : 'down',
  20. * animation : 'slide',
  21. * elementId: false,
  22. * element: null,
  23. * dataUrl: function(url){},
  24. * win: window
  25. * });
  26. */
  27. (function () {
  28. var Favico = (function (opt) {
  29. 'use strict';
  30. opt = (opt) ? opt : {};
  31. var _def = {
  32. bgColor: '#d00',
  33. textColor: '#fff',
  34. fontFamily: 'sans-serif', //Arial,Verdana,Times New Roman,serif,sans-serif,...
  35. fontStyle: 'bold', //normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900
  36. type: 'circle',
  37. position: 'down', // down, up, left, leftup (upleft)
  38. animation: 'slide',
  39. elementId: false,
  40. element: null,
  41. dataUrl: false,
  42. win: window
  43. };
  44. var _opt, _orig, _h, _w, _canvas, _context, _img, _ready, _lastBadge, _running, _readyCb, _stop, _browser, _animTimeout, _drawTimeout, _doc;
  45. _browser = {};
  46. _browser.ff = typeof InstallTrigger != 'undefined';
  47. _browser.chrome = !!window.chrome;
  48. _browser.opera = !!window.opera || navigator.userAgent.indexOf('Opera') >= 0;
  49. _browser.ie = /*@cc_on!@*/false;
  50. _browser.safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
  51. _browser.supported = (_browser.chrome || _browser.ff || _browser.opera);
  52. var _queue = [];
  53. _readyCb = function () {
  54. };
  55. _ready = _stop = false;
  56. /**
  57. * Initialize favico
  58. */
  59. var init = function () {
  60. //merge initial options
  61. _opt = merge(_def, opt);
  62. _opt.bgColor = hexToRgb(_opt.bgColor);
  63. _opt.textColor = hexToRgb(_opt.textColor);
  64. _opt.position = _opt.position.toLowerCase();
  65. _opt.animation = (animation.types['' + _opt.animation]) ? _opt.animation : _def.animation;
  66. _doc = _opt.win.document;
  67. var isUp = _opt.position.indexOf('up') > -1;
  68. var isLeft = _opt.position.indexOf('left') > -1;
  69. //transform the animations
  70. if (isUp || isLeft) {
  71. for (var a in animation.types) {
  72. for (var i = 0; i < animation.types[a].length; i++) {
  73. var step = animation.types[a][i];
  74. if (isUp) {
  75. if (step.y < 0.6) {
  76. step.y = step.y - 0.4;
  77. } else {
  78. step.y = step.y - 2 * step.y + (1 - step.w);
  79. }
  80. }
  81. if (isLeft) {
  82. if (step.x < 0.6) {
  83. step.x = step.x - 0.4;
  84. } else {
  85. step.x = step.x - 2 * step.x + (1 - step.h);
  86. }
  87. }
  88. animation.types[a][i] = step;
  89. }
  90. }
  91. }
  92. _opt.type = (type['' + _opt.type]) ? _opt.type : _def.type;
  93. _orig = link. getIcons();
  94. //create temp canvas
  95. _canvas = document.createElement('canvas');
  96. //create temp image
  97. _img = document.createElement('img');
  98. var lastIcon = _orig[_orig.length - 1];
  99. if (lastIcon.hasAttribute('href')) {
  100. _img.setAttribute('crossOrigin', 'anonymous');
  101. //get width/height
  102. _img.onload = function () {
  103. _h = (_img.height > 0) ? _img.height : 32;
  104. _w = (_img.width > 0) ? _img.width : 32;
  105. _canvas.height = _h;
  106. _canvas.width = _w;
  107. _context = _canvas.getContext('2d');
  108. icon.ready();
  109. };
  110. _img.setAttribute('src', lastIcon.getAttribute('href'));
  111. } else {
  112. _h = 32;
  113. _w = 32;
  114. _img.height = _h;
  115. _img.width = _w;
  116. _canvas.height = _h;
  117. _canvas.width = _w;
  118. _context = _canvas.getContext('2d');
  119. icon.ready();
  120. }
  121. };
  122. /**
  123. * Icon namespace
  124. */
  125. var icon = {};
  126. /**
  127. * Icon is ready (reset icon) and start animation (if ther is any)
  128. */
  129. icon.ready = function () {
  130. _ready = true;
  131. icon.reset();
  132. _readyCb();
  133. };
  134. /**
  135. * Reset icon to default state
  136. */
  137. icon.reset = function () {
  138. //reset
  139. if (!_ready) {
  140. return;
  141. }
  142. _queue = [];
  143. _lastBadge = false;
  144. _running = false;
  145. _context.clearRect(0, 0, _w, _h);
  146. _context.drawImage(_img, 0, 0, _w, _h);
  147. //_stop=true;
  148. link.setIcon(_canvas);
  149. //webcam('stop');
  150. //video('stop');
  151. window.clearTimeout(_animTimeout);
  152. window.clearTimeout(_drawTimeout);
  153. };
  154. /**
  155. * Start animation
  156. */
  157. icon.start = function () {
  158. if (!_ready || _running) {
  159. return;
  160. }
  161. var finished = function () {
  162. _lastBadge = _queue[0];
  163. _running = false;
  164. if (_queue.length > 0) {
  165. _queue.shift();
  166. icon.start();
  167. } else {
  168. }
  169. };
  170. if (_queue.length > 0) {
  171. _running = true;
  172. var run = function () {
  173. // apply options for this animation
  174. ['type', 'animation', 'bgColor', 'textColor', 'fontFamily', 'fontStyle'].forEach(function (a) {
  175. if (a in _queue[0].options) {
  176. _opt[a] = _queue[0].options[a];
  177. }
  178. });
  179. animation.run(_queue[0].options, function () {
  180. finished();
  181. }, false);
  182. };
  183. if (_lastBadge) {
  184. animation.run(_lastBadge.options, function () {
  185. run();
  186. }, true);
  187. } else {
  188. run();
  189. }
  190. }
  191. };
  192. /**
  193. * Badge types
  194. */
  195. var type = {};
  196. var options = function (opt) {
  197. opt.n = ((typeof opt.n) === 'number') ? Math.abs(opt.n | 0) : opt.n;
  198. opt.x = _w * opt.x;
  199. opt.y = _h * opt.y;
  200. opt.w = _w * opt.w;
  201. opt.h = _h * opt.h;
  202. opt.len = ("" + opt.n).length;
  203. return opt;
  204. };
  205. /**
  206. * Generate circle
  207. * @param {Object} opt Badge options
  208. */
  209. type.circle = function (opt) {
  210. opt = options(opt);
  211. var more = false;
  212. if (opt.len === 2) {
  213. opt.x = opt.x - opt.w * 0.4;
  214. opt.w = opt.w * 1.4;
  215. more = true;
  216. } else if (opt.len >= 3) {
  217. opt.x = opt.x - opt.w * 0.65;
  218. opt.w = opt.w * 1.65;
  219. more = true;
  220. }
  221. _context.clearRect(0, 0, _w, _h);
  222. _context.drawImage(_img, 0, 0, _w, _h);
  223. _context.beginPath();
  224. _context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.85 : 1)) + "px " + _opt.fontFamily;
  225. _context.textAlign = 'center';
  226. if (more) {
  227. _context.moveTo(opt.x + opt.w / 2, opt.y);
  228. _context.lineTo(opt.x + opt.w - opt.h / 2, opt.y);
  229. _context.quadraticCurveTo(opt.x + opt.w, opt.y, opt.x + opt.w, opt.y + opt.h / 2);
  230. _context.lineTo(opt.x + opt.w, opt.y + opt.h - opt.h / 2);
  231. _context.quadraticCurveTo(opt.x + opt.w, opt.y + opt.h, opt.x + opt.w - opt.h / 2, opt.y + opt.h);
  232. _context.lineTo(opt.x + opt.h / 2, opt.y + opt.h);
  233. _context.quadraticCurveTo(opt.x, opt.y + opt.h, opt.x, opt.y + opt.h - opt.h / 2);
  234. _context.lineTo(opt.x, opt.y + opt.h / 2);
  235. _context.quadraticCurveTo(opt.x, opt.y, opt.x + opt.h / 2, opt.y);
  236. } else {
  237. _context.arc(opt.x + opt.w / 2, opt.y + opt.h / 2, opt.h / 2, 0, 2 * Math.PI);
  238. }
  239. _context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')';
  240. _context.fill();
  241. _context.closePath();
  242. _context.beginPath();
  243. _context.stroke();
  244. _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')';
  245. //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
  246. if ((typeof opt.n) === 'number' && opt.n > 999) {
  247. _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
  248. } else {
  249. _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
  250. }
  251. _context.closePath();
  252. };
  253. /**
  254. * Generate rectangle
  255. * @param {Object} opt Badge options
  256. */
  257. type.rectangle = function (opt) {
  258. opt = options(opt);
  259. var more = false;
  260. if (opt.len === 2) {
  261. opt.x = opt.x - opt.w * 0.4;
  262. opt.w = opt.w * 1.4;
  263. more = true;
  264. } else if (opt.len >= 3) {
  265. opt.x = opt.x - opt.w * 0.65;
  266. opt.w = opt.w * 1.65;
  267. more = true;
  268. }
  269. _context.clearRect(0, 0, _w, _h);
  270. _context.drawImage(_img, 0, 0, _w, _h);
  271. _context.beginPath();
  272. _context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.9 : 1)) + "px " + _opt.fontFamily;
  273. _context.textAlign = 'center';
  274. _context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')';
  275. _context.fillRect(opt.x, opt.y, opt.w, opt.h);
  276. _context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')';
  277. //_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
  278. if ((typeof opt.n) === 'number' && opt.n > 999) {
  279. _context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000)) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
  280. } else {
  281. _context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
  282. }
  283. _context.closePath();
  284. };
  285. /**
  286. * Set badge
  287. */
  288. var badge = function (number, opts) {
  289. opts = ((typeof opts) === 'string' ? {
  290. animation: opts
  291. } : opts) || {};
  292. _readyCb = function () {
  293. try {
  294. if (typeof (number) === 'number' ? (number > 0) : (number !== '')) {
  295. var q = {
  296. type: 'badge',
  297. options: {
  298. n: number
  299. }
  300. };
  301. if ('animation' in opts && animation.types['' + opts.animation]) {
  302. q.options.animation = '' + opts.animation;
  303. }
  304. if ('type' in opts && type['' + opts.type]) {
  305. q.options.type = '' + opts.type;
  306. }
  307. ['bgColor', 'textColor'].forEach(function (o) {
  308. if (o in opts) {
  309. q.options[o] = hexToRgb(opts[o]);
  310. }
  311. });
  312. ['fontStyle', 'fontFamily'].forEach(function (o) {
  313. if (o in opts) {
  314. q.options[o] = opts[o];
  315. }
  316. });
  317. _queue.push(q);
  318. if (_queue.length > 100) {
  319. throw new Error('Too many badges requests in queue.');
  320. }
  321. icon.start();
  322. } else {
  323. icon.reset();
  324. }
  325. } catch (e) {
  326. throw new Error('Error setting badge. Message: ' + e.message);
  327. }
  328. };
  329. if (_ready) {
  330. _readyCb();
  331. }
  332. };
  333. var setOpt = function (key, value) {
  334. var opts = key;
  335. if (!(value == null && Object.prototype.toString.call(key) == '[object Object]')) {
  336. opts = {};
  337. opts[key] = value;
  338. }
  339. var keys = Object.keys(opts);
  340. for (var i = 0; i < keys.length; i++) {
  341. if (keys[i] == 'bgColor' || keys[i] == 'textColor') {
  342. _opt[keys[i]] = hexToRgb(opts[keys[i]]);
  343. } else {
  344. _opt[keys[i]] = opts[keys[i]];
  345. }
  346. }
  347. _queue.push(_lastBadge);
  348. icon.start();
  349. };
  350. var link = {};
  351. /**
  352. * Get icons from HEAD tag or create a new <link> element
  353. */
  354. link.getIcons = function () {
  355. var elms = [];
  356. //get link element
  357. var getLinks = function () {
  358. var icons = [];
  359. var links = _doc.getElementsByTagName('head')[0].getElementsByTagName('link');
  360. for (var i = 0; i < links.length; i++) {
  361. if ((/(^|\s)icon(\s|$)/i).test(links[i].getAttribute('rel'))) {
  362. icons.push(links[i]);
  363. }
  364. }
  365. return icons;
  366. };
  367. if (_opt.element) {
  368. elms = [_opt.element];
  369. } else if (_opt.elementId) {
  370. //if img element identified by elementId
  371. elms = [_doc.getElementById(_opt.elementId)];
  372. elms[0].setAttribute('href', elms[0].getAttribute('src'));
  373. } else {
  374. //if link element
  375. elms = getLinks();
  376. if (elms.length === 0) {
  377. elms = [_doc.createElement('link')];
  378. elms[0].setAttribute('rel', 'icon');
  379. _doc.getElementsByTagName('head')[0].appendChild(elms[0]);
  380. }
  381. }
  382. elms.forEach(function(item) {
  383. item.setAttribute('type', 'image/png');
  384. });
  385. return elms;
  386. };
  387. link.setIcon = function (canvas) {
  388. var url = canvas.toDataURL('image/png');
  389. link.setIconSrc(url);
  390. };
  391. link.setIconSrc = function (url) {
  392. if (_opt.dataUrl) {
  393. //if using custom exporter
  394. _opt.dataUrl(url);
  395. }
  396. if (_opt.element) {
  397. _opt.element.setAttribute('href', url);
  398. _opt.element.setAttribute('src', url);
  399. } else if (_opt.elementId) {
  400. //if is attached to element (image)
  401. var elm = _doc.getElementById(_opt.elementId);
  402. elm.setAttribute('href', url);
  403. elm.setAttribute('src', url);
  404. } else {
  405. //if is attached to fav icon
  406. if (_browser.ff || _browser.opera) {
  407. //for FF we need to "recreate" element, atach to dom and remove old <link>
  408. //var originalType = _orig.getAttribute('rel');
  409. var old = _orig[_orig.length - 1];
  410. var newIcon = _doc.createElement('link');
  411. _orig = [newIcon];
  412. //_orig.setAttribute('rel', originalType);
  413. if (_browser.opera) {
  414. newIcon.setAttribute('rel', 'icon');
  415. }
  416. newIcon.setAttribute('rel', 'icon');
  417. newIcon.setAttribute('type', 'image/png');
  418. _doc.getElementsByTagName('head')[0].appendChild(newIcon);
  419. newIcon.setAttribute('href', url);
  420. if (old.parentNode) {
  421. old.parentNode.removeChild(old);
  422. }
  423. } else {
  424. _orig.forEach(function(icon) {
  425. icon.setAttribute('href', url);
  426. });
  427. }
  428. }
  429. };
  430. //http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-5624139
  431. //HEX to RGB convertor
  432. function hexToRgb(hex) {
  433. var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  434. hex = hex.replace(shorthandRegex, function (m, r, g, b) {
  435. return r + r + g + g + b + b;
  436. });
  437. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  438. return result ? {
  439. r: parseInt(result[1], 16),
  440. g: parseInt(result[2], 16),
  441. b: parseInt(result[3], 16)
  442. } : false;
  443. }
  444. /**
  445. * Merge options
  446. */
  447. function merge(def, opt) {
  448. var mergedOpt = {};
  449. var attrname;
  450. for (attrname in def) {
  451. mergedOpt[attrname] = def[attrname];
  452. }
  453. for (attrname in opt) {
  454. mergedOpt[attrname] = opt[attrname];
  455. }
  456. return mergedOpt;
  457. }
  458. /**
  459. * Cross-browser page visibility shim
  460. * http://stackoverflow.com/questions/12536562/detect-whether-a-window-is-visible
  461. */
  462. function isPageHidden() {
  463. return _doc.hidden || _doc.msHidden || _doc.webkitHidden || _doc.mozHidden;
  464. }
  465. /**
  466. * @namespace animation
  467. */
  468. var animation = {};
  469. /**
  470. * Animation "frame" duration
  471. */
  472. animation.duration = 40;
  473. /**
  474. * Animation types (none,fade,pop,slide)
  475. */
  476. animation.types = {};
  477. animation.types.fade = [{
  478. x: 0.4,
  479. y: 0.4,
  480. w: 0.6,
  481. h: 0.6,
  482. o: 0.0
  483. }, {
  484. x: 0.4,
  485. y: 0.4,
  486. w: 0.6,
  487. h: 0.6,
  488. o: 0.1
  489. }, {
  490. x: 0.4,
  491. y: 0.4,
  492. w: 0.6,
  493. h: 0.6,
  494. o: 0.2
  495. }, {
  496. x: 0.4,
  497. y: 0.4,
  498. w: 0.6,
  499. h: 0.6,
  500. o: 0.3
  501. }, {
  502. x: 0.4,
  503. y: 0.4,
  504. w: 0.6,
  505. h: 0.6,
  506. o: 0.4
  507. }, {
  508. x: 0.4,
  509. y: 0.4,
  510. w: 0.6,
  511. h: 0.6,
  512. o: 0.5
  513. }, {
  514. x: 0.4,
  515. y: 0.4,
  516. w: 0.6,
  517. h: 0.6,
  518. o: 0.6
  519. }, {
  520. x: 0.4,
  521. y: 0.4,
  522. w: 0.6,
  523. h: 0.6,
  524. o: 0.7
  525. }, {
  526. x: 0.4,
  527. y: 0.4,
  528. w: 0.6,
  529. h: 0.6,
  530. o: 0.8
  531. }, {
  532. x: 0.4,
  533. y: 0.4,
  534. w: 0.6,
  535. h: 0.6,
  536. o: 0.9
  537. }, {
  538. x: 0.4,
  539. y: 0.4,
  540. w: 0.6,
  541. h: 0.6,
  542. o: 1.0
  543. }];
  544. animation.types.none = [{
  545. x: 0.4,
  546. y: 0.4,
  547. w: 0.6,
  548. h: 0.6,
  549. o: 1
  550. }];
  551. animation.types.pop = [{
  552. x: 1,
  553. y: 1,
  554. w: 0,
  555. h: 0,
  556. o: 1
  557. }, {
  558. x: 0.9,
  559. y: 0.9,
  560. w: 0.1,
  561. h: 0.1,
  562. o: 1
  563. }, {
  564. x: 0.8,
  565. y: 0.8,
  566. w: 0.2,
  567. h: 0.2,
  568. o: 1
  569. }, {
  570. x: 0.7,
  571. y: 0.7,
  572. w: 0.3,
  573. h: 0.3,
  574. o: 1
  575. }, {
  576. x: 0.6,
  577. y: 0.6,
  578. w: 0.4,
  579. h: 0.4,
  580. o: 1
  581. }, {
  582. x: 0.5,
  583. y: 0.5,
  584. w: 0.5,
  585. h: 0.5,
  586. o: 1
  587. }, {
  588. x: 0.4,
  589. y: 0.4,
  590. w: 0.6,
  591. h: 0.6,
  592. o: 1
  593. }];
  594. animation.types.popFade = [{
  595. x: 0.75,
  596. y: 0.75,
  597. w: 0,
  598. h: 0,
  599. o: 0
  600. }, {
  601. x: 0.65,
  602. y: 0.65,
  603. w: 0.1,
  604. h: 0.1,
  605. o: 0.2
  606. }, {
  607. x: 0.6,
  608. y: 0.6,
  609. w: 0.2,
  610. h: 0.2,
  611. o: 0.4
  612. }, {
  613. x: 0.55,
  614. y: 0.55,
  615. w: 0.3,
  616. h: 0.3,
  617. o: 0.6
  618. }, {
  619. x: 0.50,
  620. y: 0.50,
  621. w: 0.4,
  622. h: 0.4,
  623. o: 0.8
  624. }, {
  625. x: 0.45,
  626. y: 0.45,
  627. w: 0.5,
  628. h: 0.5,
  629. o: 0.9
  630. }, {
  631. x: 0.4,
  632. y: 0.4,
  633. w: 0.6,
  634. h: 0.6,
  635. o: 1
  636. }];
  637. animation.types.slide = [{
  638. x: 0.4,
  639. y: 1,
  640. w: 0.6,
  641. h: 0.6,
  642. o: 1
  643. }, {
  644. x: 0.4,
  645. y: 0.9,
  646. w: 0.6,
  647. h: 0.6,
  648. o: 1
  649. }, {
  650. x: 0.4,
  651. y: 0.9,
  652. w: 0.6,
  653. h: 0.6,
  654. o: 1
  655. }, {
  656. x: 0.4,
  657. y: 0.8,
  658. w: 0.6,
  659. h: 0.6,
  660. o: 1
  661. }, {
  662. x: 0.4,
  663. y: 0.7,
  664. w: 0.6,
  665. h: 0.6,
  666. o: 1
  667. }, {
  668. x: 0.4,
  669. y: 0.6,
  670. w: 0.6,
  671. h: 0.6,
  672. o: 1
  673. }, {
  674. x: 0.4,
  675. y: 0.5,
  676. w: 0.6,
  677. h: 0.6,
  678. o: 1
  679. }, {
  680. x: 0.4,
  681. y: 0.4,
  682. w: 0.6,
  683. h: 0.6,
  684. o: 1
  685. }];
  686. /**
  687. * Run animation
  688. * @param {Object} opt Animation options
  689. * @param {Object} cb Callabak after all steps are done
  690. * @param {Object} revert Reverse order? true|false
  691. * @param {Object} step Optional step number (frame bumber)
  692. */
  693. animation.run = function (opt, cb, revert, step) {
  694. var animationType = animation.types[isPageHidden() ? 'none' : _opt.animation];
  695. if (revert === true) {
  696. step = (typeof step !== 'undefined') ? step : animationType.length - 1;
  697. } else {
  698. step = (typeof step !== 'undefined') ? step : 0;
  699. }
  700. cb = (cb) ? cb : function () {
  701. };
  702. if ((step < animationType.length) && (step >= 0)) {
  703. type[_opt.type](merge(opt, animationType[step]));
  704. _animTimeout = setTimeout(function () {
  705. if (revert) {
  706. step = step - 1;
  707. } else {
  708. step = step + 1;
  709. }
  710. animation.run(opt, cb, revert, step);
  711. }, animation.duration);
  712. link.setIcon(_canvas);
  713. } else {
  714. cb();
  715. return;
  716. }
  717. };
  718. //auto init
  719. init();
  720. return {
  721. badge: badge,
  722. setOpt: setOpt,
  723. reset: icon.reset,
  724. browser: {
  725. supported: _browser.supported
  726. }
  727. };
  728. });
  729. // AMD / RequireJS
  730. if (typeof define !== 'undefined' && define.amd) {
  731. define([], function () {
  732. return Favico;
  733. });
  734. }
  735. // CommonJS
  736. else if (typeof module !== 'undefined' && module.exports) {
  737. module.exports = Favico;
  738. }
  739. // included directly via <script> tag
  740. else {
  741. this.Favico = Favico;
  742. }
  743. })();