jQuery Drag/Resize with CSS Transform Scale

前端 未结 13 2015
忘了有多久
忘了有多久 2020-11-27 13:39

I am applying a CSS transform (and the browser specific -webkit, -o etc):

transform: matrix(0.5 , 0 , 0, 0.5, 0 , 0);

to a div then using jQuery\'s draggable

13条回答
  •  悲哀的现实
    2020-11-27 14:32

    Another approach would be to add a plugin that compensate for the transformation ( remember to add "transform : true" to the plugin initialization.

    The ui.draggable need to be passed via a inverse matrix of the transformation in order to position the element in the un-transformed space which the browser later transform on display.

    For "draggable" the following worked for me ( jqueryui 1.10 ) ( the matrix calculation I have taken from jquery.panzoom):

    var Matrix = function(a, b, c, d, e, f, g, h, i) {
        if ($.type(a) === 'array') {
            this.elements = [
                +a[0], +a[2], +a[4],
                +a[1], +a[3], +a[5],
                    0,     0,     1
            ];
        } else {
            this.elements = [
                a, b, c,
                d, e, f,
                g || 0, h || 0, i || 1
            ];
        }
    };
    
    Matrix.prototype = {
        /**
         * Multiply a 3x3 matrix by a similar matrix or a vector
         * @param {Matrix|Vector} matrix
         * @return {Matrix|Vector} Returns a vector if multiplying by a vector
         */
        x: function(matrix) {
            var isVector = matrix instanceof Vector;
    
            var a = this.elements,
                b = matrix.elements;
    
            if (isVector && b.length === 3) {
                // b is actually a vector
                return new Vector(
                    a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
                    a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
                    a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
                );
            } else if (b.length === a.length) {
                // b is a 3x3 matrix
                return new Matrix(
                    a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
                    a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
                    a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
    
                    a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
                    a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
                    a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
    
                    a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
                    a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
                    a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
                );
            }
            return false; // fail
        },
        /**
         * Generates an inverse of the current matrix
         * @returns {Matrix}
         */
        inverse: function() {
            var d = 1 / this.determinant(),
                a = this.elements;
            return new Matrix(
                d * ( a[8] * a[4] - a[7] * a[5]),
                d * (-(a[8] * a[1] - a[7] * a[2])),
                d * ( a[5] * a[1] - a[4] * a[2]),
    
                d * (-(a[8] * a[3] - a[6] * a[5])),
                d * ( a[8] * a[0] - a[6] * a[2]),
                d * (-(a[5] * a[0] - a[3] * a[2])),
    
                d * ( a[7] * a[3] - a[6] * a[4]),
                d * (-(a[7] * a[0] - a[6] * a[1])),
                d * ( a[4] * a[0] - a[3] * a[1])
            );
        },
        /**
         * Calculates the determinant of the current matrix
         * @returns {Number}
         */
        determinant: function() {
            var a = this.elements;
            return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
        }
    };
    
    var Vector = function (x, y, z) {
        this.elements = [ x, y, z ];
    };
    
    /**
     * Get the element at zero-indexed index i
     * @param {Number} i
     */
    Vector.prototype.e = Matrix.prototype.e = function(i) {
    
        if( this.elements[ i ] != undefined ){
            return this.elements[ i ];    
        }
    
        return this.elements;
    };    
    
    $.ui.plugin.add("draggable", "transform", {
    
        start: function( event, ui ) {
    
            if(!$(this).data('ui-draggable')){
                return false;
            }            
    
            var inst = $(this).data("ui-draggable");
    
            inst.matrix = new Matrix(function(matrix){
    
                var rmatrix = new RegExp(
                        '^matrix\\(' +
                        '(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
                        '(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
                        '(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
                        '(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
                        '(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
                        '(\\-?[\\d\\.e]+)' + '\\)$'
                );                
    
                var matrix = rmatrix.exec( matrix );
                if (matrix) {
                    matrix.shift();
                }
                return matrix || [ 1, 0, 0, 1, 0, 0 ];
    
            }([$(this).parents('[style*="transform"]').css('transform')]));            
        },
        drag: function( event, ui ) {
    
            if(!$(this).data('ui-draggable')){
                return false;
            }            
    
            var inst = $(this).data("ui-draggable");
    
            var t_pos = inst.matrix.inverse().x(new Vector(ui.position.left, ui.position.top, 0));
    
            ui.position.left = t_pos.e(0);
            ui.position.top = t_pos.e(1);                   
    
            if(inst.options.grid) {
                ui.position.left = ui.position.left - ui.position.left % inst.options.grid[0];
                ui.position.top  = ui.position.top - ui.position.top % inst.options.grid[1];                
            }
    
            if( inst.containment ){
    
                if( ui.position.left < inst.containment[0] ){
                    ui.position.left = inst.containment[0];
                }
    
                if( ui.position.left > inst.containment[2] ){
                    ui.position.left = inst.containment[2];
                }                
    
                if( ui.position.top < inst.containment[1] ){
                    ui.position.top = inst.containment[1];
                }  
    
                if( ui.position.top > inst.containment[3] ){
                    ui.position.top = inst.containment[3];
                }
            }
        },     
    });
    

提交回复
热议问题