├── README.md ├── draggable_background.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Draggable Background 2 | 3 | A jQuery plugin to make background images draggable. 4 | 5 | **NOTE:** I don't plan to maintain this library anymore since I've moved on 6 | from jQuery. There seems to be requests for supporting different options 7 | for background-size or different units for background-position. After looking 8 | at the css spec for these properties, it seems unmaintainable to support every 9 | possible configuration, so I would encourage you to fork this and shape it to 10 | your specific needs. 11 | 12 | ## Configuration 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
OptionTypeKnown ValuesDefault ValueDescription
boundBooleantrue|falsetrueWhether dragging is bounded by the edges of the image.
axisStringx|yIf specified, restrict dragging along x or y axis.
doneFunctionCalled when dragging is stopped by mouseup, touchup, or mouseleave.
43 | 44 | ## Usage 45 | ```js 46 | // default options 47 | $('div').backgroundDraggable(); 48 | 49 | // only draggable in the x direction, and dragging is not bounded by the image 50 | $('div').backgroundDraggable({ bound: false, axis: 'x' }); 51 | 52 | // disable draggable background 53 | $('div').backgroundDraggable('disable'); 54 | 55 | // callback when drag complete 56 | $('div').backgroundDraggable({ 57 | done: function() { 58 | backgroundPosition = $('div').css('background-position'); 59 | console.log(backgroundPosition); 60 | } 61 | }); 62 | ``` 63 | 64 | ## Demo 65 | http://kentor.github.com/jquery-draggable-background/ 66 | 67 | ## Support 68 | IE9+. Only `background-size` value of `auto` (default) and `cover` are supported. `background-position` must be absolute pixels. There will be bugs if you use `center` for percentages. 69 | 70 | ## Changelog 71 | 72 | v1.2.3 [2014-10-17] 73 | - Fixed child elements of element with background dragging calling `preventDefault` (7f17318). 74 | - Improved behavior of dragging, especially when mouse up happens outside the window (d1fdbe4). 75 | 76 | v1.2.2 [2014-09-01] 77 | - Added support for a callback when dragging is finished. 78 | 79 | v1.2.1 [2014-08-01] 80 | - Added support for disabling plugin 81 | 82 | v1.2 [2014-06-06] 83 | - Refactored code to use semicolons. 84 | - Support for `background-size: cover`. 85 | 86 | v1.1 [2013-05-19] 87 | - Touch support. 88 | 89 | v1.0 [2012-09-23] 90 | 91 | - Initial release. 92 | 93 | ## License 94 | 95 | Copyright (c) 2014 Kenneth Chung 96 | 97 | Licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php) license. 98 | -------------------------------------------------------------------------------- /draggable_background.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Draggable Background plugin for jQuery 3 | * 4 | * v1.2.4 5 | * 6 | * Copyright (c) 2014 Kenneth Chung 7 | * 8 | * Licensed under the MIT license: 9 | * http://www.opensource.org/licenses/mit-license.php 10 | */ 11 | ;(function($) { 12 | var $window = $(window); 13 | 14 | // Helper function to guarantee a value between low and hi unless bool is false 15 | var limit = function(low, hi, value, bool) { 16 | if (arguments.length === 3 || bool) { 17 | if (value < low) return low; 18 | if (value > hi) return hi; 19 | } 20 | return value; 21 | }; 22 | 23 | // Adds clientX and clientY properties to the jQuery's event object from touch 24 | var modifyEventForTouch = function(e) { 25 | e.clientX = e.originalEvent.touches[0].clientX; 26 | e.clientY = e.originalEvent.touches[0].clientY; 27 | }; 28 | 29 | var getBackgroundImageDimensions = function($el) { 30 | var bgSrc = ($el.css('background-image').match(/^url\(['"]?(.*?)['"]?\)$/i) || [])[1]; 31 | if (!bgSrc) return; 32 | 33 | var imageDimensions = { width: 0, height: 0 }, 34 | image = new Image(); 35 | 36 | image.onload = function() { 37 | if ($el.css('background-size') == "cover") { 38 | var elementWidth = $el.innerWidth(), 39 | elementHeight = $el.innerHeight(), 40 | elementAspectRatio = elementWidth / elementHeight; 41 | imageAspectRatio = image.width / image.height, 42 | scale = 1; 43 | 44 | if (imageAspectRatio >= elementAspectRatio) { 45 | scale = elementHeight / image.height; 46 | } else { 47 | scale = elementWidth / image.width; 48 | } 49 | 50 | imageDimensions.width = image.width * scale; 51 | imageDimensions.height = image.height * scale; 52 | } else { 53 | imageDimensions.width = image.width; 54 | imageDimensions.height = image.height; 55 | } 56 | }; 57 | 58 | image.src = bgSrc; 59 | 60 | return imageDimensions; 61 | }; 62 | 63 | function Plugin(element, options) { 64 | this.element = element; 65 | this.options = options; 66 | this.init(); 67 | } 68 | 69 | Plugin.prototype.init = function() { 70 | var $el = $(this.element), 71 | bgSrc = ($el.css('background-image').match(/^url\(['"]?(.*?)['"]?\)$/i) || [])[1], 72 | options = this.options; 73 | 74 | if (!bgSrc) return; 75 | 76 | // Get the image's width and height if bound 77 | var imageDimensions = { width: 0, height: 0 }; 78 | if (options.bound) { 79 | imageDimensions = getBackgroundImageDimensions($el); 80 | } 81 | 82 | $el.on('mousedown.dbg touchstart.dbg', function(e) { 83 | if (e.target !== $el[0]) { 84 | return; 85 | } 86 | e.preventDefault(); 87 | 88 | if (e.originalEvent.touches) { 89 | modifyEventForTouch(e); 90 | } else if (e.which !== 1) { 91 | return; 92 | } 93 | 94 | var x0 = e.clientX, 95 | y0 = e.clientY, 96 | pos = $el.css('background-position').match(/(-?\d+).*?\s(-?\d+)/) || [], 97 | xPos = parseInt(pos[1]) || 0, 98 | yPos = parseInt(pos[2]) || 0; 99 | 100 | $window.on('mousemove.dbg touchmove.dbg', function(e) { 101 | e.preventDefault(); 102 | 103 | if (e.originalEvent.touches) { 104 | modifyEventForTouch(e); 105 | } 106 | 107 | var x = e.clientX, 108 | y = e.clientY; 109 | 110 | xPos = options.axis === 'y' ? xPos : limit($el.innerWidth()-imageDimensions.width, 0, xPos+x-x0, options.bound); 111 | yPos = options.axis === 'x' ? yPos : limit($el.innerHeight()-imageDimensions.height, 0, yPos+y-y0, options.bound); 112 | x0 = x; 113 | y0 = y; 114 | 115 | $el.css('background-position', xPos + 'px ' + yPos + 'px'); 116 | }); 117 | 118 | $window.on('mouseup.dbg touchend.dbg mouseleave.dbg', function() { 119 | if (options.done) { 120 | options.done(); 121 | } 122 | 123 | $window.off('mousemove.dbg touchmove.dbg'); 124 | $window.off('mouseup.dbg touchend.dbg mouseleave.dbg'); 125 | }); 126 | }); 127 | }; 128 | 129 | Plugin.prototype.disable = function() { 130 | var $el = $(this.element); 131 | $el.off('mousedown.dbg touchstart.dbg'); 132 | $window.off('mousemove.dbg touchmove.dbg mouseup.dbg touchend.dbg mouseleave.dbg'); 133 | } 134 | 135 | $.fn.backgroundDraggable = function(options) { 136 | var options = options; 137 | var args = Array.prototype.slice.call(arguments, 1); 138 | 139 | return this.each(function() { 140 | var $this = $(this); 141 | 142 | if (typeof options == 'undefined' || typeof options == 'object') { 143 | options = $.extend({}, $.fn.backgroundDraggable.defaults, options); 144 | var plugin = new Plugin(this, options); 145 | $this.data('dbg', plugin); 146 | } else if (typeof options == 'string' && $this.data('dbg')) { 147 | var plugin = $this.data('dbg'); 148 | Plugin.prototype[options].apply(plugin, args); 149 | } 150 | }); 151 | }; 152 | 153 | $.fn.backgroundDraggable.defaults = { 154 | bound: true, 155 | axis: undefined 156 | }; 157 | }(jQuery)); 158 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 24 | 25 | 26 |
default
27 |
bound: false
28 |

29 |
axis: 'x'
30 |
axis: 'y'
31 | 32 | 33 | --------------------------------------------------------------------------------