diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..f6cd079 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,79 @@ +{ + "rules": { + "comma-dangle": 2, + "no-cond-assign": 2, + "no-console": 2, + "no-debugger": 2, + "no-dupe-keys": 2, + "no-dupe-args": 2, + "no-empty": 2, + "no-empty-character-class": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": 2, + "semi": [ 2, "always" ], + "no-extra-semi": 2, + "no-func-assign": 2, + "no-inner-declarations": 2, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-negated-in-lhs": 2, + "no-obj-calls": 2, + "no-regex-spaces": 2, + "no-sparse-arrays": 2, + "no-unreachable": 2, + "use-isnan": 2, + "valid-typeof": 2, + + "strict": [ 2, "global" ], + + "block-scoped-var": 2, + "eqeqeq": 2, + "dot-notation": 1, + "no-alert": 2, + "no-else-return": 2, + "no-eq-null": 2, + "no-new": 2, + "no-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 1, + "no-invalid-this": 0, + "no-redeclare": 2, + "no-return-assign": 2, + "wrap-iife": [2, "inside"], + + "no-delete-var": 2, + "no-label-var": 2, + "no-undef": 2, + "no-undef-init": 2, + "no-shadow": 1, + "no-unused-vars": 1, + + "no-mixed-requires": 1, + "no-new-require": 2, + "no-path-concat": 2, + "no-sync": 1, + + "quotes": [ 2, "single" ], + "key-spacing": 2, + "no-spaced-func": 2, + "no-mixed-spaces-and-tabs": [ 2 ], + "no-multiple-empty-lines": [ 1, { "max": 2 }], + "operator-linebreak": [2, "after"], + "object-curly-spacing": [ 2, "always" ], + "space-after-keywords": [ 2, "always" ], + "semi-spacing": [2, {"before": false, "after": true}], + "brace-style": [ 2, "1tbs", { "allowSingleLine": true } ], + "space-infix-ops": 2, + "space-unary-ops": [ 2, { "words": true, "nonwords": false } ], + + "arrow-spacing": [ 2, { "before": true, "after": true } ], + "arrow-parens": [ 2 ], + "prefer-const": 1 + }, + "env": { + "es6": true, + "node": true, + "mocha": true + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..88f73b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.html diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..ed2be9a --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +docs +src +Gruntfile.js \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..b913b7c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v4.1.0 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..958bf33 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +sudo: false +node_js: + - "4.1" diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 772e18c..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = function(grunt) { - - // Project configuration. - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - uglify: { - options: { - banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' - }, - dist: { - src: 'src/*.js', - dest: 'dist/snabbt.min.js' - }, - }, - concat: { - options: { - separator: ';', - }, - dist: { - src: 'src/*.js', - dest: 'dist/snabbt.js', - }, - }, - }); - - // Load the plugin that provides the "uglify" task. - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-concat'); - - // Default task(s). - grunt.registerTask('default', ['uglify', 'concat']); -}; diff --git a/LICENSE.txt b/LICENSE.txt index 3a25dea..8dd155e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Daniel Lundin +Copyright (c) 2015 Daniel Lundin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index dbc5879..1bf6f39 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,91 @@ -snabbt.js -========= -Fast animations with Javascript and CSS transforms(Work in progress) +# snabbt.js -- [Docs](http://daniel-lundin.github.io/snabbt.js/) -- [Demo cards](http://daniel-lundin.github.io/snabbt.js/cards.html) -- [Demo sticks](http://daniel-lundin.github.io/snabbt.js/sticks.html) +Fast animations with Javascript and CSS transforms + +[](https://travis-ci.org/daniel-lundin/snabbt.js/builds/) +[](https://badge.fury.io/js/snabbt.js) + +**Docs** + +[Documentation](http://daniel-lundin.github.io/snabbt.js/) + +**Demos** + +- [Card formations](http://daniel-lundin.github.io/snabbt.js/cards.html) +- [Crazy sticks](http://daniel-lundin.github.io/snabbt.js/sticks.html) +- [Periodic table](http://daniel-lundin.github.io/snabbt.js/periodic.html) +- [Laser words](http://daniel-lundin.github.io/snabbt.js/words.html) + +## Releases +The initial release is out. Would love some feedback on things that can be improved. The release(and future ones) can be found in the release section + +- **0.6.4** - Manual mode complete bug fix +- **0.6.3** - IE Bug fix, polyfill for Array.prototype.find +- **0.6.2** - Bug fixes, Added sequencing of animations +- **0.6.1** - Fixed UMD-build +- **0.6.0** - ES6, test suite, life cycle events, new demos +- **0.5.8** - Add new tweenable property scalePost/fromScalePost +- **0.5.7** - Fix issues manual mode and spring easings +- **0.5.6** - Fix issues with duration: 0 +- **0.5.4** - Added allDone-callback, updated docs +- **0.5.3** - Bugfix for manual mode with easings +- **0.5.2** - Compability fixes, polyfill for request animation frame +- **0.5.1** - Performance improvements +- **0.5.0** - Refactoring, show deprecation warnings +- **0.4.0** - Manual mode, function initalizers +- **0.3.0** - Memory optimizations, improved Matrix API, better UMD wrappers +- **0.2.0** - Added support for RequireJS and browserify. Published to npm and bower +- **0.1.0** - Initial beta release + +## Get it +snabbt is available with AMD-support, CommonJS-support and as a global module. + +### Package managers +``` +bower install snabbt.js +npm install snabbt.js +``` + +### CDNs + +``` +https://cdnjs.com/libraries/snabbt.js +http://www.jsdelivr.com/#!snabbt +``` +## Browser Support + +
![]() |
+ ![]() |
+ ![]() |
+ ![]() |
+
+ |
10+ | +✓ | +✓ | +✓ | +✓ | +
< 4kb minified and gzipped
+~5kb minified and gzipped
Write less, animate more
npm install snabbt.js
bower install snabbt.js
Warning: snabbt.js is under development, breaking changes could occur. This document should be seen as a draft.
@@ -84,13 +97,14 @@snabbt.js is built to be fast. It will only animate things that modern browsers can animate cheaply: transforms and opacity. The goal is to make a library that will let the user make smooth animations without needing to know too much about browser rendering.
-Note: For convienience, width and height are animatable to, but be aware of those. They may cause page reflows and slow down your animations.
+Note: For convenience, width and height are animatable too, but beware since they may cause page reflows and slow down your animations.
Animations are started with the snabbt-function call. The function takes an element as first parameter and a configutation-object as second. Example:
+Animations are started with the snabbt-function call. The function takes an element as first parameter(or list there of) and a configutation-object as second. Example:
snabbt(element, {
+ snabbt(element, {
position: [100, 0, 0],
rotation: [Math.PI, 0, 0],
- duration: 1000,
- delay: 100,
easing: 'ease'
});
Animation can be chained by using the `then()`-method on the returned animation object. all from_xxx properties will be set to the end state of the previous animation.
+Animation can be chained by using `snabbt()` on the returned animation object. All fromXxx properties will be set to the end state of the previous animation.
snabbt(element, {
+ snabbt(element, {
position: [100, 0, 0],
easing: 'ease'
-}).then({
- from_rotation: [0, 0, -2*Math.PI],
+}).snabbt({
+ fromRotation: [0, 0, -2*Math.PI],
+ position: [0, 0, 0],
easing: 'spring',
- spring_constant: 0.2,
- spring_deaccelaration: 0.95,
-});
-
snabbt.js works with or without jQuery. If jQuery is detected snabbt.js will be loaded as a jQuery-plugin. When using snabbt.js with jQuery, the first parameter is the animation configuration:
-$element.snabbt({
- position: [150, 0, 0],
- rotation: [0, 0, Math.PI],
-});
- snabbt(element, {
- position: [150, 0, 0],
- rotation: [0, 0, Math.PI],
+ springConstant: 0.2,
+ springDeceleration: 0.90,
+ springMass: 10,
});
Animation can be stopped at any time by replacing the animation configuration with the string literal 'stop':
+snabbt(element, 'stop');
+ If a new animation is started with the same element it will start from the stopped position unless the 'from'-properties are used.
snabbt.js includes four easing functions: linear, ease, ease-in and ease-out. You can also use your own easing functions or use the physics based spring easing
+
snabbt.js includes four easing functions: linear, ease, easeIn and easeOut. You can also use your own easing functions or use the physics based spring easing
Instead of easing name, pass in a function that takes one parameter:
- +snabbt(element, {
+ snabbt(element, {
position: [200, 0, 0],
easing: function(value) {
- return Math.sin(Math.PI * value);
+ return value + 0.3 * Math.sin(2*Math.PI * value);
}
+}).snabbt({
+ position: [0, 0, 0],
+ easing: 'easeOut'
});
When using spring easing, the duration parameter is not in effect. Instead the animation will progress until equilibrium is reached. When easing is set to spring there are three additional parameters that can be set on the animation configuration:
Example:
-snabbt(element, {
+ snabbt(element, {
position: [100, 0, 0],
rotation: [0, 0, 2*Math.PI],
easing: 'spring',
- spring_constant: 0.3,
- spring_deacceleration: 0.8,
-}).then({
- rotation: [0, 0, 2*Math.PI],
- easing: 'ease'
+ springConstant: 0.3,
+ springDeceleration: 0.8,
+}).snabbt({
+ position: [0, 0, 0],
+ easing: 'spring',
+ springConstant: 0.3,
+ springDeceleration: 0.8,
});
+
Advanced concepts
This section describes some of the more advanced usages.
+ Sequence
+ Chaining is convenient when animating a single element or group of elements in multiple steps. However, if you want to trigger animations on a different set of element once one animation is completed you often end up with a lot of callbacks. This is where sequencing comes into play. snabbt.sequence is a function call that allows you to specify an array of animations that should run in sequence.
+ snabbt.sequence([
+ [elementTwo, {
+ position: [100, 0, 0],
+ }],
+ [elementOne, {
+ position: [100, 0, 0],
+ }],
+ [elementOne, {
+ position: [0, 0, 0],
+ }],
+ [elementTwo, {
+ position: [0, 0, 0],
+ }],
+ ]
+);
+
+
+
+
+
+
Value feeding
- The animation object is very simple to work with but has it limitations. Sometimes you want to do the transforms in another order. This is where value feeding comes handy. The value_feeder parameter expects a function that takes one parameter which will progress from 0 to 1. Every time it is called you should return a snabbtjs.matrix(see Matrix API) representing the current transform.
- snabbt(element, {
- value_feeder: function(i) {
+ The animation object is very simple to work with but has it limitations. Sometimes you want to do the transforms in another order. This is where value feeding comes handy. The valueFeeder parameter expects a function that takes two parameters, one which will progress from 0 to 1 and an identity matrix that you can modify. The function will be called every frame and should return a matrix(see Matrix API) representing the current transform.
+ snabbt(element, {
+ valueFeeder: function(i, matrix) {
var x = Math.sin(i*Math.PI);
- return snabbtjs.mult(snabbtjs.rotZ(Math.sin(6*i*Math.PI)), snabbtjs.trans(x*400, 0, 0));
+ return matrix.rotateZ(Math.sin(6*i*Math.PI)).translate(x*200, 0, 0);
},
duration: 1000
});
+ Transform origin
+ By default, rotations are applied around the center of the element. By using transformOrigin rotations can be performed around abritary positions.
+ snabbt(element, {
+ rotation: [0, 2*Math.PI, 0],
+ transformOrigin: [element.clientWidth/2, 0, 0]
+});
+
+
+
+
+
+ Manual mode
+ By using manual mode, animations can be fed by user input instead of just being time-based. Define your animations as you normally would but set the manual-property to true. Instead of returning a chainer object, an animation control object is returned. The control object has the following methods:
+
+ - setValue(value) - value should be a number between 0 and 1 where 0 represents the beginning of the animation and 1 represents the end
+ - rollback(callback) - Rollbacks the animation to the start state. The callback is an optional parameter that will be called when the rollback is completed
+ - finish(callback) - Will complete the animation starting at the value last called to setValue
+
+ Here's silly an example of what this could be used for(powered by the great Hammer.js):
+
+ Peek-a-boo!
+
+ Drag to flip!
+ Flip me back!
+
+
+
Attention animations
snabbt.js has support for attention animations. This can be useful in form validations when you want to draw attention to a form element for example. Attention animation use spring easings.
- snabbt(element, 'attention', {
+ snabbt(element, 'attention', {
rotation: [0, 0, Math.PI/2],
- spring_constant: 1.9,
- spring_deacceleration: 0.9,
+ springConstant: 1.9,
+ springDeceleration: 0.9,
});
- snabbt(element, 'attention', {
+ snabbt(element, 'attention', {
position: [50, 0, 0],
- spring_constant: 2.4,
- spring_deacceleration: 0.9,
+ springConstant: 2.4,
+ springDeceleration: 0.9,
});
+
+
+ Multi-element animations
+ Several elements can be animated with a single snabbt-call by passing a list of elements instead of just one. If you want to set different values for each of the elements you can pass initilization functions for the properties instead of actual values.
+ The initialization functions take two parameters, the current index of the element in the collection and the total number of elements. The functions must return a value in the same format as usual, e.g. a position function initializer must return an array of three coordinates.
+ This makes it possible to create complex animations with very little code:
+
+ snabbt(document.querySelectorAll('.multi-example-box'), {
+ fromRotation: [0, 0, 0],
+ rotation: function(i, total) {
+ return [0, 0, (i/(total - 1)) * (Math.PI/2)];
+ },
+ delay: function(i) {
+ return i * 50;
+ },
+ easing: 'spring',
+}).snabbt({
+ rotation: [0, 0, 0],
+ delay: function(i, total) {
+ return (total - i - 1) * 50;
+ },
+ easing: 'ease',
+});
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To see a more elaborate example of this, check out the sticks demo
+
+
+ Module loaders
+ snabbt.js is wrapped in a UMD boilerplate which means it will work with both RequireJS and browserify.
+ CommonJS:
+ var snabbt = require('snabbt.js');
+
+snabbt(element, {
+ position: [200, 0, 0]
+});
+
+
+ AMD:
+ require(['snabbt.js'], function(snabbt) {
+ snabbt(element, {
+ rotation: [2*Math.PI, 0, 0]
+ });
+});
+
+
+
+ jQuery
+ snabbt.js works with or without jQuery. If jQuery is detected snabbt will be loaded as a jQuery-plugin. When using snabbt with jQuery, the first parameter is the animation configuration:
+
+
+ With jQuery
+ $element.snabbt({
+ position: [150, 0, 0],
+ rotation: [0, 0, Math.PI],
+});
+
+
+ Without jQuery
+ snabbt(element, {
+ position: [150, 0, 0],
+ rotation: [0, 0, Math.PI],
+});
+
+
+
+
+
Matrix API
- The following functions represents the Matrix API:
+ Matrix operations are performed using the Matrix class. The class has the following methods:
- - snabbtjs.ident() - Returns the identity matrix
- - snabbtjs.trans(x, y, z) - Returns a translation matrix
- - snabbtjs.rotX(radians) - Returns a rotation around the x-axis
- - snabbtjs.rotY(radians) - Returns a rotation around the y-axis
- - snabbtjs.rotZ(radians) - Returns a rotation around the z-axis
- - snabbtjs.scale(x, y) - Returns a scaling matrix
- - snabbtjs.skew(ax, ay) - Returns a skew matrix
- - snabbtjs.mult(A, B) - Returns the matrix multiplication product of A * B
+ - Matrix.translate(x, y, z) - Multiplies with a translation matrix
+ - Matrix.rotateX(radians) - Multiplies with a rotation around the x-axis
+ - Matrix.rotateY(radians) - Multiplies with a rotation around the y-axis
+ - Matrix.rotateZ(radians) - Multiplies with a rotation around the z-axis
+ - Matrix.scale(x, y) - Multiplies with a scaling matrix
+ - Matrix.skew(ax, ay) - Multiplies with a skew matrix
+ - Matrix.clear() - Sets the matrix to the identity matrix
+ All operations are chainable to make writing matrix multiplications concise, e.g.:
+ matrix.translate(100, 0, 0).rotateX(Math.PI);
+
+ Freeform transforms
+ The matrix operations can be used outside of snabbt's animation engine. This could be useful for interactive animations.
+ var matrix = snabbt.createMatrix();
+matrix.translate(100, 0, 0);
+snabbt.setElementTransform(element, matrix);
Animation configuration
- The following parameters can on the configuration object:
+ The following parameters can be used in the configuration object:
@@ -379,17 +540,17 @@ Animation configuration
position - Pixel offsets in each x-, y- and z-direction
rotation - Rotation in radians in x-, y- and z-direction
scale - Scale in x- and y-direction
- rotation_post - Rotation applied after position and rotation
- width - Element width in pixels
- height - Element height in pixels
- opacity - Element opacity(0 - 1)
+ rotationPost - Rotation applied after position and rotation
+ width - Element width in pixels(fromWidth mandatory if used)
+ height - Element height in pixels(fromHeight mandatory if used)
+ opacity - Element opacity(0 - 1)(fromOpactiy mandatory if used)
duration - Animation duration in milliseconds
delay - Delay before the animation is started in milliseconds
- loop - Number of times to repeat the animation
- callback - Function to be called when animation is completed
+ complete(index, total) - Function to be called when animation is completed. If multiple elements are animated, this function will be called once for every element with two parameters, index of current element and total elements in the animated collection. this will be bound the current element
+ allDone - Will be called once independent of how many elements animated
- A from_xxx can be set on most properties:
+ A 'from'-property can be set on most properties. Note that 'from' has precedance over the previous end state.