Image positioning when scaling,dragging and rotating

872 views Asked by At

Im working on some code to manipulate an image. I have it 90% working but have ran into a bug that has me pulling my hair out! So I have two sliders. The left slider is to rotate and the right slider is to zoom (scale). You can also drag the image to position it.

The is a certain sequence that will cause the image to jump when it is scaled. the sequence is:

Rotate, Scale, Rotate, Scale, Drag, Scale.

On the final scale you will be able to see the image jump out of position. This is the but i am getting.

I ahve added some of my code below and my full code can be tested in the jsfiddle here

Drag:

// Drag Handler
$('#posUsrImgWrap').draggable({
    drag:function(event, ui){
        var il = ui.position.left;
        var it = ui.position.top;
        var iw = $(this).width();
        var ih = $(this).height();
        $('#posUserImg').css({'top':it+'px','left':il+'px'});
        dragged = true;
        zc = 0;
    },
    stop:function(){
        ixz = $('#posUserImg').position().left;
        iyz = $('#posUserImg').position().top;
        if(rotated){
            if(!zoomed){
                rx=orx*zv;
                ry=ory*zv;
            }
            ixz=ixz+rx;
            iyz=iyz+ry;
        }
        rxz=ixz;
        ryz=iyz;
        zoomed=false;
        rd=true;
    }
});

Rotate:

$( "#slider-vertical" ).show().slider({
    orientation: "vertical",
    min: -180,
    max: 180,
    value: sv,
    slide: function( event, ui ) {
        var rv = ui.value; // Rotate Value

        $('#posUserImg, #posUsrImgWrap').rotate(rv);
        $('#rVal').val(rv);
    },
    stop:function(){
        rx=((rxz - $('#posUserImg').position().left));
        ry=((ryz - $('#posUserImg').position().top));
        orx=rx;
        ory=ry;
        rzv=zv;
        rotated=true;
    }
});

Scale:

$( "#slider-vertical-zoom" ).show().slider({
        orientation: "vertical",
        min: -90,
        max: 150,
        step: 5,
        value: szv,
        start:function(){
            czv = (1+ $(this).slider("value")/100);
        },
        slide: function( event, ui ) {
            zv = (1+ ui.value/100); // Zoom Value
            var nx = 0;
            var ny = 0;

            var ozv =  (1+ parseInt($('#zVal').val())/100);

            nzo = calculateAspectRatioFit(iwz, ihz, iwz*(ozv), ihz*(ozv));

            if (dragged && zc == 0){
                var wt = Math.abs(iwz - nzo.width);
                var ht = Math.abs(ihz - nzo.height);
                if (czv < 1){
                    ixz = ixz-(wt/2);
                    iyz = iyz-(ht/2);
                } else {
                    ixz = ixz+(wt/2);
                    iyz = iyz+(ht/2);
                }
            }

            nzo = calculateAspectRatioFit(iwz, ihz, iwz*(zv), ihz*(zv));

            $('#posUserImg, #posUsrImgWrap').width(nzo.width).height(nzo.height);
            var wd = Math.abs(iwz - nzo.width);
            var hd = Math.abs(ihz - nzo.height);

            if (zv < 1){
                nx = (ixz+(wd/2));
                ny = (iyz+(hd/2));
                $('#posUserImg, #posUsrImgWrap').css({'left':nx+'px','top':ny+'px'});
            } else {
                nx = (ixz-(wd/2));
                ny = (iyz-(hd/2));
                $('#posUserImg, #posUsrImgWrap').css({'left':nx+'px','top':ny+'px'});
            }

            $('#wPos').val(nzo.width);
            $('#hPos').val(nzo.height);
            $('#xPos').val(($('#posUserImg').position().left+(orx*zv)));
            $('#yPos').val(($('#posUserImg').position().top+(ory*zv)));
            $('#zVal').val(ui.value);
            zc++;
            iz=1;
        },
        stop: function(){
            zx = 0;
            zoomed=true;
            rx=orx*zv;
            ry=ory*zv;
            rxz=ixz+rx;
            ryz=iyz+ry;
        }
    });

I think the problem lies within the rotate or scale end functions. I have a feeling it could be something to do with the scale value but I have tried so many different combinations to get this to work with no luck.

2

There are 2 answers

0
Glen Robson On BEST ANSWER

I found out how to do this after hours of testing and debugging. Turns out its quite a simple fix. The problem was that the draggable UI event returns a different top and left value to the rotation event. Not entirely sure how or why but it seems to work with the amended code within the draggable stop function. You can see the fixed version here.

var il,it;
// Drag Handler
$('#posUsrImgWrap').draggable({
    drag:function(event, ui){
        il = ui.position.left;
        it = ui.position.top;
        var iw = $(this).width();
        var ih = $(this).height();
        $('#posUserImg').css({'top':it+'px','left':il+'px'});
        dragged = true;
        zc = 0;
    },
    stop:function(){
        ixz=il;
        iyz=it;
    }
});
2
Gaurav Kalyan On

I have made some changes in your code by commenting some of your code. It seem to work and the bug is gone. Please give it a look. If you comment your code then I might be able to better solution of your problem. I have commented the following part:

if (zv < 1){
    nx = (ixz+(wd/2));
    ny = (iyz+(hd/2));
    $('#posUserImg, #posUsrImgWrap').css({'left':nx+'px','top':ny+'px'});
}
else{
    nx = (ixz-(wd/2));
    ny = (iyz-(hd/2));
    $('#posUserImg, #posUsrImgWrap').css({'left':nx+'px','top':ny+'px'});
}

Possibly, problem is caused mainly due to the reason when dragged=true & zc=0 you are setting ixz , iyz value twice.