imgViewer-rails 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bdad703484d766bbc86075a32b2796d527b663b2
4
+ data.tar.gz: 6f4730482aeb1b8bd31dfab4df43bd09707cd5e6
5
+ SHA512:
6
+ metadata.gz: 3fe599a3bc0c28d1f3cc078b323dc2f41d53dad2f662ef9fe89c4467512e2e9420427a6ba3383123e1e31756262142dca57591957bc551c82055e46c551e2693
7
+ data.tar.gz: 44e37b6671e66222d07395ed63d923ebffc26887bf76671019e56b60262be5ea7081257682fc3f012e3e2a1b5dd810043f84d725179db81e0d3fbb033365ae1f
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Wayne Mogg (https://github.com/waynegm)
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ imgViewer-Rails [![Gem Version][version-badge]][rubygems]
2
+ ===================
3
+
4
+ [imgViewer](https://github.com/waynegm/imgViewer), jQuery plugin to zoom and pan images rails wrap.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'imgViewer-rails'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ ## How to use
17
+
18
+ Add to your JavaScript manifest file (application.js):
19
+
20
+ ```js
21
+ //= require hammer
22
+ //= require jquery.hammer
23
+ //= require jquery.mousewheel
24
+ //= require imgViewer
25
+ ```
26
+
27
+ Visit [official doc](https://github.com/waynegm/imgViewer#documentation)
28
+
29
+ [version-badge]: https://badge.fury.io/rb/imgViewer-rails.svg
30
+ [rubygems]: https://rubygems.org/gems/imgViewer-rails
@@ -0,0 +1,12 @@
1
+ require 'imgViewer-rails/version'
2
+ require 'hammerjs-rails'
3
+ require 'jquery_mousewheel_rails'
4
+
5
+ module Jquery
6
+ module ImgViewer
7
+ module Rails
8
+ class Engine < ::Rails::Engine
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module Jquery
2
+ module ImgViewer
3
+ VERSION = '0.9.1'.freeze
4
+ end
5
+ end
@@ -0,0 +1,519 @@
1
+ /*! jQuery imgViewer - v0.9.1 - 2016-12-31
2
+ * https://github.com/waynegm/imgViewer
3
+ * Copyright (c) 2016 Wayne Mogg; Licensed MIT */
4
+ /*
5
+ * imgViewer plugin starts here
6
+ */
7
+ ;(function($) {
8
+ $.widget("wgm.imgViewer", {
9
+ options: {
10
+ zoomStep: 0.1,
11
+ zoom: 1,
12
+ zoomMax: 0,
13
+ zoomable: true,
14
+ dragable: true,
15
+ onClick: null,
16
+ onUpdate: null
17
+ },
18
+
19
+ _create: function() {
20
+ var self = this;
21
+ if (!this.element.is("img")) {
22
+ $.error('imgviewer plugin can only be applied to img elements');
23
+ }
24
+ // the original img element
25
+ self.img = self.element[0];
26
+ var $img = $(self.img);
27
+ /*
28
+ * a copy of the original image to be positioned over it and manipulated to
29
+ * provide zoom and pan
30
+ */
31
+ self.zimg = $("<img/>", {"src": self.img.src}).appendTo("body").wrap("<div class='viewport'/>");
32
+ var $zimg = $(self.zimg);
33
+ // the container or viewport for the image view
34
+ self.view = $(self.zimg).parent();
35
+ var $view = $(self.view);
36
+ // the pixel coordinate of the original image at the center of the viewport
37
+ self.vCenter = {};
38
+ // a flag used to decide if a mouse click is part of a drag or a proper click
39
+ self.drag = false;
40
+ self.pinch = false;
41
+ // a flag used to check the target image has loaded
42
+ self.ready = false;
43
+ $img.one("load",function() {
44
+ // get and some geometry information about the image
45
+ self.ready = true;
46
+ var width = $img.width(),
47
+ height = $img.height(),
48
+ offset = $img.offset();
49
+ // cache the image padding information
50
+ self.offsetPadding = {
51
+ top: parseInt($img.css('padding-top'),10),
52
+ left: parseInt($img.css('padding-left'),10),
53
+ right: parseInt($img.css('padding-right'),10),
54
+ bottom: parseInt($img.css('padding-bottom'),10)
55
+ };
56
+ /*
57
+ * cache the image margin/border size information
58
+ * because of IE8 limitations left and right borders are assumed to be the same width
59
+ * and likewise top and bottom borders
60
+ */
61
+ self.offsetBorder = {
62
+ x: Math.round(($img.outerWidth()-$img.innerWidth())/2),
63
+ y: Math.round(($img.outerHeight()-$img.innerHeight())/2)
64
+ };
65
+ /*
66
+ * define the css style for the view container using absolute positioning to
67
+ * put it directly over the original image
68
+ */
69
+ var vTop = offset.top + self.offsetBorder.y + self.offsetPadding.top,
70
+ vLeft = offset.left + self.offsetBorder.x + self.offsetPadding.left;
71
+
72
+ $view.css({
73
+ position: "absolute",
74
+ overflow: "hidden",
75
+ top: vTop+"px",
76
+ left: vLeft+"px",
77
+ width: width+"px",
78
+ height: height+"px"
79
+ });
80
+ // the zoom and pan image is position relative to the view container
81
+ $zimg.css({
82
+ position: "relative",
83
+ top: 0+"px",
84
+ left: 0+"px",
85
+ width: width+"px",
86
+ height: height+"px",
87
+ "-webkit-tap-highlight-color": "transparent"
88
+ });
89
+ // the initial view is centered at the orignal image
90
+ self.vCenter = {
91
+ x: width/2,
92
+ y: height/2
93
+ };
94
+ self.update();
95
+ }).each(function() {
96
+ if (this.complete) { $(this).load(); }
97
+ });
98
+ /*
99
+ * Render loop code during dragging and scaling using requestAnimationFrame
100
+ */
101
+ self.render = false;
102
+ /*
103
+ * Event handlers
104
+ */
105
+ $zimg.hammer();
106
+
107
+ if (self.options.zoomable) {
108
+ self._bind_zoom_events();
109
+ }
110
+ if (self.options.dragable) {
111
+ self._bind_drag_events();
112
+ }
113
+ $zimg.on("tap", function(ev) {
114
+ ev.preventDefault();
115
+ if (!self.dragging) {
116
+ ev.pageX = ev.gesture.center.x + window.scrollX;
117
+ ev.pageY = ev.gesture.center.y + window.scrollY;
118
+ self._trigger("onClick", ev, self);
119
+ }
120
+ });
121
+ /*
122
+ * Window resize handler
123
+ */
124
+
125
+ $(window).resize(function() {
126
+ /*
127
+ * the aim is to keep the view centered on the same location in the original image
128
+ */
129
+ if (self.ready) {
130
+ self.vCenter.x *=$img.width()/$view.width();
131
+ self.vCenter.y *= $img.height()/$view.height();
132
+ self.update();
133
+ }
134
+ });
135
+ },
136
+ /*
137
+ * Bind events
138
+ */
139
+ _bind_zoom_events: function() {
140
+ var self = this;
141
+ var $zimg = $(self.zimg);
142
+
143
+ function startRenderLoop() {
144
+ if (!self.render) {
145
+ self.render = true;
146
+ doRender();
147
+ }
148
+ }
149
+ function stopRenderLoop() {
150
+ self.render = false;
151
+ }
152
+ function doRender() {
153
+ if (self.render) {
154
+ window.requestAnimationFrame(doRender);
155
+ self.update();
156
+ }
157
+ }
158
+
159
+ $zimg.on("mousewheel", function(ev) {
160
+ ev.preventDefault();
161
+ var delta = ev.deltaY ;
162
+ self.options.zoom -= delta * self.options.zoomStep;
163
+ self.update();
164
+ });
165
+
166
+ $zimg.data("hammer").recognizers[1].options.enable = true;
167
+
168
+ $zimg.on("pinchstart", function() {
169
+ });
170
+
171
+ $zimg.on("pinch", function(ev) {
172
+ ev.preventDefault();
173
+ if (!self.pinch) {
174
+ self.pinchstart = { x: ev.gesture.center.x + window.scrollX, y: ev.gesture.center.y + window.scrollY};
175
+ self.pinchstartrelpos = self.cursorToImg(self.pinchstart.x, self.pinchstart.y);
176
+ self.pinchstart_scale = self.options.zoom;
177
+ startRenderLoop();
178
+ self.pinch = true;
179
+ } else {
180
+ self.options.zoom = ev.gesture.scale * self.pinchstart_scale;
181
+ var npos = self.imgToCursor( self.pinchstartrelpos.x, self.pinchstartrelpos.y);
182
+ self.vCenter.x = self.vCenter.x + (npos.x - self.pinchstart.x)/self.options.zoom;
183
+ self.vCenter.y = self.vCenter.y + (npos.y - self.pinchstart.y)/self.options.zoom;
184
+ }
185
+ });
186
+
187
+ $zimg.on("pinchend", function(ev) {
188
+ ev.preventDefault();
189
+ if (self.pinch) {
190
+ stopRenderLoop();
191
+ self.update();
192
+ self.pinch = false;
193
+ }
194
+ });
195
+ },
196
+
197
+ _bind_drag_events: function() {
198
+ var self = this;
199
+ var $zimg = $(self.zimg);
200
+ function startRenderLoop() {
201
+ if (!self.render) {
202
+ self.render = true;
203
+ doRender();
204
+ }
205
+ }
206
+ function stopRenderLoop() {
207
+ self.render = false;
208
+ }
209
+ function doRender() {
210
+ if (self.render) {
211
+ window.requestAnimationFrame(doRender);
212
+ self.update();
213
+ }
214
+ }
215
+ $zimg.on("pan", function(ev) {
216
+ ev.preventDefault();
217
+ if (!self.drag) {
218
+ self.drag = true;
219
+ self.dragXorg = self.vCenter.x;
220
+ self.dragYorg = self.vCenter.y;
221
+ startRenderLoop();
222
+ } else {
223
+ self.vCenter.x = self.dragXorg - ev.gesture.deltaX/self.options.zoom;
224
+ self.vCenter.y = self.dragYorg - ev.gesture.deltaY/self.options.zoom;
225
+ }
226
+ });
227
+
228
+ $zimg.on( "panend", function(ev) {
229
+ ev.preventDefault();
230
+ if (self.drag) {
231
+ self.drag = false;
232
+ stopRenderLoop();
233
+ self.update();
234
+ }
235
+ });
236
+ },
237
+ /*
238
+ * Unbind events
239
+ */
240
+ _unbind_zoom_events: function() {
241
+ var self = this;
242
+ var $zimg = $(self.zimg);
243
+ $zimg.data("hammer").recognizers[1].options.enable = false;
244
+ $zimg.off("mousewheel");
245
+ $zimg.off("pinchstart");
246
+ $zimg.off("pinch");
247
+ $zimg.off("pinchend");
248
+ },
249
+
250
+ _unbind_drag_events: function() {
251
+ var self = this;
252
+ var $zimg = $(self.zimg);
253
+ $zimg.off("pan");
254
+ $zimg.off("panend");
255
+ },
256
+
257
+ /*
258
+ * Remove the plugin
259
+ */
260
+ destroy: function() {
261
+ var $zimg = $(this.zimg);
262
+ $zimg.unbind("click");
263
+ $(window).unbind("resize");
264
+ $zimg.remove();
265
+ $(this.view).remove();
266
+ $.Widget.prototype.destroy.call(this);
267
+ },
268
+
269
+ _setOption: function(key, value) {
270
+ switch(key) {
271
+ case 'zoom':
272
+ if (parseFloat(value) < 1 || isNaN(parseFloat(value))) {
273
+ return;
274
+ }
275
+ break;
276
+ case 'zoomStep':
277
+ if (parseFloat(value) <= 0 || isNaN(parseFloat(value))) {
278
+ return;
279
+ }
280
+ break;
281
+ case 'zoomMax':
282
+ if (parseFloat(value) < 0 || isNaN(parseFloat(value))) {
283
+ return;
284
+ }
285
+ break;
286
+ }
287
+ var version = $.ui.version.split('.');
288
+ if (version[0] > 1 || version[1] > 8) {
289
+ this._super(key, value);
290
+ } else {
291
+ $.Widget.prototype._setOption.apply(this, arguments);
292
+ }
293
+ switch(key) {
294
+ case 'zoom':
295
+ if (this.ready) {
296
+ this.update();
297
+ }
298
+ break;
299
+ case 'zoomable':
300
+ if (this.options.zoomable) {
301
+ this._bind_zoom_events();
302
+ } else {
303
+ this._unbind_zoom_events();
304
+ }
305
+ break;
306
+ case 'dragable':
307
+ if (this.options.dragable) {
308
+ this._bind_drag_events();
309
+ } else {
310
+ this._unbind_drag_events();
311
+ }
312
+ break;
313
+ }
314
+ },
315
+
316
+ addElem: function(elem) {
317
+ $(this.view).append(elem);
318
+ },
319
+ /*
320
+ * Test if a relative image coordinate is visible in the current view
321
+ */
322
+ isVisible: function(relx, rely) {
323
+ var view = this.getView();
324
+ if (view) {
325
+ return (relx >= view.left && relx <= view.right && rely >= view.top && rely <= view.bottom);
326
+ } else {
327
+ return false;
328
+ }
329
+ },
330
+ /*
331
+ * Get relative image coordinates of current view
332
+ */
333
+ getView: function() {
334
+ if (this.ready) {
335
+ var $img = $(this.img),
336
+ width = $img.width(),
337
+ height = $img.height(),
338
+ zoom = this.options.zoom;
339
+ return {
340
+ top: this.vCenter.y/height - 0.5/zoom,
341
+ left: this.vCenter.x/width - 0.5/zoom,
342
+ bottom: this.vCenter.y/height + 0.5/zoom,
343
+ right: this.vCenter.x/width + 0.5/zoom
344
+ };
345
+ } else {
346
+ return null;
347
+ }
348
+ },
349
+ /*
350
+ * Pan the view to be centred at the given relative image location
351
+ */
352
+ panTo: function(relx, rely) {
353
+ if ( this.ready && relx >= 0 && relx <= 1 && rely >= 0 && rely <=1 ) {
354
+ var $img = $(this.img),
355
+ width = $img.width(),
356
+ height = $img.height();
357
+ this.vCenter.x = relx * width;
358
+ this.vCenter.y = rely * height;
359
+ this.update();
360
+ return { x: this.vCenter.x/width, y: this.vCenter.y/height };
361
+ } else {
362
+ return null;
363
+ }
364
+ },
365
+ /*
366
+ * Convert a relative image location to a viewport pixel location
367
+ */
368
+ imgToView: function(relx, rely) {
369
+ if ( this.ready && relx >= 0 && relx <= 1 && rely >= 0 && rely <=1 ) {
370
+ var $img = $(this.img),
371
+ width = $img.width(),
372
+ height = $img.height();
373
+
374
+ var zLeft = width/2 - this.vCenter.x * this.options.zoom;
375
+ var zTop = height/2 - this.vCenter.y * this.options.zoom;
376
+ var vx = relx * width * this.options.zoom + zLeft;
377
+ var vy = rely * height * this.options.zoom + zTop;
378
+ return { x: Math.round(vx), y: Math.round(vy) };
379
+ } else {
380
+
381
+ return null;
382
+ }
383
+ },
384
+ /*
385
+ * Convert a relative image location to a page pixel location
386
+ */
387
+ imgToCursor: function(relx, rely) {
388
+ var pos = this.imgToView(relx, rely);
389
+ if (pos) {
390
+ var offset = $(this.img).offset();
391
+ pos.x += offset.left + this.offsetBorder.x + this.offsetPadding.left;
392
+ pos.y += offset.top + this.offsetBorder.y + this.offsetPadding.top;
393
+ return pos;
394
+ } else {
395
+ return null;
396
+ }
397
+ },
398
+ /*
399
+ * Convert a viewport pixel location to a relative image coordinate
400
+ */
401
+ viewToImg: function(vx, vy) {
402
+ if (this.ready) {
403
+ var $img = $(this.img),
404
+ width = $img.width(),
405
+ height = $img.height();
406
+ var zLeft = width/2 - this.vCenter.x * this.options.zoom;
407
+ var zTop = height/2 - this.vCenter.y * this.options.zoom;
408
+ var relx= (vx - zLeft)/(width * this.options.zoom);
409
+ var rely = (vy - zTop)/(height * this.options.zoom);
410
+ if (relx>=0 && relx<=1 && rely>=0 && rely<=1) {
411
+ return {x: relx, y: rely};
412
+ } else {
413
+ return null;
414
+ }
415
+ } else {
416
+ return null;
417
+ }
418
+ },
419
+
420
+ /*
421
+ * Convert a page pixel location to a relative image coordinate
422
+ */
423
+ cursorToImg: function(cx, cy) {
424
+ if (this.ready) {
425
+ var $img = $(this.img),
426
+ width = $img.width(),
427
+ height = $img.height(),
428
+ offset = $img.offset();
429
+ var zLeft = width/2 - this.vCenter.x * this.options.zoom;
430
+ var zTop = height/2 - this.vCenter.y * this.options.zoom;
431
+ var relx = (cx - offset.left - this.offsetBorder.x - this.offsetPadding.left- zLeft)/(width * this.options.zoom);
432
+ var rely = (cy - offset.top - this.offsetBorder.y - this.offsetPadding.top - zTop)/(height * this.options.zoom);
433
+ if (relx>=0 && relx<=1 && rely>=0 && rely<=1) {
434
+ return {x: relx, y: rely};
435
+ } else {
436
+ return null;
437
+ }
438
+ } else {
439
+ return null;
440
+ }
441
+ },
442
+ /*
443
+ * Adjust the display of the image
444
+ */
445
+ update: function() {
446
+ if (this.ready) {
447
+ var zTop, zLeft, zWidth, zHeight,
448
+ $img = $(this.img),
449
+ width = $img.width(),
450
+ height = $img.height(),
451
+ offset = $img.offset(),
452
+ zoom = this.options.zoom,
453
+ zoomMax = this.options.zoomMax,
454
+ half_width = width/2,
455
+ half_height = height/2;
456
+
457
+ if (zoomMax !==0) {
458
+ zoom = Math.min(zoom, zoomMax);
459
+ this.options.zoom = zoom;
460
+ }
461
+ if (zoom <= 1) {
462
+ zTop = 0;
463
+ zLeft = 0;
464
+ zWidth = width;
465
+ zHeight = height;
466
+ this.vCenter = {
467
+ x: half_width,
468
+ y: half_height
469
+ };
470
+ this.options.zoom = 1;
471
+ zoom = 1;
472
+ } else {
473
+ zTop = Math.round(half_height - this.vCenter.y * zoom);
474
+ zLeft = Math.round(half_width - this.vCenter.x * zoom);
475
+ zWidth = Math.round(width * zoom);
476
+ zHeight = Math.round(height * zoom);
477
+ /*
478
+ * adjust the view center so the image edges snap to the edge of the view
479
+ */
480
+ if (zLeft > 0) {
481
+ this.vCenter.x = half_width/zoom;
482
+ zLeft = 0;
483
+ } else if (zLeft+zWidth < width) {
484
+ this.vCenter.x = width - half_width/zoom ;
485
+ zLeft = width - zWidth;
486
+ }
487
+ if (zTop > 0) {
488
+ this.vCenter.y = half_height/zoom;
489
+ zTop = 0;
490
+ } else if (zTop + zHeight < height) {
491
+ this.vCenter.y = height - half_height/zoom;
492
+ zTop = height - zHeight;
493
+ }
494
+ }
495
+ var vTop = Math.round(offset.top + this.offsetBorder.y + this.offsetPadding.top),
496
+ vLeft = Math.round(offset.left + this.offsetBorder.x + this.offsetPadding.left);
497
+ $(this.view).css({
498
+ top: vTop+"px",
499
+ left: vLeft+"px",
500
+ width: width+"px",
501
+ height: height+"px"
502
+ });
503
+ $(this.zimg).css({
504
+ width: width+"px",
505
+ height: height+"px"
506
+ });
507
+
508
+ var xt = -(this.vCenter.x - half_width)*zoom;
509
+ var yt = -(this.vCenter.y - half_height)*zoom;
510
+ $(this.zimg).css({transform: "translate(" + xt + "px," + yt + "px) scale(" + zoom + "," + zoom + ")" });
511
+ /*
512
+ * define the onUpdate option to do something after the image is redisplayed
513
+ * probably shouldn't pass out the this object - need to think of something better
514
+ */
515
+ this._trigger("onUpdate", null, this);
516
+ }
517
+ }
518
+ });
519
+ })(jQuery);
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: imgViewer-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Wayne Mogg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hammerjs-rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.8
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.8
27
+ - !ruby/object:Gem::Dependency
28
+ name: jquery_mousewheel_rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 3.1.12
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.1.12
41
+ description: jQuery plugin to zoom and pan images.
42
+ email:
43
+ - waynegm@gmail.com
44
+ - eric@managebac.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE
50
+ - README.md
51
+ - lib/imgViewer-rails.rb
52
+ - lib/imgViewer-rails/version.rb
53
+ - vendor/assets/javascripts/imgViewer.js
54
+ homepage: https://github.com/eduvo/imgViewer-rails
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.6.14
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: jQuery plugin to zoom and pan images, even those with a size that is a percentage
78
+ of their container.
79
+ test_files: []