Coder Social home page Coder Social logo

tram's Introduction

tram.js

Cross-browser CSS3 transitions in JavaScript.

About

The idea behind Tram is to take the performance and flexibility of CSS transitions and define them in JavaScript - offering a more powerful, expressive API with auto-stopping, sequencing, and cross-browser fallbacks.

Tram currently depends on jQuery for a few reasons: (1) Per-element data API, (2) Cross-browser CSS getters/setters, and (3) scrollTop/Left offset helpers. Keep these features in mind when making custom jQuery builds or porting tram to your library.

Available on npm: npm install tram
Available on bower: bower install tram

File size:

  • dev ~45 kb
  • min ~16 kb
  • gzip ~4 kb

Examples

How it works

On first load, Tram will use feature detection to determine whether the browser supports CSS transitions. If yes, Tram will manage styles and trust the browser to handle the frame by frame animation. If no, Tram will set styles on each frame, using its own tweening engine powered by requestAnimationFrame and performance.now().

Please keep your arms and legs inside the tram at all times.

Basic usage

Tram can be loaded via AMD, CommonJS, browser globals, or all of the above (via UMD).

var tram = window.tram;
// or
var tram = require('tram');

Before you add a transition to an element, you must first wrap it with the tram() method. This stores a Tram class instance in the element data, which is used for auto-stop and other state.

tram(element);

You may optionally save a reference to this instance, which may help performance for a large group of elements.

var myTram = tram(element); // optional

Each property must now be defined using the add() method. This should feel very familiar to CSS3 transition shorthand: property-name duration easing-function delay

tram(element).add('opacity 500ms ease-out');

Once a transition is defined, it is stored in element data. You may override settings later, for example:

tram(element).add('opacity 2s'); // changed duration to 2 seconds

To begin a transition on your element, the start() method is used.

tram(element).start({ opacity: 0.5 });

If you'd like to listen for the transition end event, use then() and supply a function:

tram(element)
  .start({ opacity: 0.5 })
  .then(function () { console.log('done!') });

Sequencing is also available by using then(). For example:

tram(element)
  .start({ opacity: 0.5 })
  .then({ opacity: 1 })
  .then({ opacity: 0 });

Tram provides some virtual properties to help with CSS3 transforms.

tram(element)
  .add('transform 1s ease-out-quint')
  .start({ x: 100, rotate: 45 }); // aka: translateX(100px) rotate(45deg)

If you need to set style values right away, use the set() method. This will stop any transitions, and immediately set the values.

tram(element).set({ x: 0, opacity: 1 });

Stopping a transition may be done using the stop() method. This also happens automatically whenever start() or set() are called.

tram(element).stop('opacity'); // specific property
tram(element).stop({ opacity: true, x: true }); // multiple properties
tram(element).stop(); // stops all property transitions

That's about it. For more, check out the examples or refer to the docs below.

Methods

TODO document each method

Properties

Browser support for transitioning DOM properties is limited, so Tram attempts to cover the most common cross-browser properties, plus a few extras. This list was compiled using CSS animation specs here and here.

Supported property names / values

'color'                // color
'background'           // color
'outline-color'        // color
'border-color'         // color
'border-top-color'     // color
'border-right-color'   // color
'border-bottom-color'  // color
'border-left-color'    // color
'border-width'         // length
'border-top-width'     // length
'border-right-width'   // length
'border-bottom-width'  // length
'border-left-width'    // length
'border-spacing'       // length
'letter-spacing'       // length
'margin'               // length
'margin-top'           // length
'margin-right'         // length
'margin-bottom'        // length
'margin-left'          // length
'padding'              // length
'padding-top'          // length
'padding-right'        // length
'padding-bottom'       // length
'padding-left'         // length
'outline-width'        // length
'opacity'              // number
'top'                  // length, percentage
'right'                // length, percentage
'bottom'               // length, percentage
'left'                 // length, percentage
'font-size'            // length, percentage
'text-indent'          // length, percentage
'word-spacing'         // length, percentage
'width'                // length, percentage
'min-width'            // length, percentage
'max-width'            // length, percentage
'height'               // length, percentage
'min-height'           // length, percentage
'max-height'           // length, percentage
'line-height'          // number, length, percentage
'transform'            // (see transform info below)
'scroll-top'           // number (tween-only)
'scroll-left'          // number (tween-only)

// TODO - planned support
// 'background-position'  // [x, y] length, percentage
// 'transform-origin'     // [x, y] length, percentage
// 'clip'                 // [x, y, w, h] rectangle
// 'crop'                 // [x, y, w, h] rectangle

Note: dash-style names are required for .add(), but other methods like .start() and .stop() may use camelCase.

Transforms

TODO describe transform shortcuts w/ examples

'x'                    // length, percentage
'y'                    // length, percentage
'z'                    // length, percentage
'rotate'               // angle
'rotateX'              // angle
'rotateY'              // angle
'rotateZ'              // angle
'scale'                // number
'scaleX'               // number
'scaleY'               // number
'scaleZ'               // number
'skew'                 // angle
'skewX'                // angle
'skewY'                // angle
'perspective'          // length

Easings

A useful site with demos of most of these is easings.net

// Defaults
'ease'
'ease-in'
'ease-out'
'ease-in-out'
'linear'

// Quad
'ease-in-quad'
'ease-out-quad'
'ease-in-out-quad'

// Cubic
'ease-in-cubic'
'ease-out-cubic'
'ease-in-out-cubic'

// Quart
'ease-in-quart'
'ease-out-quart'
'ease-in-out-quart'

// Quint
'ease-in-quint'
'ease-out-quint'
'ease-in-out-quint'

// Sine
'ease-in-sine'
'ease-out-sine'
'ease-in-out-sine'

// Expo
'ease-in-expo'
'ease-out-expo'
'ease-in-out-expo'

// Circ
'ease-in-circ'
'ease-out-circ'
'ease-in-out-circ'

// Back
'ease-in-back'
'ease-out-back'
'ease-in-out-back'

TODO

  • Add .get(prop) method to return current value
  • Support array values for props like 'background-position'

Contributing

  1. If you'd like to contribute to this project, please submit all pull requests to the dev branch. Any pull requests sent to master will be closed. This is mostly to offset the convenience of having various dist/* files available on the master branch.

  2. Grunt CLI tools may be helpful. The following commands should start a watch script that concats source files on each save:
    (from the root directory)
    npm install grunt -g
    grunt

  3. Once you're ready to send a pull request, please view test/suite.html in your browser to confirm that all tests are passing.

Thanks

Special thanks to the following open source authors + libraries.

@ded - https://github.com/ded/morpheus
@rstacruz - https://github.com/rstacruz/jquery.transit
@visionmedia - https://github.com/visionmedia/move.js
@jayferd - https://github.com/jayferd/pjs

MIT License

This code may be freely distributed under the MIT license.

Terms Of Use - Easing Equations

Open source under the BSD License.

Copyright © 2001 Robert Penner All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

tram's People

Contributors

danro avatar weotch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tram's Issues

Support CSS filters

cc @josephschmitt

Would need to add a feature detect for this, and implement a property class similar to Transform.

Feature detect from modernizr:

// https://github.com/Modernizr/Modernizr/issues/615
// documentMode is needed for false positives in oldIE, please see issue above
Modernizr.addTest('cssfilters', function() {
    var el = document.createElement('div');
    el.style.cssText = Modernizr._prefixes.join('filter' + ':blur(2px); ');
    return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
});;

Support chaining with wait()

I'd like this to work:

    $(this).tram()
            .set({opacity:0, top:-3})
            .add('opacity 400ms')
            .add('top 400ms ease-out')
            .wait(i*80)
            .then(function() { this.start({opacity: 1, top: 0}); })
            .wait(500)
            .then(function() { this.start({opacity: 0}); })
        ;
    });

I tried putting the second wait() inside of a then() but that didn't work. What I'm seeing is the first then() running but not the second.

Modify transition settings during queue

This was mentioned previously, but I had a new idea for how we could handle it.

Technically, in order for start() to do anything at all, .add() must have been invoked to create a transition property.

I propose that when .add() is invoked after a queue has been created, it will also queue the .add() settings. So I think the following would work out well:

tram(elem)
  .add('width 1s')
  .add('height 2s')
  .start({ width: 400, height: 200 }) // queue is created here
  .add('height 500ms') // this will happen after start() is ended
  .then({ height: 20 })

I think it makes sense that anything after .start() should be considered part of the queue.

cc @rvratner @weotch @mattaebersold

Safari [6.0.2 - 6.0.3] flickering bug

Looks like desktop Safari has an annoying flickering bug when setting transitions via JavaScript -- even with GPU cache tricks in place. More details: here and example here

Because of this, and questionable flickering / performance in Firefox, I may have to add UA sniffs to force tween fallback mode in certain browsers.

Feature idea: specify time using number only

Was using TweenLite recently and it's kind of nice how they deal with the time specification. I didn't look at their source to see EXACTLY what their breakpoint is on this, but if you give a number for the tween duration that is like < 20 or something, it's treated as seconds. Otherwise, it's ms. So;

  • time: .3 // That's seconds
  • time: 300 // That's ms.

Fix unit tracking in transform properties

For some reason, the units of transform sub-properties aren't tracking properly, so you end up with warnings like this (when using non-default units):

Units do not match [tween]: 3deg, 6rad 

jQuery Collections Ignore 'Then'

tram($('li')).add('width 2s').start({width:'100%'}).then(function(){ console.log('fired'); });

'then' is never fired. It seems to be an issue specific to collections, since it works as it should with single items. Also, the transition is applied to the whole collection as it should be, it just does not trigger 'then' afterwards.

Support SVG dash offset

SVGs are not the best choice for animation, but I'd like to experiment with this neat trick for drawing lines:

From: http://jakearchibald.com/2013/animated-line-drawing-svg/

var path = document.querySelector('.squiggle-animated path');
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
  'none';
// Set up the starting positions
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition =
  'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';

Bad selectors throw a fatal error

Take this example:

this.$download = $('#download');
tram(this.$download).show().set({ y: this.$download.height() * 1.5 })

If #download doesn't exist, I'm getting this JS error:

Uncaught TypeError: Cannot read property 'style' of undefined , tram.js, line 538

I personally think Tram should shrug and move on rather than throwing a fatal error.

GPU layering approach info?

Is there any gpu layer management or creation going on in the background? Or do we manage that as users of the library? I noticed you have transforms and z listed...

Git rid of Makefile?

@danro I was thinking of ditching the Makefile since it's just aliasing some simple grunt tasks. We could even make a custom task to do the build work to make it simpler to call, like grunt compile. Got any problems with that?

Allow set() to apply "auto"

Here's some example code:

    var w = this.$el.width(); // IE9 wouldn't let me set width to 100%
    this.$hr.tram()
        .add('width 200ms ease-out')
        .wait(1000)
        .then(function() { 
            this.start({ opacity:1, width: w }).then(function() {

                // Set the width to auto so it's responsive
                this.set({width: 'auto'});
            });
        })
    ;

this.set({width: 'auto'}); is causing:

Type warning: Expected: [number(px) or string(unit or %)] Got: [string] auto tram.js:1450

But I think that this is a valid use for set. Thoughts?

Matrix transform support?

I've been working on a project and I almost decided not to use tram because of its lack of matrix transforms. Currently, when I ask the browser for what 3d transform is applied, it will give me a matrix3d or matrix string. If we are to support .get in the future, it seems logical that matrixes should at least be an option for power users.

Ps, it is almost trivial to make a .get for the various transforms when matrixes are used.

Feature ideas: delays and step durations

After using tram on an actual project this weekend, I had some ideas about delays and durations.

1st, a delay in between queue steps is a must. I think wait() works nicely for this. I can alias it to "delay" if enough people prefer that.

tram(elem)
  .start({ opacity: 0 })
  .wait(2000)
  .then({ opacity: 1 })

2nd, I thought it would be nice to manually set the step duration for each step in the queue. For example, say you have opacity set to 1s, and width set to 400ms. Currently, Tram would wait for 1s, because that's the longest duration in that step:

tram(elem)
  .add('opacity 1s').add('width 400ms')
  .start({ opacity: 0.5, width: 100 }) // this step would take 1 second.
  .then(something)

But we could introduce a span virtual property to control how long to wait before going to the next step:

tram(elem)
  .add('opacity 1s').add('width 400ms')
  .start({ opacity: 0.5, width: 100, span: 500 }) // this step would take 500ms 
  .then(something)

Does span make you think too much about the dom? Should we call it time instead? I'm trying to keep it very separate from duration because that means something else entirely.. and I don't want new users to get confused about how this feature would compare to a traditional tween library like jquery.animate.

cc @josephschmitt @jeremiak @weotch

Rework macros to be used as static tram properties.

Macros should be reworked a bit.

Instead of strings, I think they'd be more useful like this:

tram(element)
  .start({ x: 200, opacity: 0 })
  .then(tram.hide);

or

tram(element)
  .start(tram.slideDown)
  .then(tram.slideUp)
  .then(function () { console.log('done') });

Getting an undefined on `wait()`

Here's my command:

tram($el)
.set({ 'margin-bottom': '10px' })
.add('margin-bottom 300ms')
.wait(i*100)
.start({ 'margin-bottom': 0 });

Error is: Uncaught TypeError: Object # has no method 'wait' hero.js:69

Use 'set' without adding a transition

The set method doesn't work unless a transition has been added for that property, which seems weird since set occurs immediately without any transition.

Warning: No active transition timer

tram($('#main')).add('width 10s linear').start({width:'50%'}).then(function(){ console.log('success'); });

Works as it should, without any issues except on collections. However, the chain returns a warning in Firebug:

"No active transition timer. Use start() or wait() before then()."

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.