├── .npmignore ├── .gitignore ├── .babelrc ├── examples ├── index.js ├── bars │ ├── style.css │ └── index.js ├── utils.js └── animation │ └── index.js ├── .eslintrc ├── test ├── .eslintrc ├── keyframe.test.js └── __snapshots__ │ └── keyframe.test.js.snap ├── .neutrinorc.js ├── LICENSE.md ├── lib ├── index.min.js └── index.js ├── package.json ├── README.md └── src └── index.js /.npmignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | import './animation'; 2 | import './bars'; 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true, 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "plugins": [ 4 | "jest" 5 | ], 6 | "env": { 7 | "jest/globals": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.neutrinorc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | use: [ 3 | 'neutrino-preset-web', 4 | 'neutrino-preset-jest' 5 | ], 6 | options: { 7 | source: 'examples', 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /examples/bars/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | margin: 3rem; 4 | } 5 | 6 | div { 7 | max-width: 10rem; 8 | } 9 | 10 | .bar { 11 | background: #999; 12 | height: 2rem; 13 | width: 10rem; 14 | margin-bottom: 1px; 15 | transform-origin: 0 0; 16 | } 17 | 18 | input[type=range] { 19 | width: 10rem; 20 | margin: 1rem 0 6rem; 21 | } 22 | -------------------------------------------------------------------------------- /examples/utils.js: -------------------------------------------------------------------------------- 1 | // 2 | // DOM utilities to simplify examples. 3 | // 4 | 5 | export const createElement = tag => document.createElement(tag); 6 | 7 | export const addElement = element => document.getElementById('root').appendChild(element); 8 | 9 | export const addClass = className => (element) => { 10 | element.className = className; 11 | 12 | return element; 13 | }; 14 | 15 | export const addDiv = className => addElement(addClass(className)(createElement('div'))); 16 | 17 | // CreateElement a slider element. 18 | export function addSlider() { 19 | const slider = createElement('input'); 20 | slider.type = 'range'; 21 | slider.value = 100; 22 | addElement(slider); 23 | 24 | return slider; 25 | } 26 | -------------------------------------------------------------------------------- /examples/bars/index.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | import keyframe from '../../src/'; 3 | import { addDiv, addSlider } from '../utils'; 4 | 5 | const scale = (element, x) => { 6 | element.style.transform = `scaleX(${x})`; 7 | }; 8 | 9 | // CreateElement DOM div elements. 10 | const div = [addDiv('bar'), addDiv('bar'), addDiv('bar'), addDiv('bar')]; 11 | 12 | const onSliderUpdate = keyframe({ 13 | // `d` is the duration between this and the previous frame. 14 | 25: d => scale(div[0], d), 15 | 50: d => scale(div[1], d), 16 | 75: d => scale(div[2], d), 17 | 100: d => scale(div[3], d), 18 | }); 19 | 20 | const slider = addSlider(); 21 | 22 | // Return range between 0 and 1. 23 | slider.addEventListener('input', () => onSliderUpdate(slider.value / 100), true); 24 | -------------------------------------------------------------------------------- /examples/animation/index.js: -------------------------------------------------------------------------------- 1 | import keyframe from '../../src/'; 2 | import { addDiv, addSlider } from '../utils'; 3 | 4 | // Create a DOM div element. 5 | const div = addDiv(); 6 | div.innerHTML = 'DEMO'; 7 | 8 | // Utility to move the div. 9 | const moveTo = (x, y) => { 10 | div.style.transform = `translate(${x}px, ${y}px)`; 11 | }; 12 | 13 | // From (0% -> 50%) move the div left 150px 14 | // then from (50% -> 100%) move the div up 50px. 15 | const onSliderUpdate = keyframe({ 16 | // d is the duration between 0% -> 50%. 17 | 50: d => moveTo(d * 150, 0), 18 | 19 | // d is the duration between 50% -> 100%. 20 | 100: d => moveTo(150, d * -50), 21 | }); 22 | 23 | onSliderUpdate(1); 24 | 25 | const slider = addSlider(); 26 | 27 | // Return range between 0 and 1. 28 | slider.addEventListener('input', () => onSliderUpdate(slider.value / 100), true); 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Bruno Lourenço 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/index.min.js: -------------------------------------------------------------------------------- 1 | "use strict";function _toConsumableArray(r){if(Array.isArray(r)){for(var e=0,n=Array(r.length);e1&&e[t[t.length-1]](r)}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=keyframes;var sort=function(r,e){return r-e},toFloat=function(r){return parseFloat(r,10)},noop=function(){},chunk2=function(r){for(var e=[],n=0;n=r[o])return e[o];for(var a=1;au||a===o);a++);var f=getProgressFromValue(r[a-1],r[a],u),c=n?n[a-1](f):f;return getValueFromProgress(e[a-1],e[a],c)}}; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "keyframe", 3 | "version": "2.1.0", 4 | "description": "A simple keyframe utility for custom animation", 5 | "homepage": "https://github.com/brunnolou/keyframe#readme", 6 | "main": "lib/index.js", 7 | "scripts": { 8 | "dev": "neutrino start", 9 | "build:demo": "neutrino build", 10 | "build": "babel src | uglifyjs -b -o lib/index.js && uglifyjs lib/index.js -m -c -o lib/index.min.js", 11 | "test": "neutrino test" 12 | }, 13 | "keywords": [ 14 | "keyframes", 15 | "animation", 16 | "key frames", 17 | "keyframe", 18 | "timeline", 19 | "transition" 20 | ], 21 | "author": "Bruno Lourenco", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "babel-cli": "^6.24.1", 25 | "babel-eslint": "^7.2.3", 26 | "babel-preset-env": "^1.6.0", 27 | "eslint": "^3.19.0", 28 | "eslint-config-airbnb-base": "^11.2.0", 29 | "eslint-plugin-import": "^2.7.0", 30 | "eslint-plugin-jest": "^20.0.3", 31 | "neutrino": "^6.*", 32 | "neutrino-preset-jest": "^6.*", 33 | "neutrino-preset-node": "^6.*", 34 | "neutrino-preset-web": "^6.*", 35 | "uglifyjs": "^2.4.11" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git+https://github.com/brunnolou/keyframe.git" 40 | }, 41 | "bugs": { 42 | "url": "https://github.com/brunnolou/keyframe/issues" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keyframe 2 | 3 | ### A simple tiny keyframe utility for custom animation. 4 | [![npm version](https://badge.fury.io/js/keyframe.svg?v2)](https://badge.fury.io/js/keyframe) 5 | ![0 dependencies](https://david-dm.org/brunnolou/keyframe.svg) 6 | ![](https://img.shields.io/github/size/brunnolou/keyframe/lib/index.min.js.svg) 7 | 8 | 9 | ## Install 10 | `npm install --save keyframe` 11 | 12 | or 13 | 14 | `yarn add keyframe` 15 | 16 | ## Usage 17 | Pass an object witch every key is the keyframe from `0` to `100`. 18 | 19 | Each keyframe is a function that will be called during the keyframe interval. Each passed function is **cached** and **runs only once** when the value is the same. 20 | 21 | And will return a function to run through the keyframes progress. 22 | 23 | ```js 24 | const run = keyframe({ 25 | 50: (d) => update(d), 26 | 100: (d) => update(d), 27 | }); 28 | 29 | run(0); // 0 30 | run(0.25); // 0.5 31 | run(0.5); // 1 32 | run(0.75); // 0.5 33 | run(1); // 1 34 | ``` 35 | 36 | ## Example 37 | ```js 38 | import keyframe from 'keyframe'; 39 | 40 | ... 41 | 42 | const moveTo = (x, y) => { 43 | div.style.transform = `translate(${x}px, ${y}px)`; 44 | }; 45 | 46 | // From (0% -> 50%) move the div left 150px 47 | // then from (50% -> 100%) move the div up 50px. 48 | const onSliderUpdate = keyframe({ 49 | // d is the duration between 0% -> 50%. 50 | 50: d => moveTo(d * 150, 0), 51 | 52 | // d is the duration between 50% -> 100%. 53 | 100: d => moveTo(150, d * -50), 54 | }); 55 | 56 | // Return range between 0 and 1. 57 | DOMslider.addEventListener('input', () => onSliderUpdate(slider.value / 100), true); 58 | 59 | ``` 60 | 61 | Check the `examples/` folder to see full examples. 62 | 63 | Or check out the [DEMO](https://brunnolou.github.io/keyframe/) page 64 | 65 | [![](https://i.giphy.com/xT39D7ALjvyjoqLU0U.gif)](https://brunnolou.github.io/keyframe/) 66 | 67 | 68 | ## Development 69 | `yarn install` 70 | 71 | `yarn run dev` 72 | 73 | ## Test 74 | `yarn test` 75 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const sort = (a, b) => a - b; 2 | const toFloat = x => parseFloat(x, 10); 3 | const noop = () => {}; 4 | const chunk2 = (value) => { 5 | const arr = []; 6 | for (let i = 0; i < value.length; i += 2) arr.push(value.slice(i, i + 2)); 7 | 8 | return arr; 9 | }; 10 | 11 | const onceDifferent = (func, value) => { 12 | let memo = value; 13 | 14 | return (newVal) => { 15 | if (memo === newVal) return memo; 16 | 17 | func(newVal); 18 | 19 | memo = newVal; 20 | 21 | return memo; 22 | }; 23 | }; 24 | 25 | // From popmotion's calc. 26 | const getProgressFromValue = (from, to, value) => (value - from) / (to - from); 27 | const getValueFromProgress = (from, to, progress) => -progress * from + progress * to + from; 28 | 29 | /** 30 | * popmotion's Interpolate from set of values to another 31 | */ 32 | const interpolate = (input, output, rangeEasing) => { 33 | const rangeLength = input.length; 34 | const finalIndex = rangeLength - 1; 35 | 36 | return (v) => { 37 | // If value outside minimum range, quickly return 38 | if (v <= input[0]) { 39 | return output[0]; 40 | } 41 | 42 | // If value outside maximum range, quickly return 43 | if (v >= input[finalIndex]) { 44 | return output[finalIndex]; 45 | } 46 | 47 | let i = 1; 48 | 49 | // Find index of range start 50 | for (; i < rangeLength; i += 1) { 51 | if (input[i] > v || i === finalIndex) { 52 | break; 53 | } 54 | } 55 | 56 | const progressInRange = getProgressFromValue(input[i - 1], input[i], v); 57 | const easedProgress = rangeEasing ? rangeEasing[i - 1](progressInRange) : progressInRange; 58 | return getValueFromProgress(output[i - 1], output[i], easedProgress); 59 | }; 60 | }; 61 | 62 | /** 63 | * keyframes 64 | * @param {Object} frames 65 | * @return {Function} 66 | */ 67 | export default function keyframes(originalFrames) { 68 | const frames = Object.assign({}, originalFrames); 69 | let noZero = false; 70 | 71 | if (!frames[0]) { 72 | noZero = true; 73 | frames[0] = noop; 74 | } 75 | 76 | const framesArray = Object.keys(frames); 77 | 78 | framesArray.forEach((key) => { 79 | const func = frames[key]; 80 | 81 | frames[key] = onceDifferent(func); 82 | }); 83 | 84 | let keysNumbers = framesArray.map(toFloat); 85 | 86 | keysNumbers = [...keysNumbers, ...keysNumbers].sort(sort).slice(1, Infinity); 87 | 88 | const chucks = chunk2(keysNumbers); 89 | 90 | const caller = (progress) => { 91 | // When 0 is present considered it done like the initial state similar to css keyframes. 92 | frames[0](1); 93 | 94 | chucks.forEach((chunk) => { 95 | // Handle the last chunk [100] without and end; 96 | if (!chunk[1]) { 97 | return; 98 | } 99 | 100 | const func = frames[chunk[1]]; 101 | const interpolatedValue = interpolate([chunk[0], chunk[1]], [0, 1]); 102 | 103 | func(interpolatedValue(progress * 100)); 104 | }); 105 | 106 | if (progress < 0) frames[framesArray[noZero ? 1 : 0]](progress); 107 | if (progress > 1) frames[framesArray[framesArray.length - 1]](progress); 108 | }; 109 | 110 | return caller; 111 | } 112 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | exports.default = keyframes; 8 | 9 | function _toConsumableArray(arr) { 10 | if (Array.isArray(arr)) { 11 | for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { 12 | arr2[i] = arr[i]; 13 | } 14 | return arr2; 15 | } else { 16 | return Array.from(arr); 17 | } 18 | } 19 | 20 | var sort = function sort(a, b) { 21 | return a - b; 22 | }; 23 | 24 | var toFloat = function toFloat(x) { 25 | return parseFloat(x, 10); 26 | }; 27 | 28 | var noop = function noop() {}; 29 | 30 | var chunk2 = function chunk2(value) { 31 | var arr = []; 32 | for (var i = 0; i < value.length; i += 2) { 33 | arr.push(value.slice(i, i + 2)); 34 | } 35 | return arr; 36 | }; 37 | 38 | var onceDifferent = function onceDifferent(func, value) { 39 | var memo = value; 40 | return function(newVal) { 41 | if (memo === newVal) return memo; 42 | func(newVal); 43 | memo = newVal; 44 | return memo; 45 | }; 46 | }; 47 | 48 | var getProgressFromValue = function getProgressFromValue(from, to, value) { 49 | return (value - from) / (to - from); 50 | }; 51 | 52 | var getValueFromProgress = function getValueFromProgress(from, to, progress) { 53 | return -progress * from + progress * to + from; 54 | }; 55 | 56 | var interpolate = function interpolate(input, output, rangeEasing) { 57 | var rangeLength = input.length; 58 | var finalIndex = rangeLength - 1; 59 | return function(v) { 60 | if (v <= input[0]) { 61 | return output[0]; 62 | } 63 | if (v >= input[finalIndex]) { 64 | return output[finalIndex]; 65 | } 66 | var i = 1; 67 | for (;i < rangeLength; i++) { 68 | if (input[i] > v || i === finalIndex) { 69 | break; 70 | } 71 | } 72 | var progressInRange = getProgressFromValue(input[i - 1], input[i], v); 73 | var easedProgress = rangeEasing ? rangeEasing[i - 1](progressInRange) : progressInRange; 74 | return getValueFromProgress(output[i - 1], output[i], easedProgress); 75 | }; 76 | }; 77 | 78 | function keyframes(originalFrames) { 79 | var frames = Object.assign({}, originalFrames); 80 | var noZero = false; 81 | if (!frames[0]) { 82 | noZero = true; 83 | frames[0] = noop; 84 | } 85 | var framesArray = Object.keys(frames); 86 | framesArray.forEach(function(key) { 87 | var func = frames[key]; 88 | frames[key] = onceDifferent(func); 89 | }); 90 | var keysNumbers = framesArray.map(toFloat); 91 | keysNumbers = [].concat(_toConsumableArray(keysNumbers), _toConsumableArray(keysNumbers)).sort(sort).slice(1, Infinity); 92 | var chucks = chunk2(keysNumbers); 93 | var caller = function caller(progress) { 94 | frames[0](1); 95 | chucks.forEach(function(chunk) { 96 | if (!chunk[1]) { 97 | return; 98 | } 99 | var func = frames[chunk[1]]; 100 | var interpolatedValue = interpolate([ chunk[0], chunk[1] ], [ 0, 1 ]); 101 | func(interpolatedValue(progress * 100)); 102 | }); 103 | if (progress < 0) frames[framesArray[noZero ? 1 : 0]](progress); 104 | if (progress > 1) frames[framesArray[framesArray.length - 1]](progress); 105 | }; 106 | return caller; 107 | } -------------------------------------------------------------------------------- /test/keyframe.test.js: -------------------------------------------------------------------------------- 1 | import keyframe from '../src'; 2 | 3 | const range = (start, end) => Array(end - start + 1).fill().map((_, i) => start + i); 4 | 5 | test('Given range between 0 and 1000 should call each frame', () => { 6 | const calls = []; 7 | 8 | const frames = { 9 | 100: d => calls.push(d), 10 | }; 11 | 12 | const run = keyframe(frames); 13 | 14 | range(0, 1000).forEach((frame) => { 15 | run(frame / 1000); 16 | }); 17 | 18 | expect(calls).toMatchSnapshot(); 19 | }); 20 | 21 | test('Given range between 0 and 10 should call each frame', () => { 22 | const calls = []; 23 | 24 | const frames = { 25 | 50: d => calls.push(`50: ${d}`), 26 | 100: d => calls.push(`100: ${d}`), 27 | }; 28 | 29 | const run = keyframe(frames); 30 | 31 | range(0, 10).forEach((frame) => { 32 | run(frame / 10); 33 | }); 34 | 35 | expect(calls).toMatchSnapshot(); 36 | }); 37 | 38 | test('Given keyframe 0 should call correct 1', () => { 39 | // When 0 is present considered it done like the initial state similar to css keyframes. 40 | const onEnterFrame = jest.fn(); 41 | 42 | const run = keyframe({ 43 | 0: onEnterFrame, 44 | }); 45 | 46 | run(0); 47 | expect(onEnterFrame).toHaveBeenLastCalledWith(1); 48 | }); 49 | 50 | test('Given 1 keyframe when zero is missing should call correct relative duration', () => { 51 | const onEnterFrame = jest.fn(); 52 | 53 | keyframe({ 20: onEnterFrame })(0.1); 54 | expect(onEnterFrame).toHaveBeenLastCalledWith(0.5); 55 | 56 | keyframe({ 50: onEnterFrame })(0.25); 57 | expect(onEnterFrame).toHaveBeenLastCalledWith(0.5); 58 | 59 | keyframe({ 100: onEnterFrame })(0.25); 60 | expect(onEnterFrame).toHaveBeenLastCalledWith(0.25); 61 | }); 62 | 63 | test('Given 1 keyframe when zero is missing should call 0', () => { 64 | let onEnterFrame = jest.fn(); 65 | 66 | keyframe({ 20: onEnterFrame })(0); 67 | expect(onEnterFrame).toHaveBeenLastCalledWith(0); 68 | 69 | onEnterFrame = jest.fn(); 70 | keyframe({ 50: onEnterFrame })(0); 71 | expect(onEnterFrame).toHaveBeenLastCalledWith(0); 72 | 73 | onEnterFrame = jest.fn(); 74 | keyframe({ 100: onEnterFrame })(0); 75 | expect(onEnterFrame).toHaveBeenLastCalledWith(0); 76 | }); 77 | 78 | test('Given 2 keyframes should call correct relative duration', () => { 79 | const onEnterFrame = jest.fn(); 80 | 81 | keyframe({ 82 | 50: () => {}, 83 | 100: onEnterFrame, 84 | })(0.75); 85 | expect(onEnterFrame).toHaveBeenLastCalledWith(0.5); 86 | 87 | keyframe({ 88 | 25: () => {}, 89 | 75: onEnterFrame, 90 | })(0.5); 91 | expect(onEnterFrame).toHaveBeenLastCalledWith(0.5); 92 | }); 93 | 94 | test('Given multiple keyframes should call each correct relative duration', () => { 95 | const onEnterFrame1 = jest.fn(); 96 | const onEnterFrame2 = jest.fn(); 97 | const onEnterFrame3 = jest.fn(); 98 | const onEnterFrame4 = jest.fn(); 99 | 100 | const run = keyframe({ 101 | 0: onEnterFrame1, 102 | 50: onEnterFrame2, 103 | 80: onEnterFrame3, 104 | 100: onEnterFrame4, 105 | }); 106 | 107 | // Frame 0. 108 | run(0); 109 | expect(onEnterFrame1).toHaveBeenLastCalledWith(1); 110 | 111 | // Frame 50. 112 | run(0.25); 113 | expect(onEnterFrame2).toHaveBeenLastCalledWith(0.5); 114 | 115 | run(0.5); 116 | expect(onEnterFrame2).toHaveBeenLastCalledWith(1); 117 | 118 | // Frame 80. 119 | run(0.6); 120 | expect(onEnterFrame3).toHaveBeenLastCalledWith(1 / 3); 121 | 122 | // Frame 100. 123 | run(0.9); 124 | expect(onEnterFrame4).toHaveBeenLastCalledWith(0.5); 125 | }); 126 | 127 | test('When a exact frame is called it should call his own fn with progress at 100%', () => { 128 | const onStart = jest.fn(); 129 | const onMiddle = jest.fn(); 130 | const onEnd = jest.fn(); 131 | 132 | const run = keyframe({ 133 | 0: onStart, 134 | 50: onMiddle, 135 | 100: onEnd, 136 | }); 137 | 138 | // Frame 0. 139 | run(0); 140 | expect(onStart).toHaveBeenLastCalledWith(1); 141 | 142 | // Frame 50. 143 | run(0.5); 144 | expect(onMiddle).toHaveBeenLastCalledWith(1); 145 | 146 | run(1); 147 | expect(onEnd).toHaveBeenLastCalledWith(1); 148 | }); 149 | 150 | test('Given multiple keyframes should call each correct relative duration', () => { 151 | const onEnterFrame1 = jest.fn(); 152 | const onEnterFrame2 = jest.fn(); 153 | const onEnterFrame3 = jest.fn(); 154 | const onEnterFrame4 = jest.fn(); 155 | 156 | const run = keyframe({ 157 | 0: onEnterFrame1, 158 | 50: onEnterFrame2, 159 | 80: onEnterFrame3, 160 | 100: onEnterFrame4, 161 | }); 162 | 163 | // Frame 0. 164 | run(0); 165 | expect(onEnterFrame1).toHaveBeenLastCalledWith(1); 166 | 167 | // Frame 50. 168 | run(0.25); 169 | expect(onEnterFrame2).toHaveBeenLastCalledWith(0.5); 170 | 171 | run(0.5); 172 | expect(onEnterFrame2).toHaveBeenLastCalledWith(1); 173 | 174 | // Frame 80. 175 | run(0.6); 176 | expect(onEnterFrame3).toHaveBeenLastCalledWith(1 / 3); 177 | 178 | // Frame 100. 179 | run(0.9); 180 | expect(onEnterFrame4).toHaveBeenLastCalledWith(0.5); 181 | }); 182 | 183 | test('Given 0 should call next frame with 0', () => { 184 | const onEnterFrame0 = jest.fn(); 185 | const onEnterFrame1 = jest.fn(); 186 | const onEnterFrame2 = jest.fn(); 187 | const onEnterFrame3 = jest.fn(); 188 | 189 | const run = keyframe({ 190 | 0: onEnterFrame0, 191 | 50: onEnterFrame1, 192 | 80: onEnterFrame2, 193 | 100: onEnterFrame3, 194 | }); 195 | 196 | // Frame 0. 197 | run(0); 198 | expect(onEnterFrame0).toHaveBeenLastCalledWith(1); 199 | expect(onEnterFrame1).toHaveBeenLastCalledWith(0); 200 | expect(onEnterFrame2).toHaveBeenLastCalledWith(0); 201 | expect(onEnterFrame2).toHaveBeenLastCalledWith(0); 202 | expect(onEnterFrame3).toHaveBeenLastCalledWith(0); 203 | }); 204 | 205 | test('Given 1 should call next frame with 1', () => { 206 | const onEnterFrame1 = jest.fn(); 207 | const onEnterFrame2 = jest.fn(); 208 | const onEnterFrame3 = jest.fn(); 209 | 210 | const run = keyframe({ 211 | 50: onEnterFrame1, 212 | 80: onEnterFrame2, 213 | 100: onEnterFrame3, 214 | }); 215 | 216 | // Frame 100. 217 | run(1); 218 | expect(onEnterFrame1).toHaveBeenLastCalledWith(1); 219 | expect(onEnterFrame2).toHaveBeenLastCalledWith(1); 220 | expect(onEnterFrame2).toHaveBeenLastCalledWith(1); 221 | expect(onEnterFrame3).toHaveBeenLastCalledWith(1); 222 | }); 223 | 224 | test('Given multiple zeros should call each function only once', () => { 225 | const onEnterFrame0 = jest.fn(); 226 | const onEnterFrame1 = jest.fn(); 227 | const onEnterFrame2 = jest.fn(); 228 | const onEnterFrame3 = jest.fn(); 229 | 230 | const run = keyframe({ 231 | 0: onEnterFrame0, 232 | 50: onEnterFrame1, 233 | 80: onEnterFrame2, 234 | 100: onEnterFrame3, 235 | }); 236 | 237 | // Frame 0. 238 | run(0); 239 | run(0); 240 | run(0); 241 | run(0); 242 | expect(onEnterFrame0).toHaveBeenCalledTimes(1); 243 | expect(onEnterFrame1).toHaveBeenCalledTimes(1); 244 | expect(onEnterFrame2).toHaveBeenCalledTimes(1); 245 | expect(onEnterFrame2).toHaveBeenCalledTimes(1); 246 | expect(onEnterFrame3).toHaveBeenCalledTimes(1); 247 | }); 248 | 249 | test('Given multiple ones should call each function only once', () => { 250 | const onEnterFrame0 = jest.fn(); 251 | const onEnterFrame1 = jest.fn(); 252 | const onEnterFrame2 = jest.fn(); 253 | const onEnterFrame3 = jest.fn(); 254 | 255 | const run = keyframe({ 256 | 0: onEnterFrame0, 257 | 50: onEnterFrame1, 258 | 80: onEnterFrame2, 259 | 100: onEnterFrame3, 260 | }); 261 | 262 | // Frame 100. 263 | run(1); 264 | run(1); 265 | run(1); 266 | run(1); 267 | expect(onEnterFrame0).toHaveBeenCalledTimes(1); 268 | expect(onEnterFrame1).toHaveBeenCalledTimes(1); 269 | expect(onEnterFrame2).toHaveBeenCalledTimes(1); 270 | expect(onEnterFrame2).toHaveBeenCalledTimes(1); 271 | expect(onEnterFrame3).toHaveBeenCalledTimes(1); 272 | }); 273 | -------------------------------------------------------------------------------- /test/__snapshots__/keyframe.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Given range between 0 and 10 should call each frame 1`] = ` 4 | Array [ 5 | "50: 0", 6 | "100: 0", 7 | "50: 0.2", 8 | "50: 0.4", 9 | "50: 0.6", 10 | "50: 0.8", 11 | "50: 1", 12 | "100: 0.2", 13 | "100: 0.4", 14 | "100: 0.6", 15 | "100: 0.8", 16 | "100: 1", 17 | ] 18 | `; 19 | 20 | exports[`Given range between 0 and 1000 should call each frame 1`] = ` 21 | Array [ 22 | 0, 23 | 0.001, 24 | 0.002, 25 | 0.003, 26 | 0.004, 27 | 0.005, 28 | 0.006, 29 | 0.007000000000000001, 30 | 0.008, 31 | 0.009, 32 | 0.01, 33 | 0.011, 34 | 0.012, 35 | 0.013000000000000001, 36 | 0.014000000000000002, 37 | 0.015, 38 | 0.016, 39 | 0.017, 40 | 0.018, 41 | 0.019, 42 | 0.02, 43 | 0.021, 44 | 0.022, 45 | 0.023, 46 | 0.024, 47 | 0.025, 48 | 0.026000000000000002, 49 | 0.027000000000000003, 50 | 0.028000000000000004, 51 | 0.029000000000000005, 52 | 0.03, 53 | 0.031, 54 | 0.032, 55 | 0.033, 56 | 0.034, 57 | 0.035, 58 | 0.036, 59 | 0.037, 60 | 0.038, 61 | 0.039, 62 | 0.04, 63 | 0.04100000000000001, 64 | 0.042, 65 | 0.043, 66 | 0.044, 67 | 0.045, 68 | 0.046, 69 | 0.047, 70 | 0.048, 71 | 0.049, 72 | 0.05, 73 | 0.051, 74 | 0.052000000000000005, 75 | 0.053, 76 | 0.054000000000000006, 77 | 0.055, 78 | 0.05600000000000001, 79 | 0.057, 80 | 0.05800000000000001, 81 | 0.059, 82 | 0.06, 83 | 0.061, 84 | 0.062, 85 | 0.063, 86 | 0.064, 87 | 0.065, 88 | 0.066, 89 | 0.067, 90 | 0.068, 91 | 0.069, 92 | 0.07, 93 | 0.071, 94 | 0.072, 95 | 0.073, 96 | 0.074, 97 | 0.075, 98 | 0.076, 99 | 0.077, 100 | 0.078, 101 | 0.079, 102 | 0.08, 103 | 0.081, 104 | 0.08200000000000002, 105 | 0.083, 106 | 0.084, 107 | 0.085, 108 | 0.086, 109 | 0.087, 110 | 0.088, 111 | 0.08900000000000001, 112 | 0.09, 113 | 0.091, 114 | 0.092, 115 | 0.09300000000000001, 116 | 0.094, 117 | 0.095, 118 | 0.096, 119 | 0.09700000000000002, 120 | 0.098, 121 | 0.099, 122 | 0.1, 123 | 0.10100000000000002, 124 | 0.102, 125 | 0.103, 126 | 0.10400000000000001, 127 | 0.105, 128 | 0.106, 129 | 0.107, 130 | 0.10800000000000001, 131 | 0.109, 132 | 0.11, 133 | 0.111, 134 | 0.11200000000000002, 135 | 0.113, 136 | 0.114, 137 | 0.115, 138 | 0.11600000000000002, 139 | 0.117, 140 | 0.118, 141 | 0.11899999999999998, 142 | 0.12, 143 | 0.121, 144 | 0.122, 145 | 0.12300000000000001, 146 | 0.124, 147 | 0.125, 148 | 0.126, 149 | 0.127, 150 | 0.128, 151 | 0.129, 152 | 0.13, 153 | 0.131, 154 | 0.132, 155 | 0.133, 156 | 0.134, 157 | 0.135, 158 | 0.136, 159 | 0.137, 160 | 0.138, 161 | 0.139, 162 | 0.14, 163 | 0.141, 164 | 0.142, 165 | 0.143, 166 | 0.144, 167 | 0.145, 168 | 0.146, 169 | 0.147, 170 | 0.148, 171 | 0.149, 172 | 0.15, 173 | 0.151, 174 | 0.152, 175 | 0.153, 176 | 0.154, 177 | 0.155, 178 | 0.156, 179 | 0.157, 180 | 0.158, 181 | 0.159, 182 | 0.16, 183 | 0.161, 184 | 0.162, 185 | 0.163, 186 | 0.16400000000000003, 187 | 0.165, 188 | 0.166, 189 | 0.16699999999999998, 190 | 0.168, 191 | 0.169, 192 | 0.17, 193 | 0.171, 194 | 0.172, 195 | 0.17299999999999996, 196 | 0.174, 197 | 0.175, 198 | 0.176, 199 | 0.177, 200 | 0.17800000000000002, 201 | 0.179, 202 | 0.18, 203 | 0.18099999999999997, 204 | 0.182, 205 | 0.183, 206 | 0.184, 207 | 0.185, 208 | 0.18600000000000003, 209 | 0.187, 210 | 0.188, 211 | 0.18899999999999997, 212 | 0.19, 213 | 0.191, 214 | 0.192, 215 | 0.193, 216 | 0.19400000000000003, 217 | 0.195, 218 | 0.196, 219 | 0.19699999999999998, 220 | 0.198, 221 | 0.199, 222 | 0.2, 223 | 0.201, 224 | 0.20200000000000004, 225 | 0.203, 226 | 0.204, 227 | 0.205, 228 | 0.206, 229 | 0.207, 230 | 0.20800000000000002, 231 | 0.209, 232 | 0.21, 233 | 0.21099999999999997, 234 | 0.212, 235 | 0.213, 236 | 0.214, 237 | 0.215, 238 | 0.21600000000000003, 239 | 0.217, 240 | 0.218, 241 | 0.21899999999999997, 242 | 0.22, 243 | 0.221, 244 | 0.222, 245 | 0.223, 246 | 0.22400000000000003, 247 | 0.225, 248 | 0.226, 249 | 0.22699999999999998, 250 | 0.228, 251 | 0.229, 252 | 0.23, 253 | 0.231, 254 | 0.23200000000000004, 255 | 0.233, 256 | 0.234, 257 | 0.235, 258 | 0.236, 259 | 0.237, 260 | 0.23799999999999996, 261 | 0.239, 262 | 0.24, 263 | 0.241, 264 | 0.242, 265 | 0.243, 266 | 0.244, 267 | 0.245, 268 | 0.24600000000000002, 269 | 0.247, 270 | 0.248, 271 | 0.249, 272 | 0.25, 273 | 0.251, 274 | 0.252, 275 | 0.253, 276 | 0.254, 277 | 0.255, 278 | 0.256, 279 | 0.257, 280 | 0.258, 281 | 0.259, 282 | 0.26, 283 | 0.261, 284 | 0.262, 285 | 0.263, 286 | 0.264, 287 | 0.265, 288 | 0.266, 289 | 0.267, 290 | 0.268, 291 | 0.269, 292 | 0.27, 293 | 0.271, 294 | 0.272, 295 | 0.273, 296 | 0.274, 297 | 0.275, 298 | 0.276, 299 | 0.277, 300 | 0.278, 301 | 0.279, 302 | 0.28, 303 | 0.281, 304 | 0.282, 305 | 0.283, 306 | 0.284, 307 | 0.285, 308 | 0.286, 309 | 0.287, 310 | 0.288, 311 | 0.289, 312 | 0.29, 313 | 0.291, 314 | 0.292, 315 | 0.293, 316 | 0.294, 317 | 0.295, 318 | 0.296, 319 | 0.297, 320 | 0.298, 321 | 0.299, 322 | 0.3, 323 | 0.301, 324 | 0.302, 325 | 0.303, 326 | 0.304, 327 | 0.305, 328 | 0.306, 329 | 0.307, 330 | 0.308, 331 | 0.309, 332 | 0.31, 333 | 0.311, 334 | 0.312, 335 | 0.313, 336 | 0.314, 337 | 0.315, 338 | 0.316, 339 | 0.317, 340 | 0.318, 341 | 0.319, 342 | 0.32, 343 | 0.321, 344 | 0.322, 345 | 0.32300000000000006, 346 | 0.324, 347 | 0.325, 348 | 0.326, 349 | 0.327, 350 | 0.32800000000000007, 351 | 0.32899999999999996, 352 | 0.33, 353 | 0.331, 354 | 0.332, 355 | 0.333, 356 | 0.33399999999999996, 357 | 0.335, 358 | 0.336, 359 | 0.337, 360 | 0.338, 361 | 0.3390000000000001, 362 | 0.34, 363 | 0.341, 364 | 0.342, 365 | 0.343, 366 | 0.344, 367 | 0.345, 368 | 0.3459999999999999, 369 | 0.347, 370 | 0.348, 371 | 0.349, 372 | 0.35, 373 | 0.3509999999999999, 374 | 0.352, 375 | 0.353, 376 | 0.354, 377 | 0.355, 378 | 0.35600000000000004, 379 | 0.357, 380 | 0.358, 381 | 0.359, 382 | 0.36, 383 | 0.361, 384 | 0.36199999999999993, 385 | 0.363, 386 | 0.364, 387 | 0.365, 388 | 0.366, 389 | 0.36700000000000005, 390 | 0.368, 391 | 0.369, 392 | 0.37, 393 | 0.371, 394 | 0.37200000000000005, 395 | 0.373, 396 | 0.374, 397 | 0.375, 398 | 0.376, 399 | 0.377, 400 | 0.37799999999999995, 401 | 0.379, 402 | 0.38, 403 | 0.381, 404 | 0.382, 405 | 0.38299999999999995, 406 | 0.384, 407 | 0.385, 408 | 0.386, 409 | 0.387, 410 | 0.38800000000000007, 411 | 0.389, 412 | 0.39, 413 | 0.391, 414 | 0.392, 415 | 0.393, 416 | 0.39399999999999996, 417 | 0.395, 418 | 0.396, 419 | 0.397, 420 | 0.398, 421 | 0.3990000000000001, 422 | 0.4, 423 | 0.401, 424 | 0.402, 425 | 0.403, 426 | 0.4040000000000001, 427 | 0.405, 428 | 0.406, 429 | 0.407, 430 | 0.408, 431 | 0.409, 432 | 0.41, 433 | 0.4109999999999999, 434 | 0.412, 435 | 0.413, 436 | 0.414, 437 | 0.415, 438 | 0.41600000000000004, 439 | 0.417, 440 | 0.418, 441 | 0.419, 442 | 0.42, 443 | 0.42100000000000004, 444 | 0.42199999999999993, 445 | 0.423, 446 | 0.424, 447 | 0.425, 448 | 0.426, 449 | 0.42699999999999994, 450 | 0.428, 451 | 0.429, 452 | 0.43, 453 | 0.431, 454 | 0.43200000000000005, 455 | 0.433, 456 | 0.434, 457 | 0.435, 458 | 0.436, 459 | 0.43700000000000006, 460 | 0.43799999999999994, 461 | 0.439, 462 | 0.44, 463 | 0.441, 464 | 0.442, 465 | 0.44299999999999995, 466 | 0.444, 467 | 0.445, 468 | 0.446, 469 | 0.447, 470 | 0.44800000000000006, 471 | 0.449, 472 | 0.45, 473 | 0.451, 474 | 0.452, 475 | 0.45300000000000007, 476 | 0.45399999999999996, 477 | 0.455, 478 | 0.456, 479 | 0.457, 480 | 0.458, 481 | 0.45899999999999996, 482 | 0.46, 483 | 0.461, 484 | 0.462, 485 | 0.463, 486 | 0.4640000000000001, 487 | 0.465, 488 | 0.466, 489 | 0.467, 490 | 0.468, 491 | 0.469, 492 | 0.47, 493 | 0.4709999999999999, 494 | 0.472, 495 | 0.473, 496 | 0.474, 497 | 0.475, 498 | 0.4759999999999999, 499 | 0.477, 500 | 0.478, 501 | 0.479, 502 | 0.48, 503 | 0.48100000000000004, 504 | 0.482, 505 | 0.483, 506 | 0.484, 507 | 0.485, 508 | 0.486, 509 | 0.48699999999999993, 510 | 0.488, 511 | 0.489, 512 | 0.49, 513 | 0.491, 514 | 0.49200000000000005, 515 | 0.493, 516 | 0.494, 517 | 0.495, 518 | 0.496, 519 | 0.49700000000000005, 520 | 0.498, 521 | 0.499, 522 | 0.5, 523 | 0.501, 524 | 0.502, 525 | 0.503, 526 | 0.504, 527 | 0.505, 528 | 0.506, 529 | 0.507, 530 | 0.508, 531 | 0.509, 532 | 0.51, 533 | 0.511, 534 | 0.512, 535 | 0.513, 536 | 0.514, 537 | 0.515, 538 | 0.516, 539 | 0.517, 540 | 0.518, 541 | 0.519, 542 | 0.52, 543 | 0.521, 544 | 0.522, 545 | 0.523, 546 | 0.524, 547 | 0.525, 548 | 0.526, 549 | 0.527, 550 | 0.528, 551 | 0.529, 552 | 0.53, 553 | 0.531, 554 | 0.532, 555 | 0.533, 556 | 0.534, 557 | 0.535, 558 | 0.536, 559 | 0.537, 560 | 0.538, 561 | 0.539, 562 | 0.54, 563 | 0.541, 564 | 0.542, 565 | 0.543, 566 | 0.544, 567 | 0.545, 568 | 0.546, 569 | 0.547, 570 | 0.548, 571 | 0.549, 572 | 0.55, 573 | 0.551, 574 | 0.552, 575 | 0.553, 576 | 0.554, 577 | 0.555, 578 | 0.556, 579 | 0.557, 580 | 0.558, 581 | 0.559, 582 | 0.56, 583 | 0.561, 584 | 0.562, 585 | 0.563, 586 | 0.564, 587 | 0.565, 588 | 0.566, 589 | 0.567, 590 | 0.568, 591 | 0.569, 592 | 0.57, 593 | 0.571, 594 | 0.572, 595 | 0.573, 596 | 0.574, 597 | 0.575, 598 | 0.576, 599 | 0.577, 600 | 0.578, 601 | 0.579, 602 | 0.58, 603 | 0.581, 604 | 0.582, 605 | 0.583, 606 | 0.584, 607 | 0.585, 608 | 0.586, 609 | 0.587, 610 | 0.588, 611 | 0.589, 612 | 0.59, 613 | 0.591, 614 | 0.592, 615 | 0.593, 616 | 0.594, 617 | 0.595, 618 | 0.596, 619 | 0.597, 620 | 0.598, 621 | 0.599, 622 | 0.6, 623 | 0.601, 624 | 0.602, 625 | 0.603, 626 | 0.604, 627 | 0.605, 628 | 0.606, 629 | 0.607, 630 | 0.608, 631 | 0.609, 632 | 0.61, 633 | 0.611, 634 | 0.612, 635 | 0.613, 636 | 0.614, 637 | 0.615, 638 | 0.616, 639 | 0.617, 640 | 0.618, 641 | 0.619, 642 | 0.62, 643 | 0.621, 644 | 0.622, 645 | 0.623, 646 | 0.624, 647 | 0.625, 648 | 0.626, 649 | 0.627, 650 | 0.628, 651 | 0.629, 652 | 0.63, 653 | 0.631, 654 | 0.632, 655 | 0.633, 656 | 0.634, 657 | 0.635, 658 | 0.636, 659 | 0.637, 660 | 0.638, 661 | 0.639, 662 | 0.64, 663 | 0.6409999999999999, 664 | 0.642, 665 | 0.643, 666 | 0.644, 667 | 0.645, 668 | 0.6460000000000001, 669 | 0.647, 670 | 0.648, 671 | 0.649, 672 | 0.65, 673 | 0.6510000000000001, 674 | 0.652, 675 | 0.653, 676 | 0.654, 677 | 0.655, 678 | 0.6560000000000001, 679 | 0.657, 680 | 0.6579999999999999, 681 | 0.659, 682 | 0.66, 683 | 0.661, 684 | 0.662, 685 | 0.6629999999999999, 686 | 0.664, 687 | 0.665, 688 | 0.666, 689 | 0.667, 690 | 0.6679999999999999, 691 | 0.669, 692 | 0.67, 693 | 0.671, 694 | 0.672, 695 | 0.6730000000000002, 696 | 0.674, 697 | 0.675, 698 | 0.676, 699 | 0.677, 700 | 0.6780000000000002, 701 | 0.679, 702 | 0.68, 703 | 0.681, 704 | 0.682, 705 | 0.6830000000000002, 706 | 0.684, 707 | 0.685, 708 | 0.686, 709 | 0.687, 710 | 0.688, 711 | 0.689, 712 | 0.69, 713 | 0.691, 714 | 0.6919999999999998, 715 | 0.693, 716 | 0.694, 717 | 0.695, 718 | 0.696, 719 | 0.6969999999999998, 720 | 0.698, 721 | 0.699, 722 | 0.7, 723 | 0.701, 724 | 0.7019999999999998, 725 | 0.703, 726 | 0.704, 727 | 0.705, 728 | 0.706, 729 | 0.7070000000000001, 730 | 0.708, 731 | 0.709, 732 | 0.71, 733 | 0.711, 734 | 0.7120000000000001, 735 | 0.713, 736 | 0.714, 737 | 0.715, 738 | 0.716, 739 | 0.7170000000000001, 740 | 0.718, 741 | 0.7189999999999999, 742 | 0.72, 743 | 0.721, 744 | 0.722, 745 | 0.723, 746 | 0.7239999999999999, 747 | 0.725, 748 | 0.726, 749 | 0.727, 750 | 0.728, 751 | 0.7289999999999999, 752 | 0.73, 753 | 0.731, 754 | 0.732, 755 | 0.733, 756 | 0.7340000000000001, 757 | 0.735, 758 | 0.736, 759 | 0.737, 760 | 0.738, 761 | 0.7390000000000001, 762 | 0.74, 763 | 0.741, 764 | 0.742, 765 | 0.743, 766 | 0.7440000000000001, 767 | 0.745, 768 | 0.746, 769 | 0.747, 770 | 0.748, 771 | 0.7490000000000001, 772 | 0.75, 773 | 0.7509999999999999, 774 | 0.752, 775 | 0.753, 776 | 0.754, 777 | 0.755, 778 | 0.7559999999999999, 779 | 0.757, 780 | 0.758, 781 | 0.759, 782 | 0.76, 783 | 0.7609999999999999, 784 | 0.762, 785 | 0.763, 786 | 0.764, 787 | 0.765, 788 | 0.7659999999999999, 789 | 0.767, 790 | 0.768, 791 | 0.769, 792 | 0.77, 793 | 0.7710000000000001, 794 | 0.772, 795 | 0.773, 796 | 0.774, 797 | 0.775, 798 | 0.7760000000000001, 799 | 0.777, 800 | 0.778, 801 | 0.779, 802 | 0.78, 803 | 0.7810000000000001, 804 | 0.782, 805 | 0.7829999999999999, 806 | 0.784, 807 | 0.785, 808 | 0.786, 809 | 0.787, 810 | 0.7879999999999999, 811 | 0.789, 812 | 0.79, 813 | 0.791, 814 | 0.792, 815 | 0.7929999999999999, 816 | 0.794, 817 | 0.795, 818 | 0.796, 819 | 0.797, 820 | 0.7980000000000002, 821 | 0.799, 822 | 0.8, 823 | 0.801, 824 | 0.802, 825 | 0.8030000000000002, 826 | 0.804, 827 | 0.805, 828 | 0.806, 829 | 0.807, 830 | 0.8080000000000002, 831 | 0.809, 832 | 0.81, 833 | 0.811, 834 | 0.812, 835 | 0.813, 836 | 0.814, 837 | 0.815, 838 | 0.816, 839 | 0.8169999999999998, 840 | 0.818, 841 | 0.819, 842 | 0.82, 843 | 0.821, 844 | 0.8219999999999998, 845 | 0.823, 846 | 0.824, 847 | 0.825, 848 | 0.826, 849 | 0.8269999999999998, 850 | 0.828, 851 | 0.829, 852 | 0.83, 853 | 0.831, 854 | 0.8320000000000001, 855 | 0.833, 856 | 0.834, 857 | 0.835, 858 | 0.836, 859 | 0.8370000000000001, 860 | 0.838, 861 | 0.839, 862 | 0.84, 863 | 0.841, 864 | 0.8420000000000001, 865 | 0.843, 866 | 0.8439999999999999, 867 | 0.845, 868 | 0.846, 869 | 0.847, 870 | 0.848, 871 | 0.8489999999999999, 872 | 0.85, 873 | 0.851, 874 | 0.852, 875 | 0.853, 876 | 0.8539999999999999, 877 | 0.855, 878 | 0.856, 879 | 0.857, 880 | 0.858, 881 | 0.8590000000000001, 882 | 0.86, 883 | 0.861, 884 | 0.862, 885 | 0.863, 886 | 0.8640000000000001, 887 | 0.865, 888 | 0.866, 889 | 0.867, 890 | 0.868, 891 | 0.8690000000000001, 892 | 0.87, 893 | 0.871, 894 | 0.872, 895 | 0.873, 896 | 0.8740000000000001, 897 | 0.875, 898 | 0.8759999999999999, 899 | 0.877, 900 | 0.878, 901 | 0.879, 902 | 0.88, 903 | 0.8809999999999999, 904 | 0.882, 905 | 0.883, 906 | 0.884, 907 | 0.885, 908 | 0.8859999999999999, 909 | 0.887, 910 | 0.888, 911 | 0.889, 912 | 0.89, 913 | 0.8909999999999999, 914 | 0.892, 915 | 0.893, 916 | 0.894, 917 | 0.895, 918 | 0.8960000000000001, 919 | 0.897, 920 | 0.898, 921 | 0.899, 922 | 0.9, 923 | 0.9010000000000001, 924 | 0.902, 925 | 0.903, 926 | 0.904, 927 | 0.905, 928 | 0.9060000000000001, 929 | 0.907, 930 | 0.9079999999999999, 931 | 0.909, 932 | 0.91, 933 | 0.911, 934 | 0.912, 935 | 0.9129999999999999, 936 | 0.914, 937 | 0.915, 938 | 0.916, 939 | 0.917, 940 | 0.9179999999999999, 941 | 0.919, 942 | 0.92, 943 | 0.921, 944 | 0.922, 945 | 0.9230000000000002, 946 | 0.924, 947 | 0.925, 948 | 0.926, 949 | 0.927, 950 | 0.9280000000000002, 951 | 0.929, 952 | 0.93, 953 | 0.931, 954 | 0.932, 955 | 0.9330000000000002, 956 | 0.934, 957 | 0.935, 958 | 0.936, 959 | 0.937, 960 | 0.938, 961 | 0.939, 962 | 0.94, 963 | 0.941, 964 | 0.9419999999999998, 965 | 0.943, 966 | 0.944, 967 | 0.945, 968 | 0.946, 969 | 0.9469999999999998, 970 | 0.948, 971 | 0.949, 972 | 0.95, 973 | 0.951, 974 | 0.9519999999999998, 975 | 0.953, 976 | 0.954, 977 | 0.955, 978 | 0.956, 979 | 0.9570000000000001, 980 | 0.958, 981 | 0.959, 982 | 0.96, 983 | 0.961, 984 | 0.9620000000000001, 985 | 0.963, 986 | 0.964, 987 | 0.965, 988 | 0.966, 989 | 0.9670000000000001, 990 | 0.968, 991 | 0.9689999999999999, 992 | 0.97, 993 | 0.971, 994 | 0.972, 995 | 0.973, 996 | 0.9739999999999999, 997 | 0.975, 998 | 0.976, 999 | 0.977, 1000 | 0.978, 1001 | 0.9789999999999999, 1002 | 0.98, 1003 | 0.981, 1004 | 0.982, 1005 | 0.983, 1006 | 0.9840000000000001, 1007 | 0.985, 1008 | 0.986, 1009 | 0.987, 1010 | 0.988, 1011 | 0.9890000000000001, 1012 | 0.99, 1013 | 0.991, 1014 | 0.992, 1015 | 0.993, 1016 | 0.9940000000000001, 1017 | 0.995, 1018 | 0.996, 1019 | 0.997, 1020 | 0.998, 1021 | 0.9990000000000001, 1022 | 1, 1023 | ] 1024 | `; 1025 | --------------------------------------------------------------------------------