├── docs └── Logo.png ├── public ├── img │ ├── favicon.ico │ └── github_logo.png ├── style │ ├── reset.css │ └── index.css ├── js │ ├── index.js │ └── fps.js └── index.html ├── .travis.yml ├── .editorconfig ├── .dependabot └── config.yml ├── .gitignore ├── .github └── workflows │ └── publish.yml ├── test ├── karma.config.js └── index.test.js ├── webpack.config.js ├── LICENSE.md ├── README.md ├── src ├── easings.js └── index.js └── package.json /docs/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davesnx/scrollto-with-animation/HEAD/docs/Logo.png -------------------------------------------------------------------------------- /public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davesnx/scrollto-with-animation/HEAD/public/img/favicon.ico -------------------------------------------------------------------------------- /public/img/github_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davesnx/scrollto-with-animation/HEAD/public/img/github_logo.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6' 4 | 5 | deploy: 6 | provider: surge 7 | project: ./public/ 8 | domain: scrollto-with-animation.surge.sh 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | update_configs: 3 | - package_manager: "javascript" 4 | directory: "/" 5 | update_schedule: "live" 6 | version_requirement_updates: "increase_versions" 7 | commit_message: 8 | prefix: "fix" 9 | allowed_updates: 10 | - match: 11 | update_type: "security" 12 | - match: 13 | dependency_name: "*" 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX and ide's folder attributes 2 | .DS_Store 3 | Thumbs.db 4 | .cache 5 | .project 6 | .settings 7 | .tmproj 8 | *.esproj 9 | nbproject 10 | *.sublime-project 11 | *.sublime-workspace 12 | *.sublime-* 13 | .idea 14 | 15 | # common node files and folders 16 | # https://github.com/github/gitignore/blob/master/Node.gitignore 17 | lib-cov 18 | *.seed 19 | *.log 20 | *.csv 21 | *.dat 22 | *.out 23 | *.pid 24 | *.gz 25 | 26 | pids 27 | logs 28 | node_modules 29 | 30 | build/Release # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | 32 | # always-ignore extensions 33 | *.diff 34 | *.err 35 | *.orig 36 | *.rej 37 | *.swo 38 | *.swp 39 | *.vi 40 | *~ 41 | 42 | dist 43 | lib 44 | src/package-info.json 45 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | install: 13 | runs-on: ubuntu-18.04 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-node@v1 17 | with: 18 | node-version: 12 19 | - run: | 20 | yarn install 21 | yarn build 22 | yarn test 23 | npx semantic-release 24 | env: 25 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 26 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 27 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 28 | - uses: dswistowski/surge-sh-action@v1 29 | with: 30 | domain: 'scrollto-with-animation.surge.sh' 31 | project: './public/' 32 | login: ${{ secrets.SURGE_LOGIN }} 33 | token: ${{ secrets.SURGE_TOKEN }} 34 | -------------------------------------------------------------------------------- /public/style/reset.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font-size: 100%; 18 | font: inherit; 19 | vertical-align: baseline; 20 | } 21 | 22 | /* HTML5 display-role reset for older browsers */ 23 | article, aside, details, figcaption, figure, 24 | footer, header, hgroup, menu, nav, section { 25 | display: block; 26 | } 27 | 28 | body { 29 | line-height: 1; 30 | } 31 | 32 | ol, ul { 33 | list-style: none; 34 | } 35 | -------------------------------------------------------------------------------- /test/karma.config.js: -------------------------------------------------------------------------------- 1 | const webpackConfig = require('./../webpack.config') 2 | 3 | module.exports = (config) => { 4 | config.set({ 5 | basePath: __dirname, 6 | files: [ 7 | '**/*.test.js' 8 | ], 9 | frameworks: ['jasmine'], 10 | preprocessors: { 11 | '**/*.test.js': ['webpack', 'sourcemap'] 12 | }, 13 | webpack: { module: webpackConfig.module }, 14 | webpackMiddleware: { 15 | noInfo: true 16 | }, 17 | plugins: [ 18 | 'karma-jasmine', 19 | 'karma-webpack', 20 | 'karma-chrome-launcher', 21 | 'karma-sourcemap-loader', 22 | 'karma-phantomjs-launcher', 23 | 'karma-spec-reporter', 24 | 'karma-coverage' 25 | ], 26 | browsers: ['PhantomJS'], 27 | browserDisconnectTimeout: 10000, 28 | browserDisconnectTolerance: 2, 29 | captureTimeout: 100000, 30 | browserNoActivityTimeout: 30000, 31 | colors: true, 32 | logColors: true, 33 | logLevel: config.LOG_INFO 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | 4 | module.exports = { 5 | debug: true, 6 | cache: false, 7 | process: true, 8 | stats: { 9 | colors: true 10 | }, 11 | entry: { 12 | 'scrollto-with-animation': path.join(__dirname, 'src') 13 | }, 14 | output: { 15 | path: path.join(__dirname, 'dist'), 16 | filename: '[name].min.js' 17 | }, 18 | plugins: [ 19 | new webpack.SourceMapDevToolPlugin({ 20 | filename: '[name].js.map' 21 | }), 22 | new webpack.optimize.UglifyJsPlugin({ 23 | minimize: true, 24 | compressor: { 25 | screw_ie8: true, 26 | warnings: false 27 | }, 28 | output: { 29 | comments: false 30 | } 31 | }) 32 | ], 33 | module: { 34 | loaders: [{ 35 | test: /\.js?$/, 36 | exclude: /node_modules/, 37 | loader: 'babel', 38 | query: { 39 | cacheDirectory: true, 40 | presets: ['es2015', 'stage-2'] 41 | } 42 | }, { 43 | test: /\.json/, 44 | loader: 'json' 45 | }] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2015 David Sancho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import scrollto, { rAF } from './../src/index' 2 | 3 | const D = document.documentElement 4 | const TO = 0 5 | const DURATION = 100 6 | const DIRECTION = 'scrollTop' 7 | const TRANSITION_OK = 'easeInOutQuad' 8 | const TRANSITION_KO = 'flowInOutFly' 9 | const TRANSITION_EQ_OK = (a, b, c, d) => a + b + c + d 10 | const TRANSITION_EQ_KO = () => {} 11 | 12 | describe(`#findAnimation when you pass`, () => { 13 | it(`an incorrect transition should throw an exception`, () => { 14 | const func = () => scrollto(D, DIRECTION, TO, DURATION, TRANSITION_KO) 15 | expect(func).toThrow() 16 | }) 17 | 18 | it(`a correct transition shouldn't throw an exception`, () => { 19 | const func = () => scrollto(D, DIRECTION, TO, DURATION, TRANSITION_OK) 20 | expect(func).not.toThrow() 21 | }) 22 | }) 23 | 24 | describe(`#defineAnimation when you pass an easing function`, () => { 25 | it(`that isn't correct should throw an exception`, () => { 26 | const func = () => scrollto(D, DIRECTION, TO, DURATION, TRANSITION_EQ_KO) 27 | expect(func).toThrow() 28 | }) 29 | 30 | it(`that is correct shouldn't throw an exception`, () => { 31 | const func = () => scrollto(D, DIRECTION, TO, DURATION, TRANSITION_EQ_OK) 32 | expect(func).not.toThrow() 33 | }) 34 | }) 35 | 36 | describe(`#do the scrollto with animation`, () => { 37 | it(`should call animationFrame.request`, () => { 38 | rAF.request = jasmine.createSpy('animationFrameSpy') 39 | scrollto(D, DIRECTION, TO, DURATION, TRANSITION_EQ_OK) 40 | expect(rAF.request).toHaveBeenCalled() 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /public/js/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | window.onload = function () { 4 | var elemHighlighted = document.getElementById('highlight') 5 | var header = document.getElementById('header') 6 | var counterFPS = document.getElementById('fpsMeter') 7 | var counterButton = document.getElementById('fps-button') 8 | var triggerButton = document.getElementById('trigger-scroll-btn') 9 | 10 | var meter = new window.FPSMeter(counterFPS, { 11 | interval: 10, 12 | smoothing: 10, 13 | show: 'fps', 14 | toggleOn: 'EventNonSense', 15 | decimals: 0, 16 | maxFps: 60, 17 | threshold: 100, 18 | position: 'fixed', 19 | left: '15px', 20 | top: 'auto', 21 | right: 'auto', 22 | bottom: '15px' 23 | }) 24 | 25 | function easeInOutCircWithFPS (t, b, c, d) { 26 | meter.tick() 27 | t /= d / 2 28 | if (t < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b 29 | t -= 2 30 | return c / 2 * (Math.sqrt(1 - t * t) + 1) + b 31 | } 32 | 33 | function enableFPS (event) { 34 | event.preventDefault() 35 | counterFPS.style.opacity = (counterFPS.style.opacity === '0') ? '1' : '0' 36 | } 37 | 38 | function scroll (event) { 39 | event.preventDefault() 40 | var direction = 'scrollTop' 41 | 42 | var position = elemHighlighted.getBoundingClientRect().top - header.getBoundingClientRect().height 43 | 44 | window.scrollToWithAnimation( 45 | document.documentElement, 46 | direction, 47 | position, 48 | 2000, 49 | easeInOutCircWithFPS, 50 | function () { 51 | console.log('Done!') 52 | } 53 | ) 54 | } 55 | 56 | counterButton.addEventListener('click', enableFPS) 57 | triggerButton.addEventListener('click', scroll) 58 | } 59 | -------------------------------------------------------------------------------- /public/style/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: 'Open Sans', Arial, sans-serif; 6 | } 7 | 8 | h1 { 9 | font-family: 'Montserrat'; 10 | font-size: 43px; 11 | font-weight: 800; 12 | letter-spacing: 10px; 13 | margin: 0; 14 | padding: 30px; 15 | padding-bottom: 20px; 16 | -webkit-font-smoothing: antialiased; 17 | color: white; 18 | } 19 | 20 | h2 { 21 | padding-bottom: 27px; 22 | color: #626974; 23 | font-weight: 600; 24 | letter-spacing: 0.5px; 25 | -webkit-font-smoothing: antialiased; 26 | line-height: 25px; 27 | } 28 | 29 | a.header-link { 30 | text-decoration: none; 31 | border-bottom: 1px solid #626974; 32 | transition: opacity 0.2s ease; 33 | color: #626974; 34 | font-weight: 600; 35 | letter-spacing: 0.5px; 36 | -webkit-font-smoothing: antialiased; 37 | } 38 | 39 | a.header-link:hover { 40 | opacity: 0.5; 41 | } 42 | 43 | .big-header { 44 | box-sizing: border-box; 45 | background: #27292F; 46 | text-align: center; 47 | position: fixed; 48 | width: 100%; 49 | top: 0; 50 | border-top: 2px solid #626974; 51 | } 52 | 53 | .box { 54 | width: 100%; 55 | height: 80px; 56 | background-color: #626974; 57 | margin: 20px auto; 58 | } 59 | 60 | .box::first { 61 | margin-top: 175px; 62 | } 63 | 64 | .box--highlight { 65 | background-color: #FF6443; 66 | } 67 | 68 | .fpsMeter > div { 69 | border-radius: 3px; 70 | } 71 | 72 | #trigger-scroll-btn { 73 | color: white; 74 | background: #27292F; 75 | font-size: 20px; 76 | border: none; 77 | border: 2px solid white; 78 | padding: 7px 20px; 79 | border-radius: 3px; 80 | transition: all 0.2s ease; 81 | cursor: pointer; 82 | 83 | margin-bottom: 20px; 84 | } 85 | 86 | #trigger-scroll-btn:hover { 87 | background: #65666B; 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/Logo.png) 2 | 3 | ### [Live demo](http://scrollto-with-animation.surge.sh/) 4 | 5 | [![Build Status](https://travis-ci.org/davesnx/scrollto-with-animation.svg?branch=master)](https://travis-ci.org/davesnx/scrollto-with-animation) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) [![npm](https://img.shields.io/npm/dm/localeval.svg)](https://www.npmjs.com/package/scrollto-with-animation) 6 | 7 | - Using [**requestAnimationFrame**](https://dev.opera.com/articles/better-performance-with-requestanimationframe/) 8 | - **3.2k** minified and gzipped 9 | - Runs the animation at **60 FPS** 10 | - Available as a **script or UMD** 11 | - Only **one dependency** to have **requestAnimationFrame cross-browser** 12 | - If user scrolls while animation is running, scroll animation would be immediately canceled 13 | 14 | ## Install 15 | 16 | ```bash 17 | npm install scrollto-with-animation --save 18 | ``` 19 | 20 | ## Usage 21 | 22 | ### Available as a [UMD](https://github.com/umdjs/umd) 23 | 24 | ```javascript 25 | var scrollToWithAnimation = require('scrollto-with-animation') 26 | // or ES6+ 27 | import scrollToWithAnimation from 'scrollto-with-animation' 28 | ``` 29 | 30 | ### or as a script 31 | 32 | ```html 33 | 34 | ``` 35 | 36 | ### Example 37 | 38 | ```javascript 39 | scrollToWithAnimation( 40 | document.documentElement, // element to scroll 41 | 'scrollTop', // direction to scroll 42 | 0, // target scrollY (0 means top of the page) 43 | 10000, // duration in ms 44 | 'easeInOutCirc', /* 45 | Can be a name of the list of 'Possible easing equations' or a callback 46 | that defines the ease. # http://gizma.com/easing/ 47 | */ 48 | function () { // callback function that runs after the animation (optional) 49 | console.log('done!') 50 | } 51 | ); 52 | ``` 53 | 54 | This will scroll to top of the page and the animation will run for 10 seconds (10000ms). 55 | 56 | 57 | ## Options 58 | 59 | ## Posible easings equations 60 | 61 | - `linearTween` 62 | - `easeInQuad` 63 | - `easeOutQuad` 64 | - `easeInOutQuad` 65 | - `easeInCubic` 66 | - `easeOutCubic` 67 | - `easeInOutCubic` 68 | - `easeInQuart` 69 | - `easeOutQuart` 70 | - `easeInOutQuart` 71 | - `easeInQuint` 72 | - `easeOutQuint` 73 | - `easeInOutQuint` 74 | - `easeInSine` 75 | - `easeOutSine` 76 | - `easeInOutSine` 77 | - `easeInExpo` 78 | - `easeOutExpo` 79 | - `easeInOutExpo` 80 | - `easeInCirc` 81 | - `easeOutCirc` 82 | - `easeInOutCirc` 83 | 84 | > Feel free to add more ease functions to [easings.js](https://github.com/davesnx/scrollToWithAnimation/blob/master/src/easings.js) open a Pull request! 85 | 86 | ## License 87 | 88 | MIT 89 | -------------------------------------------------------------------------------- /src/easings.js: -------------------------------------------------------------------------------- 1 | export default { 2 | linearTween: function (t, b, c, d) { 3 | return c * t / d + b 4 | }, 5 | easeInQuad: function (t, b, c, d) { 6 | t /= d 7 | return c * t * t + b 8 | }, 9 | easeOutQuad: function (t, b, c, d) { 10 | t /= d 11 | return -c * t * (t - 2) + b 12 | }, 13 | easeInOutQuad: function (t, b, c, d) { 14 | t /= d / 2 15 | if (t < 1) return c / 2 * t * t + b 16 | t-- 17 | return -c / 2 * (t * (t - 2) - 1) + b 18 | }, 19 | easeInCubic: function (t, b, c, d) { 20 | t /= d 21 | return c * t * t * t + b 22 | }, 23 | easeOutCubic: function (t, b, c, d) { 24 | t /= d 25 | t-- 26 | return c * (t * t * t + 1) + b 27 | }, 28 | easeInOutCubic: function (t, b, c, d) { 29 | t /= d / 2 30 | if (t < 1) return c / 2 * t * t * t + b 31 | t -= 2 32 | return c / 2 * (t * t * t + 2) + b 33 | }, 34 | easeInQuart: function (t, b, c, d) { 35 | t /= d 36 | return c * t * t * t * t + b 37 | }, 38 | easeOutQuart: function (t, b, c, d) { 39 | t /= d 40 | t-- 41 | return -c * (t * t * t * t - 1) + b 42 | }, 43 | easeInOutQuart: function (t, b, c, d) { 44 | t /= d / 2 45 | if (t < 1) return c / 2 * t * t * t * t + b 46 | t -= 2 47 | return -c / 2 * (t * t * t * t - 2) + b 48 | }, 49 | easeInQuint: function (t, b, c, d) { 50 | t /= d 51 | return c * t * t * t * t * t + b 52 | }, 53 | easeOutQuint: function (t, b, c, d) { 54 | t /= d 55 | t-- 56 | return c * (t * t * t * t * t + 1) + b 57 | }, 58 | easeInOutQuint: function (t, b, c, d) { 59 | t /= d / 2 60 | if (t < 1) return c / 2 * t * t * t * t * t + b 61 | t -= 2 62 | return c / 2 * (t * t * t * t * t + 2) + b 63 | }, 64 | easeInSine: function (t, b, c, d) { 65 | return -c * Math.cos(t / d * (Math.PI / 2)) + c + b 66 | }, 67 | easeOutSine: function (t, b, c, d) { 68 | return c * Math.sin(t / d * (Math.PI / 2)) + b 69 | }, 70 | easeInOutSine: function (t, b, c, d) { 71 | return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b 72 | }, 73 | easeInExpo: function (t, b, c, d) { 74 | return c * Math.pow(2, 10 * (t / d - 1)) + b 75 | }, 76 | easeOutExpo: function (t, b, c, d) { 77 | return c * (-Math.pow(2, -10 * t / d) + 1) + b 78 | }, 79 | easeInOutExpo: function (t, b, c, d) { 80 | t /= d / 2 81 | if (t < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b 82 | t-- 83 | return c / 2 * (-Math.pow(2, -10 * t) + 2) + b 84 | }, 85 | easeInCirc: function (t, b, c, d) { 86 | t /= d 87 | return -c * (Math.sqrt(1 - t * t) - 1) + b 88 | }, 89 | easeOutCirc: function (t, b, c, d) { 90 | t /= d 91 | t-- 92 | return c * Math.sqrt(1 - t * t) + b 93 | }, 94 | easeInOutCirc: function (t, b, c, d) { 95 | t /= d / 2 96 | if (t < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b 97 | t -= 2 98 | return c / 2 * (Math.sqrt(1 - t * t) + 1) + b 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SCROLLTO WITH ANIMATION 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrollto-with-animation", 3 | "version": "4.5.4", 4 | "author": "David Sancho (https://github.com/davesnx)", 5 | "description": "Animated scroll with requestAnimationFrame. For smooth animate scrollTo defining the easing, running at 60FPS and cross-browser", 6 | "license": "MIT", 7 | "main": "lib/index.js", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/davesnx/scrollto-with-animation" 11 | }, 12 | "files": [ 13 | "src", 14 | "lib", 15 | "dist", 16 | "README.md" 17 | ], 18 | "keywords": [ 19 | "animation", 20 | "scrollTo", 21 | "60fps", 22 | "cross-browser", 23 | "requestAnimationFrame", 24 | "easeInQuad", 25 | "browserify" 26 | ], 27 | "scripts": { 28 | "clean": "rm -rf dist/* && rm -rf lib/ && rm -rf src/package-info.json", 29 | "minify:dev": "NODE_ENV=dev webpack --watch", 30 | "minify:prod": "NODE_ENV=prod webpack -p", 31 | "compile:dev": "NODE_ENV=dev babel src --watch --out-dir lib", 32 | "compile:prod": "NODE_ENV=prod babel src --out-dir lib", 33 | "test:dev": "NODE_ENV=prod karma start test/karma.config.js --auto-watch", 34 | "test": "NODE_ENV=prod karma start test/karma.config.js --single-run", 35 | "build": "npm run clean && npm run compile:prod && npm run minify:prod", 36 | "prepublish": "npm run build" 37 | }, 38 | "pre-commit": [ 39 | "test" 40 | ], 41 | "bugs": { 42 | "url": "https://github.com/davesnx/scrollto-with-animation/issues" 43 | }, 44 | "dependencies": { 45 | "animation-frame": "^0.3.0" 46 | }, 47 | "devDependencies": { 48 | "@semantic-release/commit-analyzer": "^6.3.0", 49 | "@semantic-release/npm": "^5.2.0", 50 | "@semantic-release/release-notes-generator": "^7.3.0", 51 | "babel-cli": "^6.9.0", 52 | "babel-loader": "^6.2.2", 53 | "babel-preset-es2015": "^6.3.13", 54 | "babel-preset-stage-2": "^6.3.13", 55 | "jasmine-core": "^3.4.0", 56 | "json-loader": "^0.5.4", 57 | "karma": "^0.13.9", 58 | "karma-chrome-launcher": "^2.2.0", 59 | "karma-cli": "0.1.0", 60 | "karma-coverage": "^0.5.3", 61 | "karma-jasmine": "^0.3.6", 62 | "karma-phantomjs-launcher": "^0.2.1", 63 | "karma-sourcemap-loader": "^0.3.6", 64 | "karma-spec-reporter": "0.0.22", 65 | "karma-story-reporter": "^0.3.1", 66 | "karma-webpack": "^2.0.13", 67 | "phantomjs": "^2.1.7", 68 | "pre-push": "^0.1.1", 69 | "semantic-release": "^15.14.0", 70 | "webpack": "^1.12.13" 71 | }, 72 | "standard": { 73 | "parser": "babel-eslint", 74 | "global": [ 75 | "jasmine", 76 | "it", 77 | "describe", 78 | "beforeEach", 79 | "afterEach", 80 | "expect", 81 | "spyOn" 82 | ] 83 | }, 84 | "babel": { 85 | "presets": [ 86 | "es2015", 87 | "stage-2" 88 | ] 89 | }, 90 | "release": { 91 | "branch": "master", 92 | "plugins": [ 93 | "@semantic-release/commit-analyzer", 94 | "@semantic-release/release-notes-generator", 95 | "@semantic-release/npm" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import RAF from 'animation-frame' 2 | import easings from './easings' 3 | 4 | const packageInfo = { 5 | name: 'scrollto-with-animation', 6 | url: 'https://github.com/davesnx/scrollto-with-animation' 7 | } 8 | 9 | const rAF = new RAF() 10 | 11 | const DEBUG = process.env.NODE_ENV || true 12 | const DEFAULT_ANIMATION = 'easeInQuad' 13 | const LIB_NAME = `${packageInfo.name}` 14 | const TRANSITION_NOT_FOUND = `${LIB_NAME}: Transition not found - ${packageInfo.url}` 15 | const ANIMATION_NOT_VALID = `${LIB_NAME}: callback transition don't look like a valid equation - ${packageInfo.url}` 16 | const TRANSITION_NOT_VALID = `${LIB_NAME}: Transition isn't string or Function - ${packageInfo.url}` 17 | 18 | const ANIMATION_CANCEL = 'animation-cancel' 19 | const ANIMATION_END = 'animation-end' 20 | 21 | const _document = typeof document !== 'undefined' ? document : {} 22 | const _window = typeof window !== 'undefined' ? window : {} 23 | 24 | const findAnimation = (transition = DEFAULT_ANIMATION) => { 25 | var animation = easings[transition] 26 | if (animation === undefined && DEBUG) { 27 | throw new Error(TRANSITION_NOT_FOUND) 28 | } 29 | return animation 30 | } 31 | 32 | const defineAnimation = (transition) => { 33 | if (transition.length !== 4 && DEBUG) { 34 | throw new Error(ANIMATION_NOT_VALID) 35 | } 36 | return transition 37 | } 38 | 39 | const scrollToWithAnimation = ( 40 | element, 41 | direction = 'scrollTop', 42 | to = 0, 43 | duration = 100, 44 | transition = DEFAULT_ANIMATION, 45 | callback 46 | ) => { 47 | let id 48 | let start = direction === 'scrollTop' ? element.scrollTop : element.scrollLeft 49 | let distance = to - start 50 | let animationStartTime = +new Date() 51 | let isAnimating = true 52 | let lastScrolledPosition 53 | let transitionFunction 54 | 55 | if (!element) { 56 | element = _document.documentElement 57 | } 58 | 59 | if (typeof transition === 'string' || transition === null) { 60 | transitionFunction = findAnimation(transition) 61 | } else if (typeof transition === 'function') { 62 | transitionFunction = defineAnimation(transition) 63 | } else { 64 | throw new Error(TRANSITION_NOT_VALID) 65 | } 66 | 67 | const animateScroll = () => { 68 | const now = +new Date() 69 | const newScrollPosition = Math.floor( 70 | transitionFunction(now - animationStartTime, start, distance, duration) 71 | ) 72 | 73 | if (!lastScrolledPosition || to !== element[direction]) { 74 | lastScrolledPosition = newScrollPosition 75 | element[direction] = newScrollPosition 76 | } else { 77 | isAnimating = false 78 | if (callback) { 79 | callback(ANIMATION_CANCEL) 80 | rAF.cancel(id) 81 | } 82 | } 83 | 84 | if (now > animationStartTime + duration) { 85 | element[direction] = to 86 | isAnimating = false 87 | if (callback) { 88 | callback(ANIMATION_END) 89 | rAF.cancel(id) 90 | } 91 | } 92 | 93 | if (isAnimating) { 94 | id = rAF.request(animateScroll) 95 | } 96 | } 97 | 98 | id = rAF.request(animateScroll) 99 | } 100 | 101 | // Publish fn in window 102 | if (_window !== {}) { 103 | _window.scrollToWithAnimation = scrollToWithAnimation 104 | } 105 | 106 | export default scrollToWithAnimation 107 | export { rAF } 108 | -------------------------------------------------------------------------------- /public/js/fps.js: -------------------------------------------------------------------------------- 1 | /*! FPSMeter 0.3.1 - 9th May 2013 | https://github.com/Darsain/fpsmeter */ 2 | (function(m,j){function s(a,e){for(var g in e)try{a.style[g]=e[g]}catch(j){}return a}function H(a){return null==a?String(a):"object"===typeof a||"function"===typeof a?Object.prototype.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase()||"object":typeof a}function R(a,e){if("array"!==H(e))return-1;if(e.indexOf)return e.indexOf(a);for(var g=0,j=e.length;gd.interval?(x=M(k),m()):(x=setTimeout(k,d.interval),P=M(m))}function G(a){a=a||window.event;a.preventDefault?(a.preventDefault(),a.stopPropagation()):(a.returnValue= 6 | !1,a.cancelBubble=!0);b.toggle()}function U(){d.toggleOn&&S(f.container,d.toggleOn,G,1);a.removeChild(f.container)}function V(){f.container&&U();h=D.theme[d.theme];y=h.compiledHeatmaps||[];if(!y.length&&h.heatmaps.length){for(p=0;p=m?m*(1+j):m+j-m*j;0===l?g="#000":(t=2*m-l,k=(l-t)/l,g*=6,n=Math.floor(g), 7 | v=g-n,v*=l*k,0===n||6===n?(n=l,k=t+v,l=t):1===n?(n=l-v,k=l,l=t):2===n?(n=t,k=l,l=t+v):3===n?(n=t,k=l-v):4===n?(n=t+v,k=t):(n=l,k=t,l-=v),g="#"+N(n)+N(k)+N(l));b[e]=g}}h.compiledHeatmaps=y}f.container=s(document.createElement("div"),h.container);f.count=f.container.appendChild(s(document.createElement("div"),h.count));f.legend=f.container.appendChild(s(document.createElement("div"),h.legend));f.graph=d.graph?f.container.appendChild(s(document.createElement("div"),h.graph)):0;w.length=0;for(var q in f)f[q]&& 8 | h[q].heatOn&&w.push({name:q,el:f[q]});u.length=0;if(f.graph){f.graph.style.width=d.history*h.column.width+(d.history-1)*h.column.spacing+"px";for(c=0;c