Created
November 7, 2013 22:10
-
-
Save JamesWP/7362729 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* jQuery Infinite Drag | |
* Version 0.2 | |
* Copyright (c) 2010 Ian Li (http://ianli.com) | |
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. | |
* | |
* Requires: | |
* jQuery http://jquery.com | |
* | |
* Reference: | |
* http://ianli.com/infinitedrag/ for Usage | |
* | |
* Versions: | |
* 0.2 | |
* - Fixed problem with IE 8.0 | |
* 0.1 | |
* - Initial implementation | |
*/ | |
(function($) { | |
/** | |
* Function to create InfiniteDrag object. | |
*/ | |
$.infinitedrag = function(draggable, draggable_options, tile_options) { | |
return new InfiniteDrag(draggable, draggable_options, tile_options); | |
}; | |
$.infinitedrag.VERSION = 0.1; | |
/** | |
* The InfiniteDrag object. | |
*/ | |
var InfiniteDrag = function(draggable, draggable_options, tile_options) { | |
// Use self to reduce confusion about this. | |
var self = this; | |
var $draggable = $(draggable); | |
var $viewport = $draggable.parent(); | |
$draggable.css({ | |
position: "relative", | |
cursor: "move" | |
}); | |
// Draggable options | |
var _do = (draggable_options) ? draggable_options : {}; | |
// Tile options (DEFAULT) | |
var _to = { | |
class_name: "_tile", | |
width: 100, | |
height: 100, | |
start_col: 0, | |
start_row: 0, | |
range_col: [-1000000, 1000000], | |
range_row: [-1000000, 1000000], | |
oncreate: function($element, i, j) { | |
$element.text(i + "," + j); | |
}, | |
onupdate: function($element, i, j) { | |
return; | |
} | |
}; | |
// Override tile options. | |
for (var i in tile_options) { | |
if (tile_options[i] !== undefined) { | |
_to[i] = tile_options[i]; | |
} | |
} | |
// Override tile options based on draggable options. | |
if (_do.axis == "x") { | |
_to.range_row = [_to.start_row, _to.start_row]; | |
} else if (_do.axis == "y") { | |
_to.range_col = [_to.start_col, _to.start_col]; | |
} | |
// Creates the tile at (i, j). | |
function create_tile(i, j) { | |
if (i < _to.range_col[0] || _to.range_col[1] < i) { | |
return; | |
} else if (j < _to.range_row[0] || _to.range_row[1] < j) { | |
return; | |
} | |
grid[i][j] = true; | |
var x = i * _to.width; | |
var y = j * _to.height; | |
var $e = $draggable.append('<div></div>'); | |
var $new_tile = $e.children(":last"); | |
$new_tile.attr({ | |
"class": _to.class_name, | |
col: i, | |
row: j | |
}).css({ | |
position: "absolute", | |
left: x, | |
top: y, | |
width: _to.width, | |
height: _to.height | |
}); | |
// add tile to grisEls for use in update | |
if(gridEls[i]===undefined) gridEls[i] = {}; | |
gridEls[i][j] = $new_tile; | |
_to.oncreate($new_tile, i, j); | |
} | |
// updates the tile at (i, j). | |
function update_tile(i, j) { | |
if(gridEls[i]===undefined || gridEls[i][j]===undefined) return; | |
else _to.onupdate(gridEls[i][j], i, j); | |
} | |
// Updates the containment box wherein the draggable can be dragged. | |
var update_containment = function() { | |
// Update viewport info. | |
viewport_width = $viewport.width(), | |
viewport_height = $viewport.height(), | |
viewport_cols = Math.ceil(viewport_width / _to.width), | |
viewport_rows = Math.ceil(viewport_height / _to.height); | |
// Create containment box. | |
var half_width = _to.width / 2, | |
half_height = _to.height / 2, | |
viewport_offset = $viewport.offset(), | |
viewport_draggable_width = viewport_width - _to.width, | |
viewport_draggable_height = viewport_height - _to.height; | |
var containment = [ | |
(-_to.range_col[1] * _to.width) + viewport_offset.left + viewport_draggable_width, | |
(-_to.range_row[1] * _to.height) + viewport_offset.top + viewport_draggable_height, | |
(-_to.range_col[0] * _to.width) + viewport_offset.left, | |
(-_to.range_row[0] * _to.height) + viewport_offset.top | |
]; | |
$draggable.draggable("option", "containment", containment); | |
}; | |
var past_visible_left_col = 0,past_visible_right_col = 0,past_visible_top_row = 0,past_visible_bottom_row = 0; | |
var update_tiles = function() { | |
var $this = $draggable; | |
var $parent = $this.parent(); | |
// Problem with .position() in Chrome/WebKit: | |
// var pos = $(this).position(); | |
// So, we compute it ourselves. | |
var pos = { | |
left: $this.offset().left - $parent.offset().left, | |
top: $this.offset().top - $parent.offset().top | |
}; | |
var visible_left_col = Math.ceil(-pos.left / _to.width) - 1, | |
visible_top_row = Math.ceil(-pos.top / _to.height) - 1; | |
var visible_right_col = Math.ceil((-pos.left+$parent.width()) / _to.width) - 1, | |
visible_bottom_row = Math.ceil((-pos.top+$parent.height()) / _to.height) - 1; | |
for (var i = visible_left_col; i <= visible_left_col + viewport_cols; i++) { | |
for (var j = visible_top_row; j <= visible_top_row + viewport_rows; j++) { | |
if (grid[i] === undefined) { | |
grid[i] = {}; | |
} else if (grid[i][j] === undefined) { | |
create_tile(i, j); | |
} | |
} | |
} | |
var affected = []; | |
// todo: compute if visible cols have changed and if so then update all new cols | |
if(past_visible_bottom_row < visible_bottom_row){ | |
for (var i = visible_left_col;i<=visible_right_col;i++){ | |
affected.push({'i':i,'j':visible_bottom_row}); | |
} | |
} | |
if(past_visible_right_col < visible_right_col){ | |
for (var j = visible_top_row;j<=visible_bottom_row;j++){ | |
affected.push({'i':visible_right_col,'j':j}); | |
} | |
} | |
if(past_visible_top_row > visible_top_row){ | |
for (var i = visible_left_col;i<=visible_right_col;i++){ | |
affected.push({'i':i,'j':visible_top_row}); | |
} | |
} | |
if(past_visible_left_col > visible_left_col){ | |
for (var j = visible_top_row;j<=visible_bottom_row;j++){ | |
affected.push({'i':visible_left_col,'j':j}); | |
} | |
} | |
for(var i = 0;i<affected.length;i++){ | |
update_tile(affected[i].i,affected[i].j); | |
} | |
//console.log({l:past_visible_left_col,t:past_visible_top_row,r:past_visible_right_col,b:past_visible_bottom_row,he:$parent.height(),wi:$parent.width()}); | |
// save prev values | |
past_visible_left_col = visible_left_col; | |
past_visible_right_col = visible_right_col; | |
past_visible_top_row = visible_top_row; | |
past_visible_bottom_row = visible_bottom_row; | |
}; | |
// Public Methods | |
//----------------- | |
self.draggable = function() { | |
return $draggable; | |
}; | |
self.disabled = function(value) { | |
if (value === undefined) { | |
return $draggable; | |
} | |
$draggable.draggable("option", "disabled", value); | |
$draggable.css({ cursor: (value) ? "default" : "move" }); | |
}; | |
self.center = function(col, row) { | |
var x = _to.width * col, | |
y = _to.height * row, | |
half_width = _to.width / 2, | |
half_height = _to.height / 2, | |
half_vw_width = $viewport.width() / 2, | |
half_vw_height = $viewport.height() / 2, | |
offset = $draggable.offset(); | |
var new_offset = { | |
left: -x - (half_width - half_vw_width), | |
top: -y - (half_height - half_vw_height) | |
}; | |
if (_do.axis == "x") { | |
new_offset.top = offset.top; | |
} else if (_do.axis == "y") { | |
new_offset.left = offset.left; | |
} | |
$draggable.offset(new_offset); | |
update_tiles(); | |
}; | |
// Setup | |
//-------- | |
var viewport_width = $viewport.width(), | |
viewport_height = $viewport.height(), | |
viewport_cols = Math.ceil(viewport_width / _to.width), | |
viewport_rows = Math.ceil(viewport_height / _to.height); | |
$draggable.offset({ | |
left: $viewport.offset().left - (_to.start_col * _to.width), | |
top: $viewport.offset().top - (_to.start_row * _to.height) | |
}); | |
var grid = {}; | |
var gridEls = {}; | |
for (var i = _to.start_col, m = _to.start_col + viewport_cols; i < m && (_to.range_col[0] <= i && i <= _to.range_col[1]); i++) { | |
grid[i] = {}; | |
for (var j = _to.start_row, n = _to.start_row + viewport_rows; j < n && (_to.range_row[0] <= j && j <= _to.range_row[1]); j++) { | |
create_tile(i, j); | |
} | |
} | |
// Handle resize of window. | |
$(window).resize(function() { | |
// HACK: | |
// Update the containment when the window is resized | |
// because the containment boundaries depend on the offset of the viewport. | |
update_containment(); | |
}); | |
// The drag event handler. | |
_do.drag = function(e, ui) { | |
update_tiles(); | |
}; | |
$draggable.draggable(_do); | |
update_containment(); | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment