jquery.ql_zoom.js | |
---|---|
Dependencies: imagesLoaded throttle | /*
$.fn.imagesLoaded mit license. paul irish. 2010.
webkit fix from Oren Solomianik. thx!
*/
(function($){
$.fn.imagesLoaded = function(callback){
var elems = this.filter('img'),
len = elems.length;
elems.bind('load',function(){
if (--len <= 0){ callback.call(elems,this); }
}).each(function(){ |
cached images don't fire load sometimes, so we reset src. | if (this.complete || this.complete === undefined){
var src = this.src; |
webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f data uri bypasses webkit log warning (thx doug jones) | this.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
this.src = src;
}
});
return this;
};
})(jQuery);
/*
jQuery throttle / debounce - v1.1 - 3/7/2010
http://benalman.com/projects/jquery-throttle-debounce-plugin/
Copyright (c) 2010 "Cowboy" Ben Alman
Dual licensed under the MIT and GPL licenses.
http://benalman.com/about/license/
*/
(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
/*
QL Zoom
Copyright (c) 2011 Samuel Breed, http://quickleft.com
v0.0.2
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(function($){
$.fn.ql_zoom = function(options) {
var settings = $.extend({}, $.fn.ql_zoom.defaultOptions, options);
return this.each(function() {
var c, pos, o,
_time = new Date().getTime(),
$this = $(this),
$canvas = $('<canvas>', { 'id': 'viewer'+_time, 'style': 'display:none; position:absolute; '+settings.canvas_style }),
target_image, orig_image,
source_width, source_height,
orig_width, orig_height,
w = parseInt( settings.width, 10 ),
h = parseInt( settings.height, 10 ); |
Returns top and left positions calculated for centering box | function offset(x, y){ |
Calculate the relative coordinates, subtracting from the center to get (sx, sy) | var l = ( x - o.left ) - ~~( w / 2),
t = ( y - o.top ) - ~~( h / 2);
return [l,t];
} |
Scales current image selection to target image and returns all arguments for canvas.drawImage() | function magnify( ix, iy ){
var sx, sy, sW, sH, dx, dy, dW, dH; |
Mark the top left corner of target box, scaled from same point on original image | sx = ( (ix * source_width) / orig_width ) + (w / 2);
sy = ( (iy * source_height) / orig_height ) + (h /2); |
Viewing box is set from user settings | sW = w;
sH = h; |
Starting coords for canvas | dx = 0;
dy = 0; |
Now that the width and height are set properly, this works | dW = w;
dH = h; |
Handling for portion of viewer outside boundary of original image by scaling down the draw area | if(sx > source_width - w){
sW = source_width - sx;
dW = sW;
}
if(sy > source_height - h){
sH = source_height - sy;
dH = sH;
} |
Prevent drawImage from chocking on values < 0 | if(sx < 0){ |
dx = Math.abs(sx); sW = w + sx; dW = sW; | sx = 0;
}
if(sy < 0){ |
dy = Math.abs(sy); sH = h + sy; dH = sH; | sy = 0;
} |
Math.floor all values on the way out to prevent subpixel rendering | return [~~sx, ~~sy, ~~sW, ~~sH, ~~dx, ~~dy, ~~dW, ~~dH];
} |
Re-position canvas on mousemove to follow cursor Get updated arguments and redraw zoom window based on position | function track(e) {
var position, rect,
coords = offset( e.pageX, e.pageY ); |
Set the canvas to follow the cursor | $canvas.css({ left: coords[0] +'px', top: coords[1] +'px' }); |
Grab position relative to viewer | position = $canvas.position(); |
Grab the scaled box height and offset distances | rect = magnify( position.left, position.top ); |
Draw the image onto canvas | try{
c.clearRect(0,0,400,400);
c.drawImage( target_image[0], rect[0], rect[1], rect[2], rect[3], rect[4], rect[5], rect[6], rect[7] );
} catch(error){ |
Debug ONLY | console.dir(error);
}
}
function Events() {
if( source_height <= orig_height + ( orig_height / 10 ) ) {
return false;
}
if( source_width <= orig_width + ( orig_width / 10 ) ) {
return false;
} |
Bind show / hide canvas on hover Bind mousemove with Ben Alman's $.throttle plugin to keep canvas re-draws down | $this
.mouseenter( function(e){
$canvas.fadeIn(settings.speed);
})
.mouseleave( function(e){
$canvas.fadeOut(settings.speed);
})
.mousemove( $.throttle( settings.throttle, track) ); |
Reset the cached offset in case of a resize | $(window).resize(function(e){
o = $this.offset();
});
} |
Set everything up | (function init(){ |
Create a container if the selector is the target image TODO: fix this cause it doesn't work right =/ | if( /IMG/.test( $(this)[0].nodeName ) === true ) {
$this.wrapAll( $("<div>", { id: 'ql_zoom_'+_time, 'class': 'ql_zoom_container' }) );
$this = $('#ql_zoom_'+_time);
} |
Attach canvas to our container | $canvas.appendTo($this);
$canvas.css({ 'width': settings.width, 'height': settings.height }); |
Remember to explicitly set width and height attrs. This is extremely important | $canvas[0].setAttribute('width', w);
$canvas[0].setAttribute('height', h); |
Update position, if it's static. If it's fixed, good luck? | if( /static/.test(pos) ){
$this.css('position', 'relative');
} |
Set some additional styling on canvas | $this.css({ 'overflow': 'hidden', 'cursor': settings.pointer }); |
Cache the container's offset from the window | o = $this.offset(); |
Expose a copy of the HTML5 context | c = $canvas.get()[0].getContext('2d'); |
Save a copy of the original image | orig_image = $this.find('img').first(); |
Cache original image dimensions | orig_height = orig_image.height();
orig_width = orig_image.width(); |
Attach the target image to the safe container | target_image = $('<img>', { 'src': ( !! orig_image.data('url') ) ? orig_image.data('url') : orig_image.attr('src'), 'style': 'display:none;'}).appendTo($this); |
Using the lovely & talented Paul Irish's imagesLoaded helper | target_image.imagesLoaded(function(){ |
Cache source image dimensions | source_height = target_image.height();
source_width = target_image.width(); |
Attach our DOM events after larger image is loaded | Events();
});
})(); // End init()
});
};
$.fn.ql_zoom.defaultOptions = {
width: '200px',
height:'200px',
speed: '800',
throttle: 50,
pointer: 'crosshair',
canvas_style: 'border:1px solid #444;'
};
})(jQuery);
|