JQueryUI - draggable element gets dropped onto multiple droppable areas if the droppable areas are scaled down

StackOverflow https://stackoverflow.com/questions/19787104

سؤال

I am trying to drag and drop and element onto a droppable area. Let's say that I have multiple droppable areas with the same class and I have written a drop event handler for this class.

If I scale down my droppable areas using -webkit-transform:scale(0.3,0.3);, the drop event acts weird. The drop happens onto muliple droppable zones before the draggable element gets attached to one of the droppable areas.

I assume that this issue is because of using the scale but I don't have any idea how to fix it. Googling didn't help either.

I have set up a fiddle for DEMO.

Here is my code

THE SCRIPT

var click = {
    x: 0,
    y: 0
}; // used for recording mouse cords

$('document').ready(function(event){
    for(var i = 0 ; i <= 72 ; i++)
    {
        $('<div></div>').attr({'class':'drop_zone','id':'drop_'+i}).appendTo($('.main_container'));
    }
    $('.drop_zone').each(function(index,element){
        $(this).attr('id','drop_'+index);
    })
    $('.draggable').draggable();
    $('.draggable').on('dragstart',function(event,ui){
        $('#droppable_area_ids').html('');
        click.x = event.clientX;
        click.y = event.clientY;
    })
    $('.draggable').on('drag',function(event,ui){
        var zoom = 0.3;
        var original = ui.originalPosition;
        
        ui.position = {
            left: (event.clientX - click.x + original.left) / zoom,
            top:  (event.clientY - click.y + original.top ) / zoom
        };
    })
    $('.draggable').on('dragend',function(event,ui){
        click.x = 0;
        click.y = 0;
    })
    $('.drop_zone').droppable({
        tolerance: 'pointer',
        accept: ".draggable"
    });
    $('.drop_zone').on('drop',function(event,ui){
        console.log('dropped on ' + $(this).attr('id'));
        $('.draggable').css({'position':'absolute','top':'0px','left':'0px'}).appendTo($(this));
        $(this).parent().css('z-index',10);
        $('#droppable_area_ids').html($('#droppable_area_ids').html() + ' , ' + $(this).attr('id'));
    })
})

THE STYLE

*
{
    padding:0px;
    margin: 0px;
}
.main_container
{
    -webkit-transform: scale(0.3,0.3);
    width: 1000px;
    height: 1000px;
    background-color: #efefef;
    position: absolute;
    top: -200px;
    left: -220px;
}
.drop_zone
{
    background-color: #7e7e7e;
    width:100px;
    height:100px;
    position: relative;
    margin-left: 10px;
    margin-top: 10px;
    float: left;
}
.draggable
{
    background-color: #262626;
    width:100px;
    height: 200px;
    z-index: 100;
}
#droppable_area_ids
{
    position: absolute;
    top:100px;
    left:100px;
    width:100%;
    float:left;
}

THE HTML

<div class="main_container">
    <div class="draggable"></div> 
</div>
<div id="droppable_area_ids"></div>

Any help will be appreciated.

EDIT

This happens to be a KNOWN ISSUE WITH JQUERY and seems that they won't be fixing it in the near future. If anybody has done a workaround for this, it'll be of great help.

هل كانت مفيدة؟

المحلول

Found a workaround , posting it here just in case it helps anyone else.

I had to modify jquery-ui.js.

m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight};

to

m[i].proportions = { width: m[i].element[0].offsetWidth*scaleFactor, height: m[i].element[0].offsetHeight*scaleFactor };

where scaleFactor is initialized to 1 and is changed in your javascript code to the value of css-transform , i.e., If you use -webkit-transform:scale(0.3,0.3) , set the scaleFactor to 0.3 and bingo , you are done!

Updated fiddle using the changed jquery-ui.js file

http://jsfiddle.net/P4FMr/4/

نصائح أخرى

using the response from Harsha Venkatram and the comments in here I was finally able to fix this in an application I am working on. The application is based on WordPress and it uses a minified droppable.min.js included by Wordpress under wp-includes.

The application is an editor which has a zoom so its scalable and theres some drag and drop action of images in it. But when dragging images into certain zones it triggered multiple zones around it when being scaled down which messed up your work! And the application was built in a way that its always somewhat scaled down so it did not work well...

..So in the end I was able to apply the fix directly in the minified droppable code.

First in the scaling function, there was an x number representing the scaling so I initialized window.currentZoom in my javascript code and made the scaling function update the value of window.currentZoom to the scaling number everytime it runs, so my variable window.currentZoom always contains my scaling value, and since its a window. variable I know I can access it from anywhere.

So in wp-includes/js/jquery/ui/droppable.min.js I changed these:

from

this.proportions=function(){if(!arguments.length)return e||(e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight});

to

this.proportions=function(){if(!arguments.length)return e||(e={width:this.element[0].offsetWidth*window.currentZoom,height:this.element[0].offsetHeight*window.currentZoom});

from

o[i].proportions({width:o[i].element[0].offsetWidth,height:o[i].element[0].offsetHeight}))}}

to

o[i].proportions({width:o[i].element[0].offsetWidth*window.currentZoom,height:o[i].element[0].offsetHeight*window.currentZoom}))}}

And it fixed the bug with scaling and droppable omg!

I just thought maybe it could help someone else. Good luck!

Oh and probably I should copy this file in my theme, make sure WP update doesnt erase my change.

In the end copying this file in my theme never worked so instead I downloaded a fresh jquery-ui from jquery and put it in my theme. In there I found these lines which I modified. That worked too..

// Retrieve or derive the droppable's proportions
            return proportions ?
                proportions :
                proportions = {
                    width: this.element[ 0 ].offsetWidth*window.currentZoom,
                    height: this.element[ 0 ].offsetHeight*window.currentZoom
                };


// Activate the droppable if used directly from draggables
        if ( type === "mousedown" ) {
            m[ i ]._activate.call( m[ i ], event );
        }

        m[ i ].offset = m[ i ].element.offset();
        m[ i ].proportions( {
            width: m[ i ].element[ 0 ].offsetWidth*window.currentZoom,
            height: m[ i ].element[ 0 ].offsetHeight*window.currentZoom
        } );
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top