").addClass("guillotine-window")).css({width:"100%",height:"auto","padding-top":o}),s=e.wrap(s).parent(),this.$el=h,this.el=h[0],this.$canvas=e,this.canvas=e[0],this.$gllt=s,this.gllt=s[0],this.$document=t(i.ownerDocument),this.$body=t("body",this.$document)},i.prototype._unwrap=function(){return this.$el.removeAttr("style"),this.$el.insertBefore(this.gllt),this.$gllt.remove()},i.prototype._init=function(){var t,i,e;return i=this.op.init,(e=parseFloat(i.scale))&&this._zoom(e),(t=parseInt(i.angle))&&this._rotate(t),this._offset(parseInt(i.x)/this.op.width||0,parseInt(i.y)/this.op.height||0)},i.prototype._start=function(t){if(this.enabled&&u(t))return t.preventDefault(),t.stopImmediatePropagation(),this.p=n(t),this._bind()},i.prototype._bind=function(){return this.$body.addClass("guillotine-dragging"),this.$document.on(s.move,this._drag),this.$document.on(s.stop,this._unbind)},i.prototype._unbind=function(t){if(this.$body.removeClass("guillotine-dragging"),this.$document.off(s.move,this._drag),this.$document.off(s.stop,this._unbind),null!=t)return this._trigger("drag")},i.prototype._trigger=function(t){if(null!=this.op.eventOnChange&&this.$el.trigger(this.op.eventOnChange,[this.data,t]),"function"==typeof this.op.onChange)return this.op.onChange.call(this.el,this.data,t)},i.prototype._drag=function(t){var i,e,h,s,o;return t.preventDefault(),t.stopImmediatePropagation(),s=n(t),i=s.x-this.p.x,e=s.y-this.p.y,this.p=s,h=0===i?null:this.left-i/this.gllt.clientWidth,o=0===e?null:this.top-e/this.gllt.clientHeight,this._offset(h,o)},i.prototype._offset=function(t,i){if((t||0===t)&&(t<0&&(t=0),t>this.width-1&&(t=this.width-1),this.canvas.style.left=(100*-t).toFixed(2)+"%",this.left=t,this.data.x=Math.round(t*this.op.width)),i||0===i)return i<0&&(i=0),i>this.height-1&&(i=this.height-1),this.canvas.style.top=(100*-i).toFixed(2)+"%",this.top=i,this.data.y=Math.round(i*this.op.height)},i.prototype._zoom=function(t){var i,e,h,s;if(!(t<=0||1===t||(s=this.width,i=this.height,this.op.maxScale&&this.data.scale*t>this.op.maxScale)))return s*t>1&&i*t>1?(this.width*=t,this.height*=t,this.canvas.style.width=(100*this.width).toFixed(2)+"%",this.canvas.style.height=(100*this.height).toFixed(2)+"%",this.data.scale*=t):(this._fit(),t=this.width/s),e=(this.left+.5)*t-.5,h=(this.top+.5)*t-.5,this._offset(e,h)},i.prototype._zoomScale=function(t){var i;return t=parseFloat(t),i=t/this.data.scale,this._zoom(i)},i.prototype._fit=function(){var t,i;return t=this.width,i=this.height/this.width,i>1?(this.width=1,this.height=i):(this.width=1/i,this.height=1),this.canvas.style.width=(100*this.width).toFixed(2)+"%",this.canvas.style.height=(100*this.height).toFixed(2)+"%",this.data.scale*=this.width/t},i.prototype._center=function(){return this._offset((this.width-1)/2,(this.height-1)/2)},i.prototype._rotate=function(t){var i,h,s,n,o,a,r,l;if(e()&&0!==t&&t%90==0)return this.angle=(this.angle+t)%360,this.angle<0&&(this.angle=360+this.angle),t%180!=0&&(l=this.widthReal,s=this.heightReal,this.angle%180!=0&&(l=(n=[s,l])[0],s=n[1]),this.data.minScale=+Math.max.apply(this,[this.op.width/l,this.op.height/s]).toFixed(2),h=this.op.height/this.op.width,o=[this.height*h,this.width/h],this.width=o[0],this.height=o[1],this.width>=1&&this.height>=1?(this.canvas.style.width=100*this.width+"%",this.canvas.style.height=100*this.height+"%"):this._fit()),a=[1,1],l=a[0],s=a[1],this.angle%180!=0&&(l=(r=[i=this.height/this.width*h,1/i])[0],s=r[1]),this.el.style.width=100*l+"%",this.el.style.height=100*s+"%",this.el.style.left=(1-l)/2*100+"%",this.el.style.top=(1-s)/2*100+"%",this.$el.css({transform:"rotate("+this.angle+"deg)"}),this._center(),this.data.angle=this.angle},i.prototype.rotateLeft=function(){return this.enabled&&(this._rotate(-90),this._trigger("rotateLeft"))},i.prototype.rotateRight=function(){return this.enabled&&(this._rotate(90),this._trigger("rotateRight"))},i.prototype.center=function(){return this.enabled&&(this._center(),this._trigger("center"))},i.prototype.fit=function(){return this.enabled&&(this._fit(),this._center(),this._trigger("fit"))},i.prototype.zoomIn=function(){return this.enabled&&(this._zoom(this.zoomInFactor),this._trigger("zoomIn"))},i.prototype.zoomOut=function(){return this.enabled&&(this._zoom(this.zoomOutFactor),this._trigger("zoomOut"))},i.prototype.zoomCustom=function(t){return this.enabled&&(this._zoomScale(t),this._trigger("zoomCustom"))},i.prototype.getData=function(){return this.data},i.prototype.enable=function(){return this.enabled=!0},i.prototype.disable=function(){return this.enabled=!1},i.prototype.remove=function(){return this._unbind(),this._unwrap(),this.disable(),this.$el.off(s.start,this._start),this.$el.removeData(r+"Instance")},i}(),g=["rotateLeft","rotateRight","center","fit","zoomIn","zoomOut","zoomCustom","instance","getData","enable","disable","remove"],t.fn[r]=function(e,h){return"string"!=typeof e?this.each(function(){var h;if(!t.data(this,r+"Instance"))return h=new i(this,e),t.data(this,r+"Instance",h)}):c.call(g,e)>=0?"instance"===e?t.data(this[0],r+"Instance"):"getData"===e?t.data(this[0],r+"Instance")[e]():this.each(function(){var i;if(i=t.data(this,r+"Instance"))return i[e](h)}):void 0}}).call(this);
\ No newline at end of file
diff --git a/src/jquery.guillotine.coffee b/src/jquery.guillotine.coffee
index 7551483..bc64015 100644
--- a/src/jquery.guillotine.coffee
+++ b/src/jquery.guillotine.coffee
@@ -130,7 +130,7 @@ class Guillotine
@width = @height = @left = @top = @angle = 0
# Transformation instructions
- @data = { scale: 1, angle: 0, x: 0, y: 0, w: @op.width, h: @op.height }
+ @data = { scale: 1, angle: 0, x: 0, y: 0, w: @op.width, h: @op.height, minScale: 1, zoomStep: +@op.zoomStep.toFixed(2), maxScale: +@op.maxScale.toFixed(2)}
# Markup
@_wrap(element)
@@ -151,7 +151,11 @@ class Guillotine
# Get image's real dimensions
if element.tagName is 'IMG'
- if element.naturalWidth
+ # Forced image params
+ if element.width and element.height
+ width = element.width
+ height = element.height
+ else if element.naturalWidth
width = element.naturalWidth
height = element.naturalHeight
else
@@ -169,6 +173,13 @@ class Guillotine
canvas = $('
').addClass('guillotine-canvas')
canvas.css width: @width*100+'%', height: @height*100+'%', top: 0, left: 0
canvas = el.wrap(canvas).parent()
+
+ # Store additional data for zooming
+ @widthReal = width
+ @heightReal = height
+ @widthOrig = @width #0-1
+ @heightOrig = @height #0-1
+ @data.minScale = +(Math.max.apply @, [@op.width/@widthReal, @op.height/@heightReal]).toFixed(2)
# Guillotine (window)
## Responsive with fixed aspect ratio.
@@ -276,6 +287,7 @@ class Guillotine
return if factor <= 0 or factor == 1
w = @width; h = @height
+ return if @op.maxScale and @data.scale * factor > @op.maxScale
# Zoom
if w * factor > 1 and h * factor > 1
@width *= factor
@@ -302,6 +314,12 @@ class Guillotine
top = (@top + 0.5) * factor - 0.5
@_offset left, top
+
+ _zoomScale: (scale) ->
+ scale = parseFloat(scale);
+ factor = scale / @data.scale;
+ @_zoom factor
+
# Adjust the element (canvas) to the edges of the window keeping aspect ratio.
_fit: ->
@@ -329,9 +347,15 @@ class Guillotine
# Smallest positive equivalent angle (total rotation)
@angle = (@angle + angle) % 360
@angle = 360 + @angle if @angle < 0
-
+
# Different dimensions?
if (angle % 180 isnt 0)
+ # Calc new min scale
+ w = @widthReal ; h = @heightReal
+ if @angle % 180 isnt 0
+ [w,h] = [h,w]
+ @data.minScale = +(Math.max.apply @, [@op.width/w, @op.height/h]).toFixed(2)
+
# Switch canvas dimensions (as percentages)
#
# canvasWidth = @width * glltWidth; canvasHeight = @height * glltHeigth
@@ -375,6 +399,7 @@ class Guillotine
fit: -> @enabled and (@_fit(); @_center(); @_trigger('fit'))
zoomIn: -> @enabled and (@_zoom(@zoomInFactor); @_trigger('zoomIn'))
zoomOut: -> @enabled and (@_zoom(@zoomOutFactor); @_trigger('zoomOut'))
+ zoomCustom:(f) -> @enabled and (@_zoomScale(f); @_trigger('zoomCustom'))
# Utilities
getData: -> @data
@@ -392,10 +417,10 @@ class Guillotine
# The Plugin
# ______________________________
#
-whitelist = ['rotateLeft', 'rotateRight', 'center', 'fit', 'zoomIn', 'zoomOut', \
+whitelist = ['rotateLeft', 'rotateRight', 'center', 'fit', 'zoomIn', 'zoomOut', 'zoomCustom', \
'instance', 'getData', 'enable', 'disable', 'remove']
-$.fn[pluginName] = (options) ->
+$.fn[pluginName] = (options, param) ->
# Plug it! Lightweight plugin wrapper around the constructor.
if typeof options isnt 'string'
@each ->
@@ -412,4 +437,4 @@ $.fn[pluginName] = (options) ->
return $.data(@[0], pluginName+'Instance')[options]() if options is 'getData'
@each ->
guillotine = $.data(@, pluginName + 'Instance')
- guillotine[options]() if guillotine
+ guillotine[options](param) if guillotine