文件名:pinchzoom
/*
Copyright (c) Manuel Stofer 2012 - rtp.ch - RTP.PinchZoom.js
This is free software; you can redistribute it and/or modify it under the terms
of the [GNU General Public License](http://www.gnu.org/licenses/gpl-3.0.txt),
either version 3 of the License, or (at your option) any later version.
*/
/*global jQuery, console, define, setTimeout, _, window*/
(function () {
'use strict';
var definePinchZoom = function ($, _) {
/**
* Pinch zoom using jQuery and Underscore.js
* @author Manuel Stofer <mst@rtp.ch>
* @param el
* @param options
* @constructor
*/
var PinchZoom = function (el, options) {
this.el = $(el);
this.zoomFactor = 1;
this.lastScale = 1;
this.offset = {
x: 0,
y: 0
};
this.options = _.extend(this.defaults, options);
this.setupMarkup();
this.bindEvents();
this.update();
},
sum = function (a, b) {
return a + b;
},
isCloseTo = function (value, expected) {
return value > expected - 0.01 && value < expected + 0.01;
};
PinchZoom.prototype = {
defaults: {
tapZoomFactor: 2,
zoomOutFactor: 1.3,
animationDuration: 300,
animationInterval: 5,
maxZoom: 4,
minZoom: 0.5,
use2d: true
},
/**
* Event handler for 'dragstart'
* @param event
*/
handleDragStart: function (event) {
this.stopAnimation();
this.lastDragPosition = false;
this.hasInteraction = true;
this.handleDrag(event);
},
/**
* Event handler for 'drag'
* @param event
*/
handleDrag: function (event) {
if (this.zoomFactor > 1.0) {
var touch = this.getTouches(event)[0];
this.drag(touch, this.lastDragPosition);
this.offset = this.sanitizeOffset(this.offset);
this.lastDragPosition = touch;
}
},
handleDragEnd: function () {
this.end();
},
/**
* Event handler for 'zoomstart'
* @param event
*/
handleZoomStart: function (event) {
this.stopAnimation();
this.lastScale = 1;
this.nthZoom = 0;
this.lastZoomCenter = false;
this.hasInteraction = true;
},
/**
* Event handler for 'zoom'
* @param event
*/
handleZoom: function (event, newScale) {
// a relative scale factor is used
var touchCenter = this.getTouchCenter(this.getTouches(event)),
scale = newScale / this.lastScale;
this.lastScale = newScale;
// the first touch events are thrown away since they are not precise
this.nthZoom += 1;
if (this.nthZoom > 3) {
this.scale(scale, touchCenter);
this.drag(touchCenter, this.lastZoomCenter);
}
this.lastZoomCenter = touchCenter;
},
handleZoomEnd: function () {
this.end();
},
/**
* Event handler for 'doubletap'
* @param event
*/
handleDoubleTap: function (event) {
var center = this.getTouches(event)[0],
zoomFactor = this.zoomFactor > 1 ? 1 : this.options.tapZoomFactor,
startZoomFactor = this.zoomFactor,
updateProgress = _.bind(function (progress) {
this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor), center);
}, this);
if (this.hasInteraction) {
return;
}
if (startZoomFactor > zoomFactor) {
center = this.getCurrentZoomCenter();
}
this.animate(this.options.animationDuration, this.options.animationInterval, updateProgress, this.swing);
},
/**
* Max / min values for the offset
* @param offset
* @return {Object} the sanitized offset
*/
sanitizeOffset: function (offset) {
var maxX = (this.zoomFactor - 1) * this.getContainerX(),
maxY = (this.zoomFactor - 1) * this.getContainerY(),
maxOffsetX = Math.max(maxX, 0),
maxOffsetY = Math.max(maxY, 0),
minOffsetX = Math.min(maxX, 0),
minOffsetY = Math.min(maxY, 0);
return {
x: Math.min(Math.max(offset.x, minOffsetX), maxOffsetX),
y: Math.min(Math.max(offset.y, minOffsetY), maxOffsetY)
};
},
/**
* Scale to a specific zoom factor (not relative)
* @param zoomFactor
* @param center