Opened 9 years ago

Closed 9 years ago

Last modified 7 years ago

#5920 closed bug (notabug)

oversize draggable

Reported by: rotkiw Owned by:
Priority: minor Milestone: 1.9.0
Component: ui.draggable Version: 1.8.4
Keywords: Cc:
Blocked by: Blocking:

Description

If the draggable is bigger than the holder, the draggable is just snap to the edges of the holder.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>draggable test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js"></script>
<script type="text/javascript">
	$(document).ready(function() {
		$('#drag').draggable({
			containment: 'parent',
			//grid: [20, 20]
		});
	});
</script>
<style type="text/css">
#holder {
	width:200px;
	height: 200px;
	overflow:hidden;
	background-color:#CF0;
}
#drag {
	width:400px;
	height: 400px;
	overflow:hidden;
	background-color: #C00;
}
#content {
	width:390px;
	height:390px;
	margin: 5px;
	background-color:#09F;
}
</style>
</head>
<body>
<div id="holder">
  <div id="drag">
    <div id="content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur enim. Nullam id ligula in nisl tincidunt feugiat. Curabitur eu magna porttitor ligula bibendum rhoncus. Etiam dignissim. Duis lobortis porta risus. Quisque velit metus, dignissim in, rhoncus at, congue quis, mi. Praesent vel lorem. Suspendisse ut dolor at justo tristique dapibus. Morbi erat mi, rutrum a, aliquam nec, mattis semper, leo. Maecenas blandit risus vitae quam. Vivamus ut odio. Pellentesque mollis arcu nec metus. Nullam bibendum scelerisque turpis. Aliquam erat volutpat.</div>
  </div>
</div>
</body>
</html>

solution:

	_generatePosition: function(event) {

		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
		var pageX = event.pageX;
		var pageY = event.pageY;
		var flagX = false;
		var flagY = false;

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */
		
		if(this.originalPosition) { //If we are not dragging yet, we won't check for options
			
			if(this.containment) {
				if (((this.containment[2] < 0) && (this.offset.click.left - event.pageX < this.containment[0])) || ((this.containment[2] >= 0) && (event.pageX - this.offset.click.left < this.containment[0]))) {
					pageX = this.containment[0] + this.offset.click.left;
					flagX = true; // Prevent jump at oversized draggable element (cursor offset > dragabble width - holder width)
				}
				if (((this.containment[3] < 0) && (this.offset.click.top - event.pageY < this.containment[1])) || ((this.containment[3] >= 0) && (event.pageY - this.offset.click.top < this.containment[1]))) {
					pageY = this.containment[1] + this.offset.click.top;
					flagY = true;
				}
				if ((!flagX && (Math.abs(event.pageX - this.offset.click.left) > Math.abs(this.containment[2]))) || ((this.containment[2] >= 0) && (event.pageX - this.offset.click.left > this.containment[2]))) pageX = this.containment[2] + this.offset.click.left;
				if ((!flagY && (Math.abs(event.pageY - this.offset.click.top) > Math.abs(this.containment[3]))) || ((this.containment[3] >= 0) && (event.pageY - this.offset.click.top > this.containment[3]))) pageY = this.containment[3] + this.offset.click.top;
			}
			
			if(o.grid) {
				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
				pageY = this.containment ? (!(Math.abs(top - this.offset.click.top) < this.containment[1] || top - this.offset.click.top > Math.abs(this.containment[3])) ? top : (!(Math.abs(top - this.offset.click.top) < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
				pageX = this.containment ? (!(Math.abs(left - this.offset.click.left) < this.containment[0] || left - this.offset.click.left > Math.abs(this.containment[2])) ? left : (!(Math.abs(left - this.offset.click.left) < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
			}

		}
		
		return {
			top: (
				pageY																// The absolute mouse position
				- this.offset.click.top													// Click offset (relative to the element)
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
			),
			left: (
				pageX																// The absolute mouse position
				- this.offset.click.left												// Click offset (relative to the element)
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
				+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
			)
		};

	},

Attachments (1)

jquery.ui.draggable.js (29.5 KB) - added by rotkiw 9 years ago.
improved draggable

Download all attachments as: .zip

Change History (8)

Changed 9 years ago by rotkiw

Attachment: jquery.ui.draggable.js added

improved draggable

comment:1 Changed 9 years ago by Scott González

Resolution: invalid
Status: newclosed

Containing a draggable inside something that's smaller than the draggable itself doesn't make sense.

comment:2 Changed 9 years ago by krazedout

Hi there,

I don't agree with scott's comment - I'm currently encountering this problem as well where my draggable contents is larger than the container element. This happens because I'm creating something with a google maps effect where the user can drag a large div inside a smaller viewport.

I do hope that the jquery devs will consider opening this issue again because there are situations where the draggable element is larger than its parent container (E.g. with overflow:hidden). In the meantime, I'm currently using the Mapbox plugin to circumvent this issue.

Thanks!

comment:3 Changed 9 years ago by Seuldieu

I also disagree with Scott's shortsighted comment--one of the first practical uses that came to mind for draggable elements, was creating a click-and-drag window similar to google maps. Thanks Krazedout for the Mapbox reference, seeing as I will probably use that as well for now.

+1 for Jquery UI devs addressing this ticket in a future release...

Last edited 9 years ago by Seuldieu (previous) (diff)

comment:4 Changed 8 years ago by bart

I also disagree with Scott's comment. This seems like a big oversight for 'draggable'. If I have a place where I'm letting someone view a large image in a small area and I want them to be able to drag it around to see the whole image, then I need draggable to be able to support the dragging of a large element inside a small container.

It's the same situation if you open an image in Photoshop, make its window smaller than the image, then use the hand tool to drag the image inside that window. The image is contained within that window.

I think this would be solvable if instead of defining a container box, I would be defining min/max values for the top and left properties. Then I could say that the max left position is "0" (so that I would never be able to move the image towards the right past its left edge).

Last edited 8 years ago by bart (previous) (diff)

comment:5 Changed 8 years ago by janrenn

Containment smaller than draggable really doesn't make sense. You are talking about "viewport" smaller than draggable. Create helper "containment" block, give this block width = (2 * draggable_width – viewport_width), the same with height, and center this block relative to viewport. Then attach this helper block as "containment". It works OK for me.

However, simplifying setting "min" and "max" coordinates directly via Draggable API properties, not using containment as proxy should be nice.

Last edited 8 years ago by janrenn (previous) (diff)

comment:5 Changed 8 years ago by janrenn

Containment smaller than draggable really doesn't make sense. You are talking about "viewport" smaller than draggable. Create helper "containment" block, give this block width = (2 * draggable_width – viewport_width), the same with height and center this block relative to viewport. Then attach this helper block as "containment". It works OK for me.

However, simplifying setting "min" and "max" coordinates directly via Draggable API properties, not using containment as proxy should be nice.

comment:6 Changed 7 years ago by Scott González

Milestone: 1.next1.9.0
Note: See TracTickets for help on using tickets.