Carl Poole
Carl Poole

Reputation: 2030

Dynamically change transform-origin for a scale in jquery after drag

I'm working on an page that contains a rectangular inner-block inside a container. The inner-block can be dragged and also be scaled when you scroll the mouse.

[ See my JSFiddle. ]

The center of the screen is the origin point of the zoom transformation, so when the inner-block is centered in the page it appears to simply scale, but when you drag the inner-block about the center origin point, it will scale appropriately around or away from the center point of the screen. I marked the center screen point with a small red dot in the JSFiddle so its easier to see.

As the inner-block is dragged around I recalculate the top/left coords of it, and also the difference between that position and the center of the page in order to get the transformation-origin adjustment coords.

PROBLEM: It works fine when the inner-block is scale-factor 1, but if you zoom and then drag the object, it unexpectedly jumps position and doesn't zoom back correctly. Are you able to see what I am doing wrong, or what I would need to add to prevent the unexpected behavior? Thanks in advance!

//Get center of the page "origin"
var originX = $('.block').width()/2;
var originY = $('.block').height()/2;

//Get center point of the inner-block
var blockRX = $('.inner-block').width()/2;
var blockRY = $('.inner-block').height()/2;

//Set position of the inner-block to match center origin initially
$(".inner-block").css({top: originY-blockRY, left: originX-blockRX});
$(".inner-block").draggable();

//Initial Scale 1:1
var scale_system = 1;

//Get Top/Left coords of inner-block
var blockTop = $('.inner-block').offset().top;
var blockLeft = $('.inner-block').offset().left;

//Calculate diff between center of page and Top/Left of inner-block
var xCalc = (originX-blockLeft);
var yCalc = (originY-blockTop);

//Set origin of transformations as center of page (in relation to Top/Left)
//Using the just calculated values
$(".inner-block").css({"-webkit-transform-origin": xCalc+"px "+yCalc+"px"});

//Zoom settings
var maxScale = 4;
var minScale = 1;
var zoomScale = .07;

//Drag Actions
$(function() {
    var isDragging = false;

    //Perform calculations as drag occurs
    $(".inner-block").mousedown(function() {
        $('.inner-block').mousemove(function(e) {
            isDragging = true;
            $(window).unbind("mousemove");

            //Get New Top/Left of inner-block as it drags
            blockTop = $('.inner-block').offset().top;
            blockLeft = $('.inner-block').offset().left;
            console.log("BlockTopLeft "+blockLeft+" "+blockTop);

            //Calculate new diff between Top/Left and Origin
            xCalc = (originX-blockLeft);
            yCalc = (originY-blockTop);
            console.log("Origin Distance "+xCalc+" "+yCalc);
            })
    })
    .mouseup(function() {
        var wasDragging = isDragging;
        isDragging = false;
        $(window).unbind("mousemove");
        if (wasDragging) {
            //Update origin position in relation to Top/Left of inner-block
            $(".inner-block").css({"-webkit-transform-origin": xCalc+"px "+yCalc+"px"});
        }
    });
});

//Perform scroll function below on mousewheel
$('.block').bind('mousewheel', function (event) {
    scroll(event);
});

function scroll(event) {

    event.preventDefault();  

    var newScale = ((event.originalEvent.wheelDelta / 120 > 0) ? 
                    (scale_system * (1.0 + zoomScale)) : 
                    (scale_system * (1.0 - zoomScale)));

    scale_system = ((newScale > maxScale) ? 
                    (maxScale) : 
                    (((newScale < minScale)?
                      (minScale):
                      (newScale)))
                   );

    //Update Top/Left position of the inner-block
    blockTop = $('.inner-block').offset().top;
    blockLeft = $('.inner-block').offset().left;
    console.log("BlockTopLeft "+blockLeft+" "+blockTop);

    //Update X/Y radius to block center
    blockRX = ($('.inner-block').width()/2)*scale_system;
    blockRY = ($('.inner-block').height()/2)*scale_system;
    console.log("BlockRXY "+blockRX+" "+blockRY);

    //Recalculate the diff between T/L and origin
    console.log("Origin "+originX+" "+originY);
    xCalc = (originX-blockLeft);
    yCalc = (originY-blockTop);
    console.log("Origin - TL "+xCalc+" "+yCalc);

    $(".inner-block").css({"-webkit-transform": "scale(" + scale_system + ")"}); 
}

Upvotes: 2

Views: 1461

Answers (1)

Carl Poole
Carl Poole

Reputation: 2030

I think I have found the answer to my own question. After much Googling it appears there are problems with jQuery when trying to perform CSS transformations paired with dragging. There is an extensive issue page on jQuery's development ticket page highlighting the problem and many examples, and they have decided not to address the problem. I'm going to explore other options.

Upvotes: 1

Related Questions