Reputation: 71
I create a container with two small child divs. I make the container and child divs draggable. The child divs drag as expected. The outer container drags as expected when the zoom ratio is 1.0 but when zoomed in, the drag operations jump when the container is first moved. There are some other related questions and possible answers but those I've tried only fix issues with the child containers not the parent container.
In particular, I've tried all of the suggestions here: jQuery Drag/Resize with CSS Transform Scale
And I reviewed this: jQuery UI Draggable jumps at the first drag which has no useful answer.
jsfiddle here: http://jsfiddle.net/nigelt/w521gv0j/5/
HTML:
<!-- Create an area where we will allow items to be moved -->
<div id=mycontainer>Press '+' to zoom in, '-' to zoom out, 'r' to reset.
<br>This pane is draggable
<!-- create a couple of boxes -->
<div class="mybox" id="source">Draggable</div>
<div class="mybox" id="dest">Draggable</div>
</div>
CSS:
#mycontainer {
width: 600px;
height: 400px;
background: #ddd;
position: absolute;
top: 0;
left: 0;
float: none;
border: solid 1px;
}
.mybox {
position: absolute;
background: #fff;
border: 1px solid;
border-radius: 6px;
width: 100px;
height: 75px;
float: none;
text-align: center;
}
#source {
top: 50px;
left: 100px;
}
#dest {
top: 100px;
left: 250px;
}
body {
margin: 0px;
/* force mycontainer to edge */
overflow: hidden;
/* no scrolling of body area. Clip the contents if moved */
}
javascript:
// global to set the zoomscale
zoomScale = 1;
// Set the zoom scale
var setZoomScale = function (zoom) {
zoomScale = zoom;
var container = $("#mycontainer");
var scaleval = 'scale(' + zoom + ',' + zoom + ')';
container.css('-ms-transform', scaleval);
container.css('-webkit-transform', scaleval);
container.css('transform', scaleval);
}
// Make the boxes draggable
// apply the stackoverflow fix
$("#source, #dest").draggable({
start: function (event, ui) {
ui.position.left = 0;
ui.position.top = 0;
},
drag: function (event, ui) {
// drag handle fix
var changeLeft = ui.position.left - ui.originalPosition.left; // find change in left
var newLeft = ui.originalPosition.left + changeLeft / ((zoomScale)); // adjust new left by our zoomScale
var changeTop = ui.position.top - ui.originalPosition.top; // find change in top
var newTop = ui.originalPosition.top + changeTop / zoomScale; // adjust new top by our zoomScale
ui.position.left = newLeft;
ui.position.top = newTop;
}
});
// make the virtual window draggable
// apply the stackoverflow fix
$("#mycontainer").draggable({
start: function (event, ui) {
ui.position.left = 0;
ui.position.top = 0;
},
drag: function (event, ui) {
// drag handle fix
var changeLeft = ui.position.left - ui.originalPosition.left; // find change in left
var newLeft = ui.originalPosition.left + changeLeft / ((zoomScale)); // adjust new left by our zoomScale
var changeTop = ui.position.top - ui.originalPosition.top; // find change in top
var newTop = ui.originalPosition.top + changeTop / zoomScale; // adjust new top by our zoomScale
ui.position.left = newLeft;
ui.position.top = newTop;
},
stop: function (event, ui) {}
});
// add a keypress handler so we can change the zoom
$(document).keypress(function (ev) {
var key = String.fromCharCode(ev.charCode);
if (key == '+') {
setZoomScale(zoomScale *= 1.5);
} else if (key == '-') {
setZoomScale(zoomScale /= 1.5);
} else if (key == 'r') {
// reset
setZoomScale(1.0);
$("#mycontainer").css({
"top": 0,
"left": 0
});
}
});
setZoomScale(1.5);
In the fiddle, the zoom ratio is initially set to 1.5. To reset it to 1.0, set focus to the demo window and press 'r'. After that the container drag works correctly
Upvotes: 0
Views: 2733
Reputation: 99
This was my solution:
var highestTopHeight = 10;
var leftestLeftWidth = 10;
function resizeFix(event, ui) {
let curWidth = ui.position.left + ui.size.width;
if (curWidth > ui.element.parent().width() || curWidth === ui.element.parent().width()) {
ui.size.width = ui.element.parent().width() - ui.position.left;
}
let curHeight = ui.position.top + ui.size.height;
if (curHeight > ui.element.parent().height() || curWidth === ui.element.parent().height()) {
ui.size.height = ui.element.parent().height() - ui.position.top;
}
if (ui.position.top >= 0)
highestTopHeight = ui.size.height;
if (ui.position.top < 0) {
ui.position.top = 0;
ui.size.height = highestTopHeight;
}
if (ui.position.left >= 0)
leftestLeftWidth = ui.size.width;
if (ui.position.left < 0) {
ui.position.left = 0;
ui.size.width = leftestLeftWidth;
}
}
Apply that to the resize of the resizable:
$('#yourID').resizable({ ... resize: resizeFix, ... })
resize: resizeFix,
Upvotes: 0
Reputation: 71
Well, in the end it took more time to create the fiddle and write up the question than to find the answer. This post: Jquery draggable with zoom problem fixed my problem perfectly.
Modified code for my fiddle:
var pointerX;
var pointerY;
$("#mycontainer").draggable({
start: function(evt, ui) {
pointerY = (evt.pageY - $('body').offset().top) / zoomScale - parseInt($(evt.target).css('top'));
pointerX = (evt.pageX - $('body').offset().left) / zoomScale - parseInt($(evt.target).css('left'));
//console.log('pointer: ' + pointerX + ',' + pointerY);
},
drag: function(evt,ui) {
var canvasTop = $('body').offset().top;
var canvasLeft = $('body').offset().left;
var canvasHeight = $('body').height();
var canvasWidth = $('body').width();
//console.log('canvas: ' + canvasLeft + ',' + canvasTop + ' ' + canvasWidth + 'x' + canvasHeight);
// Fix for zoom
ui.position.top = Math.round((evt.pageY - canvasTop) / zoomScale - pointerY);
ui.position.left = Math.round((evt.pageX - canvasLeft) / zoomScale - pointerX);
// Check if element is outside canvas
if (ui.position.left < 0) ui.position.left = 0;
//if (ui.position.left + $(this).width() > canvasWidth) ui.position.left = canvasWidth - $(this).width();
if (ui.position.top < 0) ui.position.top = 0;
//if (ui.position.top + $(this).height() > canvasHeight) ui.position.top = canvasHeight - $(this).height();
// Finally, make sure offset aligns with position
ui.offset.top = Math.round(ui.position.top + canvasTop);
ui.offset.left = Math.round(ui.position.left + canvasLeft);
},
stop: function(event, ui) {
}
});
Upvotes: 2