I've tried using jquery's built in draggable and I've tried using custom drag functions with no avail. Both have their respected issues and I will try to highlight both of them.
Basically, I am trying to allow the dragging of an element that is on a scaled div container. The following methods work okay on a scaled element that is less than around 2
. But if you go any higher than that, we see some issues.
Any help would be appreciated. Thank you for your time.
HTML
<div id="container">
<div id="dragme">Hi</div>
</div>
Method 1 (Jquery draggable function)
I've tried the jquery draggable function as you can see in this jsfiddle example.
The problems I found in this example are the following:
- Biggest concern: The droppable container does not change when it is scaled up. So if the element is being dragged over part of the scaled container that isn't a part of it's original size, it will fail.
- When you click to drag a div, it teleports a little bit away from the mouse and is not a seamless drag.
JS
var percent = 2.5;
$("#dragme").draggable({
zIndex: 3000,
appendTo: 'body',
helper: function (e, ui) {
var draggable_element = $(this),
width = draggable_element.css('width'),
height = draggable_element.css('height'),
text = draggable_element.text(),
fontsize = draggable_element.css('font-size'),
textalign = draggable_element.css('font-size');
return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
'position': 'absolute',
'text-align': textalign,
'background-color': "red",
'font-size': fontsize,
'line-height': height,
'width': width,
'height': height,
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
},
start: function (e, ui) {
$(this).hide();
},
stop: function (e, ui) {
$(this).show();
}
});
$("#container").droppable({
drop: function (event, ui) {
var formBg = $(this),
x = ui.offset.left,
y = ui.offset.top,
drag_type = ui.draggable.attr('id');
var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;
$(ui.draggable).css({
'top': element_top,
'left': element_left
});
}
});
Method 2 - Custom drag function
I've tried using a custom drag function but it unusable after around a 2
scale.
- jsfiddle on a
scale(2)
- Looks like the draggable div is having a seizure. - jsfiddle on a
scale(2.5)
- The draggable div flys away when you try to drag it.
JS
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $parent = this;
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
$(this).addClass('active-handle')
var $drag = $parent.addClass('draggable');
}
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
follow = function (e) {
$drag.offset({
top: e.pageY + pos_y - drg_h,
left: e.pageX + pos_x - drg_w
})
};
$(window).on("mousemove", follow).on("mouseup", function () {
$drag.removeClass('draggable');
$(window).off("mousemove", follow);
});
e.preventDefault(); // disable selection
}).on("mouseup", function () {
if (opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle');
$parent.removeClass('draggable');
}
});
}
})(jQuery);
$("#dragme").drags({}, function (e) {});
I've tried using jquery's built in draggable and I've tried using custom drag functions with no avail. Both have their respected issues and I will try to highlight both of them.
Basically, I am trying to allow the dragging of an element that is on a scaled div container. The following methods work okay on a scaled element that is less than around 2
. But if you go any higher than that, we see some issues.
Any help would be appreciated. Thank you for your time.
HTML
<div id="container">
<div id="dragme">Hi</div>
</div>
Method 1 (Jquery draggable function)
I've tried the jquery draggable function as you can see in this jsfiddle example.
The problems I found in this example are the following:
- Biggest concern: The droppable container does not change when it is scaled up. So if the element is being dragged over part of the scaled container that isn't a part of it's original size, it will fail.
- When you click to drag a div, it teleports a little bit away from the mouse and is not a seamless drag.
JS
var percent = 2.5;
$("#dragme").draggable({
zIndex: 3000,
appendTo: 'body',
helper: function (e, ui) {
var draggable_element = $(this),
width = draggable_element.css('width'),
height = draggable_element.css('height'),
text = draggable_element.text(),
fontsize = draggable_element.css('font-size'),
textalign = draggable_element.css('font-size');
return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
'position': 'absolute',
'text-align': textalign,
'background-color': "red",
'font-size': fontsize,
'line-height': height,
'width': width,
'height': height,
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
},
start: function (e, ui) {
$(this).hide();
},
stop: function (e, ui) {
$(this).show();
}
});
$("#container").droppable({
drop: function (event, ui) {
var formBg = $(this),
x = ui.offset.left,
y = ui.offset.top,
drag_type = ui.draggable.attr('id');
var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;
$(ui.draggable).css({
'top': element_top,
'left': element_left
});
}
});
Method 2 - Custom drag function
I've tried using a custom drag function but it unusable after around a 2
scale.
- jsfiddle on a
scale(2)
- Looks like the draggable div is having a seizure. - jsfiddle on a
scale(2.5)
- The draggable div flys away when you try to drag it.
JS
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $parent = this;
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
$(this).addClass('active-handle')
var $drag = $parent.addClass('draggable');
}
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
follow = function (e) {
$drag.offset({
top: e.pageY + pos_y - drg_h,
left: e.pageX + pos_x - drg_w
})
};
$(window).on("mousemove", follow).on("mouseup", function () {
$drag.removeClass('draggable');
$(window).off("mousemove", follow);
});
e.preventDefault(); // disable selection
}).on("mouseup", function () {
if (opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle');
$parent.removeClass('draggable');
}
});
}
})(jQuery);
$("#dragme").drags({}, function (e) {});
Share
Improve this question
edited Mar 8, 2015 at 6:42
bryan
asked Mar 3, 2015 at 0:21
bryanbryan
9,39918 gold badges91 silver badges174 bronze badges
4
- are you trying to make a custom drag function? jquery-ui already has a draggable function. – Da Rod Commented Mar 3, 2015 at 0:51
- i tested your code with a few scaled entries. it seems like once it hits around 1.75 it starts to flicker and jump like you suggest. anything below that seems to drag just fine. – Da Rod Commented Mar 3, 2015 at 2:15
- i took the liberty of updating your jsfiddle as well so that you can track the position and size. i'll try a few more things but i think this may be a browser related issue. – Da Rod Commented Mar 3, 2015 at 2:17
- check this answer stackoverflow./questions/19787104/… – Nishit Maheta Commented Mar 11, 2015 at 12:48
3 Answers
Reset to default 6 +100Here are a few of my findings to make sure dragging on a scaled container works for method one. The only caveat is to make sure you have var percent
as the scaled percentage declared before any of these actions happen.
First, use this code at the top of your javascript. This wil help making sure that the droppable area works with a sacled container.
$.ui.ddmanager.prepareOffsets = function( t, event ) { var i, j, m = $.ui.ddmanager.droppables[ t.options.scope ] || [], type = event ? event.type : null, list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); droppablesLoop: for ( i = 0; i < m.length; i++ ) { if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { continue; } for ( j = 0; j < list.length; j++ ) { if ( list[ j ] === m[ i ].element[ 0 ] ) { m[ i ].proportions().height = 0; continue droppablesLoop; } } m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; if ( !m[ i ].visible ) { continue; } 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 * percent, height: m[ i ].element[ 0 ].offsetHeight * percent }); } };
Here are a few functions that are necessary to fix the drag so it works on a scaled container.
function dragFix(event, ui) { var changeLeft = ui.position.left - ui.originalPosition.left, newLeft = ui.originalPosition.left + changeLeft / percent, changeTop = ui.position.top - ui.originalPosition.top, newTop = ui.originalPosition.top + changeTop / percent; ui.position.left = newLeft; ui.position.top = newTop; }
function startFix(event, ui) { ui.position.left = 0; ui.position.top = 0; var element = $(this); }
You will want this if you want to enable the element to be resizable on a scaled container.
function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent; ui.size.width = newWidth; ui.size.height = newHeight; }
To make an element draggable, I use the following function.
$("ELEMENT").resizable({ minWidth: - ($(this).width()) * 10, minHeight: - ($(this).height()) * 10, resize: resizeFix, start: startFix });
$("ELEMENT").draggable({ cursor: "move", start: startFix, drag: dragFix }); }
A similar problem is mentioned here: jquery - css "transform:scale" affects '.offset()' of jquery
It seems the problem arises from the fact that jQuery fails to return exact size for scaled elements and therefore failing setting right offset values to the element.
To solve this, he is suggesting first setting scale to 1 and setting offset and then again resetting scale value.
But this alone does not solve the problem here. Since mouse position is taken while it is scaled, position values should also be divided by scale value.
Here is an edited version of code:
var scl = 2.5;
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top/scl + drg_h - e.pageY/scl,
pos_x = $drag.offset().left/scl + drg_w - e.pageX/scl;
follow = function(e) {
var size = {
top:e.pageY/scl + pos_y - drg_h+scl*2,
left:e.pageX/scl + pos_x - drg_w+scl*2
};
$drag.parent().css("transform","scale(1)");
$drag.offset(size);
$drag.parent().css("transform","scale("+scl+")");
};
Note: I only replaced scale value for transform
tag, since I am using chrome. You can also replace all instances or instead you can use a different class with 1 scale value.
JSFiddle is also here.
Here is an example of simple drag with scaling, however, in prue dom.
<style>
#dragme {
position:absolute;
border:1px solid red;
background:pink;
left:10px;
top:20px;
width:100px;
height:200px;
}
#container {
transform: scale(2,2) translate(100px,100px);
position:relative;
border:1px solid green;
background:grey;
width:200px;
height:300px;
}
</style>
<body>
<div id="container">
<div id="dragme">Hi</div>
</div>
<script>
var dragme=document.getElementById("dragme");
var container=document.getElementById("container");
dragme.onmousedown=function Drag(e){
this.ini_X = this.offsetLeft-e.clientX/2;
this.ini_Y = this.offsetTop-e.clientY/2;
container.onmousemove = move;
container.onmouseup = release;
return false;
}
function move(e){
e.target.style.left = e.clientX/2 + e.target.ini_X + 'px';
e.target.style.top = e.clientY/2 + e.target.ini_Y + 'px';
}
function release(){
container.onmousemove=container.onmouseup=null;
}
</script>
</body>