├── .babelrc ├── dist ├── .gitignore ├── request-frame.es.js └── request-frame.js ├── .gitignore ├── .npmignore ├── test ├── compatibility │ ├── amd │ │ ├── native.js │ │ └── assign.js │ ├── compatibility-assignation-amd.html │ ├── compatibility-native.html │ ├── compatibility-native-amd.html │ └── compatibility-assignation.html ├── system.js ├── index.html └── test.js ├── rollup ├── rollup.config.es.js └── rollup.config.umd.js ├── bower.json ├── LICENSE ├── gulpfile.babel.js ├── package.json ├── demo └── fps.html ├── README.md └── src └── request-frame.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } -------------------------------------------------------------------------------- /dist/.gitignore: -------------------------------------------------------------------------------- 1 | #request-frame.js 2 | #request-frame.min.js 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | project 3 | npm-debug.log 4 | dummy.js 5 | yarn.lock -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | project 3 | npm-debug.log 4 | dummy.js 5 | yarn.lock 6 | rollup 7 | src 8 | test 9 | .babelrc 10 | bower.json 11 | gulpfile.babel.js 12 | -------------------------------------------------------------------------------- /test/compatibility/amd/native.js: -------------------------------------------------------------------------------- 1 | requirejs.config({ 2 | baseUrl: '../../dist', 3 | }); 4 | requirejs(['request-frame'], 5 | function(requestFrame) { 6 | // Re-assign native functions 7 | requestFrame('native'); 8 | }); 9 | -------------------------------------------------------------------------------- /rollup/rollup.config.es.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | 3 | export default { 4 | moduleName: 'requestFrame', 5 | entry: 'src/request-frame.js', 6 | plugins: [babel({ 7 | babelrc: false, 8 | exclude: 'node_modules/**' 9 | })], 10 | format: 'es', 11 | dest: 'dist/request-frame.es.js' 12 | }; 13 | -------------------------------------------------------------------------------- /rollup/rollup.config.umd.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | 3 | export default { 4 | moduleName: 'requestFrame', 5 | entry: './src/request-frame.js', 6 | plugins: [babel({ 7 | babelrc: false, 8 | presets: ["es2015-rollup"] 9 | })], 10 | format: 'umd', 11 | dest: './dist/request-frame.js' 12 | }; 13 | -------------------------------------------------------------------------------- /test/system.js: -------------------------------------------------------------------------------- 1 | describe('System check', function () { 2 | it('DeStijl function exists', function () { 3 | expect(_deStijl).to.be.a('function'); 4 | }); 5 | it('Style namespace to exist as an object', function(){ 6 | var obj = _deStijl.isObject(style); 7 | expect(obj).to.be.true; 8 | }); 9 | it('Version should be a string', function(){ 10 | expect(DeStijl.version).to.be.a('string'); 11 | }) 12 | }); 13 | -------------------------------------------------------------------------------- /test/compatibility/amd/assign.js: -------------------------------------------------------------------------------- 1 | requirejs.config({ 2 | baseUrl: '../../dist', 3 | }); 4 | requirejs(['request-frame'], 5 | function(requestFrame) { 6 | var div = document.getElementsByTagName('div'); 7 | 8 | // Assign functions 9 | var request = requestFrame('request'); 10 | var cancel = requestFrame('cancel'); 11 | 12 | // Expose the functions on screen 13 | (function exposeFunctions(timestamp) { 14 | 15 | // Show the request function 16 | div[0].innerHTML = request; 17 | 18 | // Show the cancel function 19 | div[1].innerHTML = cancel; 20 | 21 | // Show the high resolution timestamp 22 | div[2].innerHTML = timestamp; 23 | 24 | // request the frame 25 | request(exposeFunctions); 26 | }()); 27 | }); 28 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "request-frame", 3 | "version": "1.5.3", 4 | "description": "requestAnimationFrame & cancelAnimationFrame polyfill for optimal cross-browser development.", 5 | "main": "dist/request-frame.js", 6 | "moduleType": [ 7 | "amd", 8 | "globals" 9 | ], 10 | "keywords": [ 11 | "requestAnimationFrame", 12 | "webkitRequestAnimationFrame", 13 | "mozRequestAnimationFrame", 14 | "cancelAnimationFrame", 15 | "mozCancelAnimationFrame", 16 | "webkitCancelAnimationFrame", 17 | "webkitCancelRequestAnimationFrame", 18 | "setTimeout", 19 | "cancelTimeout", 20 | "timing functions", 21 | "requestAnimationFrame polyfill", 22 | "polyfill", 23 | "animation timing", 24 | "animation timestamp" 25 | ], 26 | "author": "Julien Etienne", 27 | "license": "MIT", 28 | "ignore": [ 29 | "node_modules", 30 | "bower_components", 31 | "test" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2016 Julien Etienne 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | request-frame test 8 | 9 | 15 | 16 | 17 | 18 |
Chai supports: IE 9+, Chrome 7+, FireFox 4+ ' Safari 5+ only. For others use: compatibility-assignation.html compatibility-native.html 19 |
20 |
21 | 22 | 23 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/compatibility/compatibility-assignation-amd.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | AMD request-frame Assignation Check 9 | 27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 | 39 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | const version = '1.5.3'; 2 | 3 | 4 | import {src, dest, task, watch} from 'gulp-es-next'; 5 | import concat from 'gulp-concat'; 6 | import rename from 'gulp-rename'; 7 | import header from 'gulp-header'; 8 | import bump from 'gulp-bump'; 9 | import pkg from './package.json'; 10 | 11 | 12 | const banner = ['/**', 13 | ' * <%= pkg.name %> - requestAnimationFrame & cancelAnimationFrame polyfill for', 14 | ' * optimal cross-browser development.', 15 | ' * Version: v<%= pkg.version %>', 16 | ' * License: <%= pkg.license %>', 17 | ' * Copyright <%= pkg.author %> 2015 All Rights Reserved.', 18 | ' * github: <%= pkg.repository.url %>', 19 | ' *‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾', 20 | ' */', 21 | '' 22 | ].join('\n'); 23 | 24 | 25 | const minBanner = ['/**', 26 | ' * <%= pkg.name %> - <%= pkg.description %>', 27 | ' * @version v<%= pkg.version %>', 28 | ' * @license <%= pkg.license %>', 29 | ' * Copyright <%= pkg.author %> 2015 All Rights Reserved.', 30 | ' */', 31 | '' 32 | ].join('\n'); 33 | 34 | 35 | task('Add header to ES version', function() { 36 | return src('./dist/request-frame.es.js') 37 | .pipe(header(minBanner, { 38 | pkg: pkg 39 | })) 40 | .pipe(dest('./dist')); 41 | }); 42 | 43 | 44 | task('Add header to UMD version', function() { 45 | return src('./dist/request-frame.js') 46 | .pipe(header(minBanner, { 47 | pkg: pkg 48 | })) 49 | .pipe(dest('./dist')); 50 | }); 51 | 52 | 53 | task('bump', function(){ 54 | src(['./bower.json','./package.json']) 55 | .pipe(bump({version: version})) 56 | .pipe(dest('./')); 57 | }); 58 | 59 | 60 | task('default', [ 61 | 'Add header to ES version', 62 | 'Add header to UMD version' 63 | ]); 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "request-frame", 3 | "version": "1.5.3", 4 | "description": "requestAnimationFrame & cancelAnimationFrame polyfill for optimal cross-browser development.", 5 | "main": "dist/request-frame.js", 6 | "jsnext:main": "dist/request-frame.es.js", 7 | "scripts": { 8 | "bump": "gulp bump", 9 | "header": "gulp", 10 | "build": "rollup -c rollup/rollup.config.umd.js && rollup -c rollup/rollup.config.es.js", 11 | "watch": "rollup -c rollup/rollup.config.umd.js -c --watch", 12 | "test": "./node_modules/.bin/http-server ./ -p 9999", 13 | "dummy": "wzrd dummy.js | wtch | garnish" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/julienetie/request-frame" 18 | }, 19 | "keywords": [ 20 | "requestAnimationFrame", 21 | "webkitRequestAnimationFrame", 22 | "mozRequestAnimationFrame", 23 | "cancelAnimationFrame", 24 | "mozCancelAnimationFrame", 25 | "webkitCancelAnimationFrame", 26 | "webkitCancelRequestAnimationFrame", 27 | "setTimeout", 28 | "cancelTimeout", 29 | "timing functions", 30 | "requestAnimationFrame polyfill", 31 | "polyfill", 32 | "animation timing", 33 | "animation timestamp" 34 | ], 35 | "author": "Julien Etienne", 36 | "license": "MIT", 37 | "bugs": { 38 | "url": "https://github.com/julienetie/request-frame/issues" 39 | }, 40 | "homepage": "https://github.com/julienetie/request-frame", 41 | "devDependencies": { 42 | "babel-cli": "*", 43 | "babel-preset-es2015": "*", 44 | "babel-preset-es2015-rollup": "^1.2.0", 45 | "chai": "*", 46 | "gulp": "^3.9.1", 47 | "gulp-bump": "*", 48 | "gulp-concat": "*", 49 | "gulp-es-next": "*", 50 | "gulp-header": "*", 51 | "gulp-rename": "*", 52 | "http-server": "*", 53 | "mocha": "*", 54 | "requirejs": "*", 55 | "rollup": "*", 56 | "rollup-plugin-babel": "*", 57 | "rollup-watch": "*" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/compatibility/compatibility-native.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | SRC request-frame Native Check 9 | 27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 | 39 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /test/compatibility/compatibility-native-amd.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | AMD request-frame Native Check 9 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /test/compatibility/compatibility-assignation.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | SRC request-frame Assignation Check 9 | 10 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /demo/fps.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FPS demo 7 | 8 | 9 | 10 |
11 | 12 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `* *` _If you are not supporting browsers from IE9 and below, you probably don't need this or any equivalent polyfill_ `* *` 2 | 3 | # request-frame 4 | 5 | ### A comprehensive requestAnimationFrame & cancelAnimationFrame polyfill. 6 | 7 | - Supports ES6 - AMD - CJS & IIFE 8 | - Provides a clean polyfill for requestAnimationFrame & cancelAnimationFrame. 9 | - Tested & working on: IE 5.5+, FF 3+, Opera 11.16+, Safari 4+, Chrome 14+, iOS 3+, Android 2.3+, Android Chrome 28+. 10 | - **iOS 6 bug fix** without user-agent sniffing. 11 | - **Firefox 4 - 10 function mismatch normalization**. 12 | - Doesn't modify native functions unless specified. 13 | - AMD compliant. 14 | 15 | #### Install options 16 | 17 | `npm i request-frame --save` **  |  ** `bower i request-frame` **  |  ** [src](https://github.com/julienetie/request-frame/tree/master/dist) **  |  ** [release](https://github.com/julienetie/request-frame/releases) 18 | 19 | 20 | ```javascript 21 | import requestFrame from 'request-frame'; // ES6 22 | ``` 23 | 24 | ```javascript 25 | // AMD, IIFE 26 | ``` 27 | 28 | ```javascript 29 | const requestFrame = require('request-frame'); // CJS 30 | ``` 31 | 32 | 33 | ### The API: 34 | #### Assign the timing functions: 35 | *requestFrame( request | cancel | native )* request is default. 36 | ```javascript 37 | var request = requestFrame('request'); // window.requestAnimationFrame | setTimeout 38 | var cancel = requestFrame('cancel'); // window.cancelAnimationFrame | cancelTimeout 39 | ``` 40 | #### Or re/ assign native functions: 41 | ```javascript 42 | requestFrame('native'); // re/ declares requestAnimationFrame & cancelAnimationFrame 43 | ``` 44 | Below is just an example of the requestAnimationFrame API, see links: [MDN](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame), [MSDN](https://msdn.microsoft.com/en-us/library/windows/apps/hh453388.aspx) & [W3](http://www.w3.org/TR/2011/WD-html5-20110525/timers.html). 45 | 46 | #### Loop something: 47 | ```javascript 48 | var requestId; 49 | 50 | function something( useTimeStamp ){ 51 | 52 | // Do something here 53 | 54 | requestId = request(something); 55 | } 56 | 57 | requestId = request(something); // Assigns Id & calls "something" 58 | ``` 59 | 60 | #### Cancel something: 61 | 62 | ```javascript 63 | cancel(requestId); // Cancels frame request 64 | ``` 65 | 66 | ### The ideology 67 | request-frame aims to provide an optimal development consistency with the use of animation timing functions across the large number of browsers and devices. This lib is ideal for those who may want to avoid re-assigning native functions, or avoid interfering with other libs that do. requestFrame() is purposely not a constructor. The intention is for requestAnimationFrame to be used once or few times during execution since multiple task are expected to be more efficient via a single requestAnimationFrame loop compared to several instances. 68 | 69 | ### Browsers tested & passing: 70 | 71 | Supports everything from IE5+ 72 | 73 | 74 | ### Contribute 75 | Just do it! 76 | 77 | #### Test 78 | `npm run test` 79 | To launch port 9999 80 | 81 | - ./test/ 82 | - ./test/compatibility-assignation-amd.html 83 | - ./test/compatibility-assignation.html 84 | - ./test/compatibility-native-amd.html 85 | - ./test/compatibility-native.html 86 | 87 | _Browser based testing for RAF is imperative_ 88 | 89 | --- 90 | 91 | [MIT License](https://github.com/julienetie/request-frame/blob/master/LICENSE) 92 | 93 | © 2016 Julien Etienne 94 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var expect = chai.expect, 2 | 3 | err = new ReferenceError('RequestFrame parameter is not a type.'), 4 | native = 'native', 5 | request = 'request', 6 | cancel = 'cancel', 7 | rAF = window.requestAnimationFrame || 8 | window.mozRequestAnimationFrame || 9 | window.webkitRequestAnimationFrame, 10 | 11 | cAF = window.cancelAnimationFrame || 12 | window.mozCancelAnimationFrame || 13 | window.webkitCancelAnimationFrame || 14 | window.webkitCancelRequestAnimationFrame; 15 | 16 | function isRequestOrSetFn(func) { 17 | 18 | var reference = func.toString(), 19 | referenceLower = reference.toLowerCase(), 20 | containsRequest = referenceLower.indexOf('request') > -1, 21 | containsSet = referenceLower.indexOf('set') > -1, 22 | results = containsRequest || containsSet ? true : false; 23 | return results; 24 | } 25 | 26 | function isCancellationFn(func) { 27 | var reference = func.toString(), 28 | referenceLower = reference.toLowerCase(), 29 | containsCancel = referenceLower.indexOf('cancel') > -1, 30 | containsClear = referenceLower.indexOf('clear') > -1, 31 | results = containsCancel || containsClear ? true : false; 32 | return results; 33 | } 34 | 35 | function isAnimationFrameFunction(func) { 36 | if (!func) { 37 | return; 38 | } 39 | var reference = func.toString(); 40 | reference = reference.indexOf('AnimationFrame') > -1; 41 | return reference; 42 | } 43 | 44 | 45 | 46 | // Production steps of ECMA-262, Edition 5, 15.4.4.14 47 | // Reference: http://es5.github.io/#x15.4.4.14 48 | if (!Array.prototype.indexOf) { 49 | Array.prototype.indexOf = function(searchElement, fromIndex) { 50 | 51 | var k; 52 | 53 | // 1. Let O be the result of calling ToObject passing 54 | // the this value as the argument. 55 | if (this == null) { 56 | throw new TypeError('"this" is null or not defined'); 57 | } 58 | 59 | var O = Object(this); 60 | 61 | // 2. Let lenValue be the result of calling the Get 62 | // internal method of O with the argument "length". 63 | // 3. Let len be ToUint32(lenValue). 64 | var len = O.length >>> 0; 65 | 66 | // 4. If len is 0, return -1. 67 | if (len === 0) { 68 | return -1; 69 | } 70 | 71 | // 5. If argument fromIndex was passed let n be 72 | // ToInteger(fromIndex); else let n be 0. 73 | var n = +fromIndex || 0; 74 | 75 | if (Math.abs(n) === Infinity) { 76 | n = 0; 77 | } 78 | 79 | // 6. If n >= len, return -1. 80 | if (n >= len) { 81 | return -1; 82 | } 83 | 84 | // 7. If n >= 0, then Let k be n. 85 | // 8. Else, n<0, Let k be len - abs(n). 86 | // If k is less than 0, then let k be 0. 87 | k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); 88 | 89 | // 9. Repeat, while k < len 90 | while (k < len) { 91 | // a. Let Pk be ToString(k). 92 | // This is implicit for LHS operands of the in operator 93 | // b. Let kPresent be the result of calling the 94 | // HasProperty internal method of O with argument Pk. 95 | // This step can be combined with c 96 | // c. If kPresent is true, then 97 | // i. Let elementK be the result of calling the Get 98 | // internal method of O with the argument ToString(k). 99 | // ii. Let same be the result of applying the 100 | // Strict Equality Comparison Algorithm to 101 | // searchElement and elementK. 102 | // iii. If same is true, return k. 103 | if (k in O && O[k] === searchElement) { 104 | return k; 105 | } 106 | k++; 107 | } 108 | return -1; 109 | }; 110 | } 111 | 112 | 113 | var RA = requestFrame('request'); 114 | var CA = requestFrame('cancel'); 115 | /** 116 | * Need to add iOS 6 + ff 4-10 bug checks. 117 | */ 118 | 119 | 120 | describe('requestFrame', function() { 121 | it('Should throw an error if type is not valid', function() { 122 | expect(function() { 123 | requestFrame(''); 124 | }).to 125 | .throw('RequestFrame parameter is not a type.'); 126 | }); 127 | }); 128 | 129 | 130 | 131 | describe('Native type', function() { 132 | before(function() { 133 | requestFrame(native); 134 | var hasNativeRequestFunction = window.requestAnimationFrame === rAF, 135 | hasNativeCancellationFunction = window.requestAnimationFrame === cAF; 136 | }); 137 | 138 | it('Should return nothing', function() { 139 | expect(requestFrame(native)).to.not.be.ok; 140 | }); 141 | 142 | it('Should set requestAnimationFrame as request or set function', function() { 143 | expect(isRequestOrSetFn(window.requestAnimationFrame)).to.be.ok; 144 | }); 145 | 146 | it('Should set cancelAnimationFrame as request or set function', function() { 147 | expect(isCancellationFn(window.cancelAnimationFrame)).to.be.ok; 148 | }); 149 | 150 | it('Should provide a matching pair of start and cancellation functions ', function() { 151 | expect(isAnimationFrameFunction(RA) === isAnimationFrameFunction(CA)).to.be.ok; 152 | }); 153 | }); 154 | 155 | 156 | 157 | describe('Request type', function() { 158 | it('Should return a request or set function', function() { 159 | expect(isRequestOrSetFn(RA)).to.be.ok; 160 | }); 161 | }); 162 | 163 | 164 | 165 | describe('Cancel type', function() { 166 | it('Should return a cancellation function', function() { 167 | expect(isCancellationFn(CA)).to.be.ok; 168 | }); 169 | }); 170 | 171 | 172 | 173 | describe('Request & cancel in conjunction', function() { 174 | it('Should provide a matching pair of start and cancellation functions ', function() { 175 | expect(isAnimationFrameFunction(RA) === isAnimationFrameFunction(CA)).to.be.ok; 176 | }); 177 | }); 178 | -------------------------------------------------------------------------------- /src/request-frame.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {String} type - request | cancel | native. 3 | * @return {Function} Timing function. 4 | */ 5 | export default function requestFrame(type) { 6 | // The only vendor prefixes required. 7 | const vendors = ['moz', 'webkit']; 8 | 9 | // Disassembled timing function abbreviations. 10 | const aF = 'AnimationFrame'; 11 | const rqAF = 'Request' + aF; 12 | 13 | // Checks for firefox 4 - 10 function pair mismatch. 14 | const mozRAF = window.mozRequestAnimationFrame; 15 | const mozCAF = window.mozCancelAnimationFrame; 16 | const hasMozMismatch = mozRAF && !mozCAF; 17 | 18 | // Final assigned functions. 19 | var assignedRequestAnimationFrame; 20 | var assignedCancelAnimationFrame; 21 | 22 | // Initial time of the timing lapse. 23 | var previousTime = 0; 24 | 25 | var requestFrameMain; 26 | 27 | // Date.now polyfill, mainly for legacy IE versions. 28 | if (!Date.now) { 29 | Date.now = function() { 30 | return new Date().getTime(); 31 | }; 32 | } 33 | 34 | /** 35 | * hasIOS6RequestAnimationFrameBug. 36 | * @See {@Link https://gist.github.com/julienetie/86ac394ec41f1271ff0a} 37 | * - for Commentary. 38 | * @Copyright 2015 - Julien Etienne. 39 | * @License: MIT. 40 | */ 41 | function hasIOS6RequestAnimationFrameBug() { 42 | const webkitRAF = window.webkitRequestAnimationFrame; 43 | const rAF = window.requestAnimationFrame; 44 | 45 | // CSS/ Device with max for iOS6 Devices. 46 | const hasMobileDeviceWidth = screen.width <= 768 ? true : false; 47 | 48 | // Only supports webkit prefixed requestAnimtionFrane. 49 | const requiresWebkitprefix = !(webkitRAF && rAF); 50 | 51 | // iOS6 webkit browsers don't support performance now. 52 | const hasNoNavigationTiming = window.performance ? false : true; 53 | 54 | const iOS6Notice = `setTimeout is being used as a substitiue for 55 | requestAnimationFrame due to a bug within iOS 6 builds`; 56 | 57 | const hasIOS6Bug = requiresWebkitprefix && hasMobileDeviceWidth && 58 | hasNoNavigationTiming; 59 | 60 | const bugCheckresults = (timingFnA, timingFnB, notice) => { 61 | if (timingFnA || timingFnB) { 62 | console.warn(notice); 63 | return true; 64 | } else { 65 | return false; 66 | } 67 | } 68 | 69 | const displayResults = (hasBug, hasBugNotice, webkitFn, nativeFn) => { 70 | if (hasBug) { 71 | return bugCheckresults(webkitFn, nativeFn, hasBugNotice); 72 | } else { 73 | return false; 74 | } 75 | } 76 | 77 | return displayResults(hasIOS6Bug, iOS6Notice,webkitRAF, rAF); 78 | } 79 | 80 | /** 81 | * Native clearTimeout function. 82 | * @return {Function} 83 | */ 84 | function clearTimeoutWithId(id) { 85 | clearTimeout(id); 86 | id = null; 87 | } 88 | 89 | /** 90 | * Based on a polyfill by Erik, introduced by Paul Irish & 91 | * further improved by Darius Bacon. 92 | * @see {@link http://www.paulirish.com/2011/ 93 | * requestanimationframe-for-smart-animating} 94 | * @see {@link https://github.com/darius/requestAnimationFrame/blob/ 95 | * master/requestAnimationFrame.js} 96 | * @callback {Number} Timestamp. 97 | * @return {Function} setTimeout Function. 98 | */ 99 | function setTimeoutWithTimestamp(callback) { 100 | let immediateTime = Date.now(); 101 | let lapsedTime = Math.max(previousTime + 16, immediateTime); 102 | return setTimeout(function() { 103 | callback(previousTime = lapsedTime); 104 | }, 105 | lapsedTime - immediateTime); 106 | } 107 | 108 | /** 109 | * Queries the native function, prefixed function 110 | * or use the setTimeoutWithTimestamp function. 111 | * @return {Function} 112 | */ 113 | function queryRequestAnimationFrame() { 114 | if (Array.prototype.filter) { 115 | assignedRequestAnimationFrame = window['request' + aF] || 116 | window[vendors.filter(function(vendor) { 117 | if (window[vendor + rqAF] !== undefined) 118 | return vendor; 119 | }) + rqAF] || setTimeoutWithTimestamp; 120 | } else { 121 | return setTimeoutWithTimestamp; 122 | } 123 | if (!hasIOS6RequestAnimationFrameBug()) { 124 | return assignedRequestAnimationFrame; 125 | } else { 126 | return setTimeoutWithTimestamp; 127 | } 128 | } 129 | 130 | /** 131 | * Queries the native function, prefixed function 132 | * or use the clearTimeoutWithId function. 133 | * @return {Function} 134 | */ 135 | function queryCancelAnimationFrame() { 136 | let cancellationNames = []; 137 | if (Array.prototype.map) { 138 | vendors.map(function(vendor) { 139 | return ['Cancel', 'CancelRequest'].map( 140 | function(cancellationNamePrefix) { 141 | cancellationNames.push(vendor + 142 | cancellationNamePrefix + aF); 143 | }); 144 | }); 145 | } else { 146 | return clearTimeoutWithId; 147 | } 148 | 149 | /** 150 | * Checks for the prefixed cancelAnimationFrame implementation. 151 | * @param {Array} prefixedNames - An array of the prefixed names. 152 | * @param {Number} i - Iteration start point. 153 | * @return {Function} prefixed cancelAnimationFrame function. 154 | */ 155 | function prefixedCancelAnimationFrame(prefixedNames, i) { 156 | let cancellationFunction; 157 | for (; i < prefixedNames.length; i++) { 158 | if (window[prefixedNames[i]]) { 159 | cancellationFunction = window[prefixedNames[i]]; 160 | break; 161 | } 162 | } 163 | return cancellationFunction; 164 | } 165 | 166 | // Use truthly function 167 | assignedCancelAnimationFrame = window['cancel' + aF] || 168 | prefixedCancelAnimationFrame(cancellationNames, 0) || 169 | clearTimeoutWithId; 170 | 171 | // Check for iOS 6 bug 172 | if (!hasIOS6RequestAnimationFrameBug()) { 173 | return assignedCancelAnimationFrame; 174 | } else { 175 | return clearTimeoutWithId; 176 | } 177 | } 178 | 179 | function getRequestFn() { 180 | if (hasMozMismatch) { 181 | return setTimeoutWithTimestamp; 182 | } else { 183 | return queryRequestAnimationFrame(); 184 | } 185 | } 186 | 187 | function getCancelFn() { 188 | return queryCancelAnimationFrame(); 189 | } 190 | 191 | function setNativeFn() { 192 | if (hasMozMismatch) { 193 | window.requestAnimationFrame = setTimeoutWithTimestamp; 194 | window.cancelAnimationFrame = clearTimeoutWithId; 195 | } else { 196 | window.requestAnimationFrame = queryRequestAnimationFrame(); 197 | window.cancelAnimationFrame = queryCancelAnimationFrame(); 198 | } 199 | } 200 | 201 | /** 202 | * The type value "request" singles out firefox 4 - 10 and 203 | * assigns the setTimeout function if plausible. 204 | */ 205 | 206 | switch (type) { 207 | case 'request': 208 | case '': 209 | requestFrameMain = getRequestFn(); 210 | break; 211 | 212 | case 'cancel': 213 | requestFrameMain = getCancelFn(); 214 | break; 215 | 216 | case 'native': 217 | setNativeFn(); 218 | break; 219 | default: 220 | throw new Error('RequestFrame parameter is not a type.'); 221 | } 222 | return requestFrameMain; 223 | } 224 | -------------------------------------------------------------------------------- /dist/request-frame.es.js: -------------------------------------------------------------------------------- 1 | /** 2 | * request-frame - requestAnimationFrame & cancelAnimationFrame polyfill for optimal cross-browser development. 3 | * @version v1.5.3 4 | * @license MIT 5 | * Copyright Julien Etienne 2015 All Rights Reserved. 6 | */ 7 | /** 8 | * @param {String} type - request | cancel | native. 9 | * @return {Function} Timing function. 10 | */ 11 | function requestFrame(type) { 12 | // The only vendor prefixes required. 13 | const vendors = ['moz', 'webkit']; 14 | 15 | // Disassembled timing function abbreviations. 16 | const aF = 'AnimationFrame'; 17 | const rqAF = 'Request' + aF; 18 | 19 | // Checks for firefox 4 - 10 function pair mismatch. 20 | const mozRAF = window.mozRequestAnimationFrame; 21 | const mozCAF = window.mozCancelAnimationFrame; 22 | const hasMozMismatch = mozRAF && !mozCAF; 23 | 24 | // Final assigned functions. 25 | var assignedRequestAnimationFrame; 26 | var assignedCancelAnimationFrame; 27 | 28 | // Initial time of the timing lapse. 29 | var previousTime = 0; 30 | 31 | var requestFrameMain; 32 | 33 | // Date.now polyfill, mainly for legacy IE versions. 34 | if (!Date.now) { 35 | Date.now = function () { 36 | return new Date().getTime(); 37 | }; 38 | } 39 | 40 | /** 41 | * hasIOS6RequestAnimationFrameBug. 42 | * @See {@Link https://gist.github.com/julienetie/86ac394ec41f1271ff0a} 43 | * - for Commentary. 44 | * @Copyright 2015 - Julien Etienne. 45 | * @License: MIT. 46 | */ 47 | function hasIOS6RequestAnimationFrameBug() { 48 | const webkitRAF = window.webkitRequestAnimationFrame; 49 | const rAF = window.requestAnimationFrame; 50 | 51 | // CSS/ Device with max for iOS6 Devices. 52 | const hasMobileDeviceWidth = screen.width <= 768 ? true : false; 53 | 54 | // Only supports webkit prefixed requestAnimtionFrane. 55 | const requiresWebkitprefix = !(webkitRAF && rAF); 56 | 57 | // iOS6 webkit browsers don't support performance now. 58 | const hasNoNavigationTiming = window.performance ? false : true; 59 | 60 | const iOS6Notice = `setTimeout is being used as a substitiue for 61 | requestAnimationFrame due to a bug within iOS 6 builds`; 62 | 63 | const hasIOS6Bug = requiresWebkitprefix && hasMobileDeviceWidth && hasNoNavigationTiming; 64 | 65 | const bugCheckresults = (timingFnA, timingFnB, notice) => { 66 | if (timingFnA || timingFnB) { 67 | console.warn(notice); 68 | return true; 69 | } else { 70 | return false; 71 | } 72 | }; 73 | 74 | const displayResults = (hasBug, hasBugNotice, webkitFn, nativeFn) => { 75 | if (hasBug) { 76 | return bugCheckresults(webkitFn, nativeFn, hasBugNotice); 77 | } else { 78 | return false; 79 | } 80 | }; 81 | 82 | return displayResults(hasIOS6Bug, iOS6Notice, webkitRAF, rAF); 83 | } 84 | 85 | /** 86 | * Native clearTimeout function. 87 | * @return {Function} 88 | */ 89 | function clearTimeoutWithId(id) { 90 | clearTimeout(id); 91 | } 92 | 93 | /** 94 | * Based on a polyfill by Erik, introduced by Paul Irish & 95 | * further improved by Darius Bacon. 96 | * @see {@link http://www.paulirish.com/2011/ 97 | * requestanimationframe-for-smart-animating} 98 | * @see {@link https://github.com/darius/requestAnimationFrame/blob/ 99 | * master/requestAnimationFrame.js} 100 | * @callback {Number} Timestamp. 101 | * @return {Function} setTimeout Function. 102 | */ 103 | function setTimeoutWithTimestamp(callback) { 104 | let immediateTime = Date.now(); 105 | let lapsedTime = Math.max(previousTime + 16, immediateTime); 106 | return setTimeout(function () { 107 | callback(previousTime = lapsedTime); 108 | }, lapsedTime - immediateTime); 109 | } 110 | 111 | /** 112 | * Queries the native function, prefixed function 113 | * or use the setTimeoutWithTimestamp function. 114 | * @return {Function} 115 | */ 116 | function queryRequestAnimationFrame() { 117 | if (Array.prototype.filter) { 118 | assignedRequestAnimationFrame = window['request' + aF] || window[vendors.filter(function (vendor) { 119 | if (window[vendor + rqAF] !== undefined) return vendor; 120 | }) + rqAF] || setTimeoutWithTimestamp; 121 | } else { 122 | return setTimeoutWithTimestamp; 123 | } 124 | if (!hasIOS6RequestAnimationFrameBug()) { 125 | return assignedRequestAnimationFrame; 126 | } else { 127 | return setTimeoutWithTimestamp; 128 | } 129 | } 130 | 131 | /** 132 | * Queries the native function, prefixed function 133 | * or use the clearTimeoutWithId function. 134 | * @return {Function} 135 | */ 136 | function queryCancelAnimationFrame() { 137 | let cancellationNames = []; 138 | if (Array.prototype.map) { 139 | vendors.map(function (vendor) { 140 | return ['Cancel', 'CancelRequest'].map(function (cancellationNamePrefix) { 141 | cancellationNames.push(vendor + cancellationNamePrefix + aF); 142 | }); 143 | }); 144 | } else { 145 | return clearTimeoutWithId; 146 | } 147 | 148 | /** 149 | * Checks for the prefixed cancelAnimationFrame implementation. 150 | * @param {Array} prefixedNames - An array of the prefixed names. 151 | * @param {Number} i - Iteration start point. 152 | * @return {Function} prefixed cancelAnimationFrame function. 153 | */ 154 | function prefixedCancelAnimationFrame(prefixedNames, i) { 155 | let cancellationFunction; 156 | for (; i < prefixedNames.length; i++) { 157 | if (window[prefixedNames[i]]) { 158 | cancellationFunction = window[prefixedNames[i]]; 159 | break; 160 | } 161 | } 162 | return cancellationFunction; 163 | } 164 | 165 | // Use truthly function 166 | assignedCancelAnimationFrame = window['cancel' + aF] || prefixedCancelAnimationFrame(cancellationNames, 0) || clearTimeoutWithId; 167 | 168 | // Check for iOS 6 bug 169 | if (!hasIOS6RequestAnimationFrameBug()) { 170 | return assignedCancelAnimationFrame; 171 | } else { 172 | return clearTimeoutWithId; 173 | } 174 | } 175 | 176 | function getRequestFn() { 177 | if (hasMozMismatch) { 178 | return setTimeoutWithTimestamp; 179 | } else { 180 | return queryRequestAnimationFrame(); 181 | } 182 | } 183 | 184 | function getCancelFn() { 185 | return queryCancelAnimationFrame(); 186 | } 187 | 188 | function setNativeFn() { 189 | if (hasMozMismatch) { 190 | window.requestAnimationFrame = setTimeoutWithTimestamp; 191 | window.cancelAnimationFrame = clearTimeoutWithId; 192 | } else { 193 | window.requestAnimationFrame = queryRequestAnimationFrame(); 194 | window.cancelAnimationFrame = queryCancelAnimationFrame(); 195 | } 196 | } 197 | 198 | /** 199 | * The type value "request" singles out firefox 4 - 10 and 200 | * assigns the setTimeout function if plausible. 201 | */ 202 | 203 | switch (type) { 204 | case 'request': 205 | case '': 206 | requestFrameMain = getRequestFn(); 207 | break; 208 | 209 | case 'cancel': 210 | requestFrameMain = getCancelFn(); 211 | break; 212 | 213 | case 'native': 214 | setNativeFn(); 215 | break; 216 | default: 217 | throw new Error('RequestFrame parameter is not a type.'); 218 | } 219 | return requestFrameMain; 220 | } 221 | 222 | export default requestFrame; 223 | -------------------------------------------------------------------------------- /dist/request-frame.js: -------------------------------------------------------------------------------- 1 | /** 2 | * request-frame - requestAnimationFrame & cancelAnimationFrame polyfill for optimal cross-browser development. 3 | * @version v1.5.3 4 | * @license MIT 5 | * Copyright Julien Etienne 2015 All Rights Reserved. 6 | */ 7 | (function (global, factory) { 8 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 9 | typeof define === 'function' && define.amd ? define(factory) : 10 | (global.requestFrame = factory()); 11 | }(this, (function () { 'use strict'; 12 | 13 | /** 14 | * @param {String} type - request | cancel | native. 15 | * @return {Function} Timing function. 16 | */ 17 | function requestFrame(type) { 18 | // The only vendor prefixes required. 19 | var vendors = ['moz', 'webkit']; 20 | 21 | // Disassembled timing function abbreviations. 22 | var aF = 'AnimationFrame'; 23 | var rqAF = 'Request' + aF; 24 | 25 | // Checks for firefox 4 - 10 function pair mismatch. 26 | var mozRAF = window.mozRequestAnimationFrame; 27 | var mozCAF = window.mozCancelAnimationFrame; 28 | var hasMozMismatch = mozRAF && !mozCAF; 29 | 30 | // Final assigned functions. 31 | var assignedRequestAnimationFrame; 32 | var assignedCancelAnimationFrame; 33 | 34 | // Initial time of the timing lapse. 35 | var previousTime = 0; 36 | 37 | var requestFrameMain; 38 | 39 | // Date.now polyfill, mainly for legacy IE versions. 40 | if (!Date.now) { 41 | Date.now = function () { 42 | return new Date().getTime(); 43 | }; 44 | } 45 | 46 | /** 47 | * hasIOS6RequestAnimationFrameBug. 48 | * @See {@Link https://gist.github.com/julienetie/86ac394ec41f1271ff0a} 49 | * - for Commentary. 50 | * @Copyright 2015 - Julien Etienne. 51 | * @License: MIT. 52 | */ 53 | function hasIOS6RequestAnimationFrameBug() { 54 | var webkitRAF = window.webkitRequestAnimationFrame; 55 | var rAF = window.requestAnimationFrame; 56 | 57 | // CSS/ Device with max for iOS6 Devices. 58 | var hasMobileDeviceWidth = screen.width <= 768 ? true : false; 59 | 60 | // Only supports webkit prefixed requestAnimtionFrane. 61 | var requiresWebkitprefix = !(webkitRAF && rAF); 62 | 63 | // iOS6 webkit browsers don't support performance now. 64 | var hasNoNavigationTiming = window.performance ? false : true; 65 | 66 | var iOS6Notice = 'setTimeout is being used as a substitiue for \n requestAnimationFrame due to a bug within iOS 6 builds'; 67 | 68 | var hasIOS6Bug = requiresWebkitprefix && hasMobileDeviceWidth && hasNoNavigationTiming; 69 | 70 | var bugCheckresults = function bugCheckresults(timingFnA, timingFnB, notice) { 71 | if (timingFnA || timingFnB) { 72 | console.warn(notice); 73 | return true; 74 | } else { 75 | return false; 76 | } 77 | }; 78 | 79 | var displayResults = function displayResults(hasBug, hasBugNotice, webkitFn, nativeFn) { 80 | if (hasBug) { 81 | return bugCheckresults(webkitFn, nativeFn, hasBugNotice); 82 | } else { 83 | return false; 84 | } 85 | }; 86 | 87 | return displayResults(hasIOS6Bug, iOS6Notice, webkitRAF, rAF); 88 | } 89 | 90 | /** 91 | * Native clearTimeout function. 92 | * @return {Function} 93 | */ 94 | function clearTimeoutWithId(id) { 95 | clearTimeout(id); 96 | } 97 | 98 | /** 99 | * Based on a polyfill by Erik, introduced by Paul Irish & 100 | * further improved by Darius Bacon. 101 | * @see {@link http://www.paulirish.com/2011/ 102 | * requestanimationframe-for-smart-animating} 103 | * @see {@link https://github.com/darius/requestAnimationFrame/blob/ 104 | * master/requestAnimationFrame.js} 105 | * @callback {Number} Timestamp. 106 | * @return {Function} setTimeout Function. 107 | */ 108 | function setTimeoutWithTimestamp(callback) { 109 | var immediateTime = Date.now(); 110 | var lapsedTime = Math.max(previousTime + 16, immediateTime); 111 | return setTimeout(function () { 112 | callback(previousTime = lapsedTime); 113 | }, lapsedTime - immediateTime); 114 | } 115 | 116 | /** 117 | * Queries the native function, prefixed function 118 | * or use the setTimeoutWithTimestamp function. 119 | * @return {Function} 120 | */ 121 | function queryRequestAnimationFrame() { 122 | if (Array.prototype.filter) { 123 | assignedRequestAnimationFrame = window['request' + aF] || window[vendors.filter(function (vendor) { 124 | if (window[vendor + rqAF] !== undefined) return vendor; 125 | }) + rqAF] || setTimeoutWithTimestamp; 126 | } else { 127 | return setTimeoutWithTimestamp; 128 | } 129 | if (!hasIOS6RequestAnimationFrameBug()) { 130 | return assignedRequestAnimationFrame; 131 | } else { 132 | return setTimeoutWithTimestamp; 133 | } 134 | } 135 | 136 | /** 137 | * Queries the native function, prefixed function 138 | * or use the clearTimeoutWithId function. 139 | * @return {Function} 140 | */ 141 | function queryCancelAnimationFrame() { 142 | var cancellationNames = []; 143 | if (Array.prototype.map) { 144 | vendors.map(function (vendor) { 145 | return ['Cancel', 'CancelRequest'].map(function (cancellationNamePrefix) { 146 | cancellationNames.push(vendor + cancellationNamePrefix + aF); 147 | }); 148 | }); 149 | } else { 150 | return clearTimeoutWithId; 151 | } 152 | 153 | /** 154 | * Checks for the prefixed cancelAnimationFrame implementation. 155 | * @param {Array} prefixedNames - An array of the prefixed names. 156 | * @param {Number} i - Iteration start point. 157 | * @return {Function} prefixed cancelAnimationFrame function. 158 | */ 159 | function prefixedCancelAnimationFrame(prefixedNames, i) { 160 | var cancellationFunction = void 0; 161 | for (; i < prefixedNames.length; i++) { 162 | if (window[prefixedNames[i]]) { 163 | cancellationFunction = window[prefixedNames[i]]; 164 | break; 165 | } 166 | } 167 | return cancellationFunction; 168 | } 169 | 170 | // Use truthly function 171 | assignedCancelAnimationFrame = window['cancel' + aF] || prefixedCancelAnimationFrame(cancellationNames, 0) || clearTimeoutWithId; 172 | 173 | // Check for iOS 6 bug 174 | if (!hasIOS6RequestAnimationFrameBug()) { 175 | return assignedCancelAnimationFrame; 176 | } else { 177 | return clearTimeoutWithId; 178 | } 179 | } 180 | 181 | function getRequestFn() { 182 | if (hasMozMismatch) { 183 | return setTimeoutWithTimestamp; 184 | } else { 185 | return queryRequestAnimationFrame(); 186 | } 187 | } 188 | 189 | function getCancelFn() { 190 | return queryCancelAnimationFrame(); 191 | } 192 | 193 | function setNativeFn() { 194 | if (hasMozMismatch) { 195 | window.requestAnimationFrame = setTimeoutWithTimestamp; 196 | window.cancelAnimationFrame = clearTimeoutWithId; 197 | } else { 198 | window.requestAnimationFrame = queryRequestAnimationFrame(); 199 | window.cancelAnimationFrame = queryCancelAnimationFrame(); 200 | } 201 | } 202 | 203 | /** 204 | * The type value "request" singles out firefox 4 - 10 and 205 | * assigns the setTimeout function if plausible. 206 | */ 207 | 208 | switch (type) { 209 | case 'request': 210 | case '': 211 | requestFrameMain = getRequestFn(); 212 | break; 213 | 214 | case 'cancel': 215 | requestFrameMain = getCancelFn(); 216 | break; 217 | 218 | case 'native': 219 | setNativeFn(); 220 | break; 221 | default: 222 | throw new Error('RequestFrame parameter is not a type.'); 223 | } 224 | return requestFrameMain; 225 | } 226 | 227 | return requestFrame; 228 | 229 | }))); 230 | --------------------------------------------------------------------------------