BKWLD / tram

Cross-browser CSS3 transitions in JavaScript.
186 stars 23 forks source link

Matrix transform support? #22

Closed FossPrime closed 10 years ago

FossPrime commented 10 years ago

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.

danro commented 10 years ago

I could be mistaken, but reversing + correctly parsing a transformation matrix seems like the opposite of trivial.. and would require a bunch of extra code.

In regards to the .get() method, I was thinking it would return the current internal transform property like get('x') or y, scale, etc- since tram tracks these values internally.

FossPrime commented 10 years ago

How would Tram's internal values help when the animation is stopped midframe?

getting point values is quite trivial... the main issue would be the design...tram(el).addMatrix(...)?

matrixTo3dPoints = function(matrix) {
    var result = {
                x   : matrix[12],
                y   : matrix[13],
                z   : matrix[15],
                sx  : matrix[0],
                sy  : matrix[5],
                sz  : matrix[10]
            };

    return result;
}

to parse I use

parseMatrixStr = function(matrix_str){
    var m;

    if (matrix_str == "none") {
        return  [   1,  0,  0,  0,
                    0,  1,  0,  0,
                    0,  0,  1,  0,
                    0,  0,  0,  1   ];
    } else if ( matrix_str.indexOf( "matrix(" ) == 0 ) {
        m = matrix_str.replace(/^\w+\(/,"[").replace(/\)$/,"]");
        m = JSON.parse(m);
        m = [   m[0],   m[1],   0   ,   0   ,
                m[2],   m[3],   0   ,   0   ,
                0   ,   0   ,   1   ,   0   ,
                m[4],   m[5],   0   ,   1   ];
        return m;
    } else if ( matrix_str.indexOf( "matrix3d(" ) == 0 ) {
        m = matrix_str.replace(/^\w+\(/,"[").replace(/\)$/,"]");
        m = JSON.parse(m);
        return m;
    } else {
        throw "FATAL error, unknow matrix format.";
    }
};

Granted, I have intentionally avoided skews.

danro commented 10 years ago

Can you give me a use case where you would need to work with a matrix?

FossPrime commented 10 years ago

I can't make a fiddle currently... so here goes nothing:

Say you are animating a popup menu, you want the menu to swoop open and closed. You want the user to be able to drag it back and forth. You want the user to be able to stop it in the middle of a swoop with their finger.

That would require getting the value of the current X and Z translate at every point when the user stops the animation. The browsers all return matrixes... the way to do it is to get the matrix and modify it. It could be simplified if the tram().get(x) and get(z) used the matrix from the browser, but setting a dual value animation on the same transform property is not trivial/impossible with the current system... Not so if we could apply a matrix to animate to.

danro commented 10 years ago

I think I see what you mean. However, tram is primarily focused on transition-based animations. Transitions are great for animations that have a clearly defined start and finish, but not so much for animations with constantly changing values. I wouldn't recommend using a CSS transition to animate something on mousemove or touchmove.

Instead, it sounds like you might be better off building a custom frame-based animation. Here's an example of how you could use tram.frame to calculate an eased value and apply it on each frame.

http://jsbin.com/AXuHiqEH/34/edit?js,output

FossPrime commented 10 years ago

While I agree that running tram.set() on renderAnimationFrame is not efficient, once the finger is of the screen and the close/open state is animated to, it would seem unorthodox to have to change the modus operandi needlessly.

I am looking at my options.

P.S. Found transit... they implement get('transform') as a matrix, making it an all in one solution to my woes. They shy away from parsing however, that's still up to me.

danro commented 10 years ago

Yea, I've intentionally steered clear of parsing the transform matrix because of the difficulty (or even feasibility) of correctly unrolling the values in the reverse order. If you come up with any brilliant solutions for this though, I'd love to see it!

FossPrime commented 10 years ago

I think it's possible to make an tram.add() that uses matrix transforms... it would be relatively challenging. On the other hand, I don't see why we cant tram.add a matrix, for those of us who can. P.S. congrats on the awesome library... it is truly unchallenged, but has room for improvement.