├── .gitignore ├── polyfill.js ├── window.js ├── CHANGELOG.md ├── LICENSE ├── package.json ├── test.js ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /polyfill.js: -------------------------------------------------------------------------------- 1 | require('./').polyfill() 2 | -------------------------------------------------------------------------------- /window.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = window 3 | } catch(e) { 4 | module.exports = {} 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | ## [3.4.1] - 2018-11-02 4 | 5 | ### Added 6 | 7 | - License file added. Version bumped to update the npm package. [#39](https://github.com/chrisdickinson/raf/pull/39) 8 | 9 | ## [3.4.0] - 2017-10-01 10 | 11 | ### Changed 12 | 13 | - Make raf.polyfill optionally accept an object to attach the polyfills to. [#35](https://github.com/chrisdickinson/raf/pull/35) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Chris Dickinson 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "raf", 3 | "version": "3.4.1", 4 | "description": "requestAnimationFrame polyfill for node and the browser", 5 | "main": "index.js", 6 | "scripts": { 7 | "testling": "browserify test.js | testling", 8 | "test": "node test.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/chrisdickinson/raf.git" 13 | }, 14 | "keywords": [ 15 | "requestAnimationFrame", 16 | "polyfill" 17 | ], 18 | "author": "Chris Dickinson ", 19 | "contributors": [ 20 | "Christian Maughan Tegnér " 21 | ], 22 | "license": "MIT", 23 | "devDependencies": { 24 | "testling": "~1.6.1", 25 | "browserify": "~4.1.2", 26 | "tape": "^4.0.0" 27 | }, 28 | "dependencies": { 29 | "performance-now": "^2.1.0" 30 | }, 31 | "testling": { 32 | "files": "test.js", 33 | "browsers": [ 34 | "iexplore/6.0..latest", 35 | "firefox/3.0..6.0", 36 | "firefox/15.0..latest", 37 | "firefox/nightly", 38 | "chrome/4.0..10.0", 39 | "chrome/20.0..latest", 40 | "chrome/canary", 41 | "opera/10.0..latest", 42 | "opera/next", 43 | "safari/4.0..latest", 44 | "ipad/6.0..latest", 45 | "iphone/6.0..latest" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | , raf = require('./index.js') 3 | 4 | test('continues to emit events', function(t) { 5 | t.plan(11) 6 | 7 | var start = new Date().getTime() 8 | , times = 0 9 | 10 | raf(function tick(dt) { 11 | t.ok(dt >= 0, 'time has passed: ' + dt) 12 | if(++times == 10) { 13 | var elapsed = (new Date().getTime() - start) 14 | t.ok(elapsed >= 150, 'should take at least 9 frames worth of wall time: ' + elapsed) 15 | t.end() 16 | } else { 17 | raf(tick) 18 | } 19 | }) 20 | }) 21 | 22 | test('cancel removes callbacks from queue', function(t) { 23 | t.plan(6) 24 | 25 | function cb1() { cb1.called = true } 26 | function cb2() { cb2.called = true } 27 | function cb3() { cb3.called = true } 28 | 29 | var handle1 = raf(cb1) 30 | t.ok(handle1, 'returns a handle') 31 | var handle2 = raf(cb2) 32 | t.ok(handle2, 'returns a handle') 33 | var handle3 = raf(cb3) 34 | t.ok(handle3, 'returns a handle') 35 | 36 | raf.cancel(handle2) 37 | 38 | raf(function() { 39 | t.ok(cb1.called, 'callback was invoked') 40 | t.notOk(cb2.called, 'callback was cancelled') 41 | t.ok(cb3.called, 'callback was invoked') 42 | t.end() 43 | }) 44 | }) 45 | 46 | test('raf should throw on errors', function(t) { 47 | t.plan(1) 48 | 49 | var onError = function() { 50 | t.pass('error bubbled up to event loop') 51 | } 52 | 53 | if(typeof window !== 'undefined') { 54 | window.onerror = onError 55 | } else if(typeof process !== 'undefined') { 56 | process.on('uncaughtException', onError) 57 | } 58 | 59 | raf(function() { 60 | throw new Error('foo') 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var now = require('performance-now') 2 | , root = typeof window === 'undefined' ? global : window 3 | , vendors = ['moz', 'webkit'] 4 | , suffix = 'AnimationFrame' 5 | , raf = root['request' + suffix] 6 | , caf = root['cancel' + suffix] || root['cancelRequest' + suffix] 7 | 8 | for(var i = 0; !raf && i < vendors.length; i++) { 9 | raf = root[vendors[i] + 'Request' + suffix] 10 | caf = root[vendors[i] + 'Cancel' + suffix] 11 | || root[vendors[i] + 'CancelRequest' + suffix] 12 | } 13 | 14 | // Some versions of FF have rAF but not cAF 15 | if(!raf || !caf) { 16 | var last = 0 17 | , id = 0 18 | , queue = [] 19 | , frameDuration = 1000 / 60 20 | 21 | raf = function(callback) { 22 | if(queue.length === 0) { 23 | var _now = now() 24 | , next = Math.max(0, frameDuration - (_now - last)) 25 | last = next + _now 26 | setTimeout(function() { 27 | var cp = queue.slice(0) 28 | // Clear queue here to prevent 29 | // callbacks from appending listeners 30 | // to the current frame's queue 31 | queue.length = 0 32 | for(var i = 0; i < cp.length; i++) { 33 | if(!cp[i].cancelled) { 34 | try{ 35 | cp[i].callback(last) 36 | } catch(e) { 37 | setTimeout(function() { throw e }, 0) 38 | } 39 | } 40 | } 41 | }, Math.round(next)) 42 | } 43 | queue.push({ 44 | handle: ++id, 45 | callback: callback, 46 | cancelled: false 47 | }) 48 | return id 49 | } 50 | 51 | caf = function(handle) { 52 | for(var i = 0; i < queue.length; i++) { 53 | if(queue[i].handle === handle) { 54 | queue[i].cancelled = true 55 | } 56 | } 57 | } 58 | } 59 | 60 | module.exports = function(fn) { 61 | // Wrap in a new function to prevent 62 | // `cancel` potentially being assigned 63 | // to the native rAF function 64 | return raf.call(root, fn) 65 | } 66 | module.exports.cancel = function() { 67 | caf.apply(root, arguments) 68 | } 69 | module.exports.polyfill = function(object) { 70 | if (!object) { 71 | object = root; 72 | } 73 | object.requestAnimationFrame = raf 74 | object.cancelAnimationFrame = caf 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # raf 2 | 3 | [![Browser Support](http://ci.testling.com/chrisdickinson/raf.png)](http://ci.testling.com/chrisdickinson/raf) 4 | 5 | requestAnimationFrame polyfill for node and the browser. 6 | 7 | ```js 8 | var raf = require('raf') 9 | 10 | raf(function tick() { 11 | // Animation logic 12 | raf(tick) 13 | }) 14 | ``` 15 | 16 | **Note:** The stream/event emitter logic found in versions prior to 1.0.0 can be found in [raf-stream](https://www.npmjs.org/package/raf-stream). 17 | 18 | ## Getting started 19 | 20 | ### CommonJS (Node, Browserify, Webpack, etc.) 21 | 22 | Install `raf` from npm: 23 | 24 | ```bash 25 | npm install --save raf 26 | ``` 27 | 28 | Require it like you would any other module: 29 | 30 | ```js 31 | const raf = require('raf') 32 | ``` 33 | 34 | ### AMD (require.js, etc) 35 | 36 | Download the UMD-bundle from [wzrd.in](https://wzrd.in/standalone/raf@latest) (remember to include the current version number in the filename). 37 | 38 | Add it to your AMD module loader config and require it like you would any other module: 39 | 40 | ```html 41 | define(['raf'], raf => {...}) 42 | ``` 43 | 44 | ### ` 52 | ``` 53 | 54 | The API will be available on `window.raf`. 55 | 56 | ## API 57 | 58 | [Documentation at Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame), [W3 Specification](http://www.w3.org/TR/animation-timing/#requestAnimationFrame) 59 | 60 | ### var handle = raf(callback) 61 | 62 | `callback` is the function to invoke in the next frame. `handle` is a long integer value that uniquely identifies the entry in the callback list. This is a non-zero value, but you may not make any other assumptions about its value. 63 | 64 | ### raf.cancel(handle) 65 | 66 | `handle` is the entry identifier returned by `raf()`. Removes the queued animation frame callback (other queued callbacks will still be invoked unless cancelled). 67 | 68 | ### raf.polyfill([object]) 69 | 70 | Shorthand to polyfill `window.requestAnimationFrame` and `window.cancelAnimationFrame` if necessary (Polyfills `global` in node). 71 | 72 | Alternatively you can require `raf/polyfill` which will act the same as `require('raf').polyfill()`. 73 | 74 | If you provide `object` the polyfills are attached to that given object, instead of the inferred global. 75 | Useful if you have an instance of a fake `window` object, and want to add `raf` and `caf` to it. 76 | 77 | ## Acknowledgments 78 | 79 | Based on work by Erik Möller, Paul Irish, and Tino Zijdel (https://gist.github.com/paulirish/1579671) 80 | 81 | ## License 82 | 83 | MIT 84 | --------------------------------------------------------------------------------