├── 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 | Option |
16 | Type |
17 | Known Values |
18 | Default Value |
19 | Description |
20 |
21 |
22 | bound |
23 | Boolean |
24 | true|false |
25 | true |
26 | Whether dragging is bounded by the edges of the image. |
27 |
28 |
29 | axis |
30 | String |
31 | x|y |
32 | |
33 | If specified, restrict dragging along x or y axis. |
34 |
35 |
36 | done |
37 | Function |
38 | |
39 | |
40 | Called when dragging is stopped by mouseup, touchup, or mouseleave. |
41 |
42 |
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 |
--------------------------------------------------------------------------------