722 lines
19 KiB
JavaScript
722 lines
19 KiB
JavaScript
|
//>>built
|
||
|
// wrapped by build app
|
||
|
define("dojox/mobile/app/ImageView", ["dijit","dojo","dojox","dojo/require!dojox/mobile/app/_Widget,dojo/fx/easing"], function(dijit,dojo,dojox){
|
||
|
dojo.provide("dojox.mobile.app.ImageView");
|
||
|
dojo.experimental("dojox.mobile.app.ImageView");
|
||
|
dojo.require("dojox.mobile.app._Widget");
|
||
|
|
||
|
dojo.require("dojo.fx.easing");
|
||
|
|
||
|
dojo.declare("dojox.mobile.app.ImageView", dojox.mobile.app._Widget, {
|
||
|
|
||
|
// zoom: Number
|
||
|
// The current level of zoom. This should not be set manually.
|
||
|
zoom: 1,
|
||
|
|
||
|
// zoomCenterX: Number
|
||
|
// The X coordinate in the image where the zoom is focused
|
||
|
zoomCenterX: 0,
|
||
|
|
||
|
// zoomCenterY: Number
|
||
|
// The Y coordinate in the image where the zoom is focused
|
||
|
zoomCenterY: 0,
|
||
|
|
||
|
// maxZoom: Number
|
||
|
// The highest degree to which an image can be zoomed. For example,
|
||
|
// a maxZoom of 5 means that the image will be 5 times larger than normal
|
||
|
maxZoom: 5,
|
||
|
|
||
|
// autoZoomLevel: Number
|
||
|
// The degree to which the image is zoomed when auto zoom is invoked.
|
||
|
// The higher the number, the more the image is zoomed in.
|
||
|
autoZoomLevel: 3,
|
||
|
|
||
|
// disableAutoZoom: Boolean
|
||
|
// Disables auto zoom
|
||
|
disableAutoZoom: false,
|
||
|
|
||
|
// disableSwipe: Boolean
|
||
|
// Disables the users ability to swipe from one image to the next.
|
||
|
disableSwipe: false,
|
||
|
|
||
|
// autoZoomEvent: String
|
||
|
// Overrides the default event listened to which invokes auto zoom
|
||
|
autoZoomEvent: null,
|
||
|
|
||
|
// _leftImg: Node
|
||
|
// The full sized image to the left
|
||
|
_leftImg: null,
|
||
|
|
||
|
// _centerImg: Node
|
||
|
// The full sized image in the center
|
||
|
_centerImg: null,
|
||
|
|
||
|
// _rightImg: Node
|
||
|
// The full sized image to the right
|
||
|
_rightImg: null,
|
||
|
|
||
|
// _leftImg: Node
|
||
|
// The small sized image to the left
|
||
|
_leftSmallImg: null,
|
||
|
|
||
|
// _centerImg: Node
|
||
|
// The small sized image in the center
|
||
|
_centerSmallImg: null,
|
||
|
|
||
|
// _rightImg: Node
|
||
|
// The small sized image to the right
|
||
|
_rightSmallImg: null,
|
||
|
|
||
|
constructor: function(){
|
||
|
|
||
|
this.panX = 0;
|
||
|
this.panY = 0;
|
||
|
|
||
|
this.handleLoad = dojo.hitch(this, this.handleLoad);
|
||
|
this._updateAnimatedZoom = dojo.hitch(this, this._updateAnimatedZoom);
|
||
|
this._updateAnimatedPan = dojo.hitch(this, this._updateAnimatedPan);
|
||
|
this._onAnimPanEnd = dojo.hitch(this, this._onAnimPanEnd);
|
||
|
},
|
||
|
|
||
|
buildRendering: function(){
|
||
|
this.inherited(arguments);
|
||
|
|
||
|
this.canvas = dojo.create("canvas", {}, this.domNode);
|
||
|
|
||
|
dojo.addClass(this.domNode, "mblImageView");
|
||
|
},
|
||
|
|
||
|
postCreate: function(){
|
||
|
this.inherited(arguments);
|
||
|
|
||
|
this.size = dojo.marginBox(this.domNode);
|
||
|
|
||
|
dojo.style(this.canvas, {
|
||
|
width: this.size.w + "px",
|
||
|
height: this.size.h + "px"
|
||
|
});
|
||
|
this.canvas.height = this.size.h;
|
||
|
this.canvas.width = this.size.w;
|
||
|
|
||
|
var _this = this;
|
||
|
|
||
|
// Listen to the mousedown/touchstart event. Record the position
|
||
|
// so we can use it to pan the image.
|
||
|
this.connect(this.domNode, "onmousedown", function(event){
|
||
|
if(_this.isAnimating()){
|
||
|
return;
|
||
|
}
|
||
|
if(_this.panX){
|
||
|
_this.handleDragEnd();
|
||
|
}
|
||
|
|
||
|
_this.downX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
|
||
|
_this.downY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
|
||
|
});
|
||
|
|
||
|
// record the movement of the mouse.
|
||
|
this.connect(this.domNode, "onmousemove", function(event){
|
||
|
if(_this.isAnimating()){
|
||
|
return;
|
||
|
}
|
||
|
if((!_this.downX && _this.downX !== 0) || (!_this.downY && _this.downY !== 0)){
|
||
|
// If the touch didn't begin on this widget, ignore the movement
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if((!_this.disableSwipe && _this.zoom == 1)
|
||
|
|| (!_this.disableAutoZoom && _this.zoom != 1)){
|
||
|
var x = event.targetTouches ?
|
||
|
event.targetTouches[0].clientX : event.pageX;
|
||
|
var y = event.targetTouches ?
|
||
|
event.targetTouches[0].clientY : event.pageY;
|
||
|
|
||
|
_this.panX = x - _this.downX;
|
||
|
_this.panY = y - _this.downY;
|
||
|
|
||
|
if(_this.zoom == 1){
|
||
|
// If not zoomed in, then try to move to the next or prev image
|
||
|
// but only if the mouse has moved more than 10 pixels
|
||
|
// in the X direction
|
||
|
if(Math.abs(_this.panX) > 10){
|
||
|
_this.render();
|
||
|
}
|
||
|
}else{
|
||
|
// If zoomed in, pan the image if the mouse has moved more
|
||
|
// than 10 pixels in either direction.
|
||
|
if(Math.abs(_this.panX) > 10 || Math.abs(_this.panY) > 10){
|
||
|
_this.render();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.connect(this.domNode, "onmouseout", function(event){
|
||
|
if(!_this.isAnimating() && _this.panX){
|
||
|
_this.handleDragEnd();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.connect(this.domNode, "onmouseover", function(event){
|
||
|
_this.downX = _this.downY = null;
|
||
|
});
|
||
|
|
||
|
// Set up AutoZoom, which zooms in a fixed amount when the user taps
|
||
|
// a part of the canvas
|
||
|
this.connect(this.domNode, "onclick", function(event){
|
||
|
if(_this.isAnimating()){
|
||
|
return;
|
||
|
}
|
||
|
if(_this.downX == null || _this.downY == null){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var x = (event.targetTouches ?
|
||
|
event.targetTouches[0].clientX : event.pageX);
|
||
|
var y = (event.targetTouches ?
|
||
|
event.targetTouches[0].clientY : event.pageY);
|
||
|
|
||
|
// If the mouse/finger has moved more than 14 pixels from where it
|
||
|
// started, do not treat it as a click. It is a drag.
|
||
|
if(Math.abs(_this.panX) > 14 || Math.abs(_this.panY) > 14){
|
||
|
_this.downX = _this.downY = null;
|
||
|
_this.handleDragEnd();
|
||
|
return;
|
||
|
}
|
||
|
_this.downX = _this.downY = null;
|
||
|
|
||
|
if(!_this.disableAutoZoom){
|
||
|
|
||
|
if(!_this._centerImg || !_this._centerImg._loaded){
|
||
|
// Do nothing until the image is loaded
|
||
|
return;
|
||
|
}
|
||
|
if(_this.zoom != 1){
|
||
|
_this.set("animatedZoom", 1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var pos = dojo._abs(_this.domNode);
|
||
|
|
||
|
// Translate the clicked point to a point on the source image
|
||
|
var xRatio = _this.size.w / _this._centerImg.width;
|
||
|
var yRatio = _this.size.h / _this._centerImg.height;
|
||
|
|
||
|
// Do an animated zoom to the point which was clicked.
|
||
|
_this.zoomTo(
|
||
|
((x - pos.x) / xRatio) - _this.panX,
|
||
|
((y - pos.y) / yRatio) - _this.panY,
|
||
|
_this.autoZoomLevel);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Listen for Flick events
|
||
|
dojo.connect(this.domNode, "flick", this, "handleFlick");
|
||
|
},
|
||
|
|
||
|
isAnimating: function(){
|
||
|
// summary:
|
||
|
// Returns true if an animation is in progress, false otherwise.
|
||
|
return this._anim && this._anim.status() == "playing";
|
||
|
},
|
||
|
|
||
|
handleDragEnd: function(){
|
||
|
// summary:
|
||
|
// Handles the end of a dragging event. If not zoomed in, it
|
||
|
// determines if the next or previous image should be transitioned
|
||
|
// to.
|
||
|
this.downX = this.downY = null;
|
||
|
console.log("handleDragEnd");
|
||
|
|
||
|
if(this.zoom == 1){
|
||
|
if(!this.panX){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var leftLoaded = (this._leftImg && this._leftImg._loaded)
|
||
|
|| (this._leftSmallImg && this._leftSmallImg._loaded);
|
||
|
var rightLoaded = (this._rightImg && this._rightImg._loaded)
|
||
|
|| (this._rightSmallImg && this._rightSmallImg._loaded);
|
||
|
|
||
|
// Check if the drag has moved the image more than half its length.
|
||
|
// If so, move to either the previous or next image.
|
||
|
var doMove =
|
||
|
!(Math.abs(this.panX) < this._centerImg._baseWidth / 2) &&
|
||
|
(
|
||
|
(this.panX > 0 && leftLoaded ? 1 : 0) ||
|
||
|
(this.panX < 0 && rightLoaded ? 1 : 0)
|
||
|
);
|
||
|
|
||
|
|
||
|
if(!doMove){
|
||
|
// If not moving to another image, animate the sliding of the
|
||
|
// image back into place.
|
||
|
this._animPanTo(0, dojo.fx.easing.expoOut, 700);
|
||
|
}else{
|
||
|
// Move to another image.
|
||
|
this.moveTo(this.panX);
|
||
|
}
|
||
|
}else{
|
||
|
if(!this.panX && !this.panY){
|
||
|
return;
|
||
|
}
|
||
|
// Recenter the zoomed image based on where it was panned to
|
||
|
// previously
|
||
|
this.zoomCenterX -= (this.panX / this.zoom);
|
||
|
this.zoomCenterY -= (this.panY / this.zoom);
|
||
|
|
||
|
this.panX = this.panY = 0;
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
handleFlick: function(event){
|
||
|
// summary:
|
||
|
// Handle a flick event.
|
||
|
if(this.zoom == 1 && event.duration < 500){
|
||
|
// Only handle quick flicks here, less than 0.5 seconds
|
||
|
|
||
|
// If not zoomed in, then check if we should move to the next photo
|
||
|
// or not
|
||
|
if(event.direction == "ltr"){
|
||
|
this.moveTo(1);
|
||
|
}else if(event.direction == "rtl"){
|
||
|
this.moveTo(-1);
|
||
|
}
|
||
|
// If an up or down flick occurs, it means nothing so ignore it
|
||
|
this.downX = this.downY = null;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
moveTo: function(direction){
|
||
|
direction = direction > 0 ? 1 : -1;
|
||
|
var toImg;
|
||
|
|
||
|
if(direction < 1){
|
||
|
if(this._rightImg && this._rightImg._loaded){
|
||
|
toImg = this._rightImg;
|
||
|
}else if(this._rightSmallImg && this._rightSmallImg._loaded){
|
||
|
toImg = this._rightSmallImg;
|
||
|
}
|
||
|
}else{
|
||
|
if(this._leftImg && this._leftImg._loaded){
|
||
|
toImg = this._leftImg;
|
||
|
}else if(this._leftSmallImg && this._leftSmallImg._loaded){
|
||
|
toImg = this._leftSmallImg;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._moveDir = direction;
|
||
|
var _this = this;
|
||
|
|
||
|
if(toImg && toImg._loaded){
|
||
|
// If the image is loaded, make a linear animation to show it
|
||
|
this._animPanTo(this.size.w * direction, null, 500, function(){
|
||
|
_this.panX = 0;
|
||
|
_this.panY = 0;
|
||
|
|
||
|
if(direction < 0){
|
||
|
// Moving to show the right image
|
||
|
_this._switchImage("left", "right");
|
||
|
}else{
|
||
|
// Moving to show the left image
|
||
|
_this._switchImage("right", "left");
|
||
|
}
|
||
|
|
||
|
_this.render();
|
||
|
_this.onChange(direction * -1);
|
||
|
});
|
||
|
|
||
|
}else{
|
||
|
// If the next image is not loaded, make an animation to
|
||
|
// move the center image to half the width of the widget and back
|
||
|
// again
|
||
|
|
||
|
console.log("moveTo image not loaded!", toImg);
|
||
|
|
||
|
this._animPanTo(0, dojo.fx.easing.expoOut, 700);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_switchImage: function(toImg, fromImg){
|
||
|
var toSmallImgName = "_" + toImg + "SmallImg";
|
||
|
var toImgName = "_" + toImg + "Img";
|
||
|
|
||
|
var fromSmallImgName = "_" + fromImg + "SmallImg";
|
||
|
var fromImgName = "_" + fromImg + "Img";
|
||
|
|
||
|
this[toImgName] = this._centerImg;
|
||
|
this[toSmallImgName] = this._centerSmallImg;
|
||
|
|
||
|
this[toImgName]._type = toImg;
|
||
|
|
||
|
if(this[toSmallImgName]){
|
||
|
this[toSmallImgName]._type = toImg;
|
||
|
}
|
||
|
|
||
|
this._centerImg = this[fromImgName];
|
||
|
this._centerSmallImg = this[fromSmallImgName];
|
||
|
this._centerImg._type = "center";
|
||
|
|
||
|
if(this._centerSmallImg){
|
||
|
this._centerSmallImg._type = "center";
|
||
|
}
|
||
|
this[fromImgName] = this[fromSmallImgName] = null;
|
||
|
},
|
||
|
|
||
|
_animPanTo: function(to, easing, duration, callback){
|
||
|
this._animCallback = callback;
|
||
|
this._anim = new dojo.Animation({
|
||
|
curve: [this.panX, to],
|
||
|
onAnimate: this._updateAnimatedPan,
|
||
|
duration: duration || 500,
|
||
|
easing: easing,
|
||
|
onEnd: this._onAnimPanEnd
|
||
|
});
|
||
|
|
||
|
this._anim.play();
|
||
|
return this._anim;
|
||
|
},
|
||
|
|
||
|
onChange: function(direction){
|
||
|
// summary:
|
||
|
// Stub function that can be listened to in order to provide
|
||
|
// new images when the displayed image changes
|
||
|
},
|
||
|
|
||
|
_updateAnimatedPan: function(amount){
|
||
|
this.panX = amount;
|
||
|
this.render();
|
||
|
},
|
||
|
|
||
|
_onAnimPanEnd: function(){
|
||
|
this.panX = this.panY = 0;
|
||
|
|
||
|
if(this._animCallback){
|
||
|
this._animCallback();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
zoomTo: function(centerX, centerY, zoom){
|
||
|
this.set("zoomCenterX", centerX);
|
||
|
this.set("zoomCenterY", centerY);
|
||
|
|
||
|
this.set("animatedZoom", zoom);
|
||
|
},
|
||
|
|
||
|
render: function(){
|
||
|
var cxt = this.canvas.getContext('2d');
|
||
|
|
||
|
cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||
|
|
||
|
// Render the center image
|
||
|
this._renderImg(
|
||
|
this._centerSmallImg,
|
||
|
this._centerImg,
|
||
|
this.zoom == 1 ? (this.panX < 0 ? 1 : this.panX > 0 ? -1 : 0) : 0);
|
||
|
|
||
|
if(this.zoom == 1 && this.panX != 0){
|
||
|
if(this.panX > 0){
|
||
|
// Render the left image, showing the right side of it
|
||
|
this._renderImg(this._leftSmallImg, this._leftImg, 1);
|
||
|
}else{
|
||
|
// Render the right image, showing the left side of it
|
||
|
this._renderImg(this._rightSmallImg, this._rightImg, -1);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_renderImg: function(smallImg, largeImg, panDir){
|
||
|
// summary:
|
||
|
// Renders a single image
|
||
|
|
||
|
|
||
|
// If zoomed, we just display the center img
|
||
|
var img = (largeImg && largeImg._loaded) ? largeImg : smallImg;
|
||
|
|
||
|
if(!img || !img._loaded){
|
||
|
// If neither the large or small image is loaded, display nothing
|
||
|
return;
|
||
|
}
|
||
|
var cxt = this.canvas.getContext('2d');
|
||
|
|
||
|
var baseWidth = img._baseWidth;
|
||
|
var baseHeight = img._baseHeight;
|
||
|
|
||
|
// Calculate the size the image would be if there were no bounds
|
||
|
var desiredWidth = baseWidth * this.zoom;
|
||
|
var desiredHeight = baseHeight * this.zoom;
|
||
|
|
||
|
// Calculate the actual size of the viewable image
|
||
|
var destWidth = Math.min(this.size.w, desiredWidth);
|
||
|
var destHeight = Math.min(this.size.h, desiredHeight);
|
||
|
|
||
|
|
||
|
// Calculate the size of the window on the original image to use
|
||
|
var sourceWidth = this.dispWidth = img.width * (destWidth / desiredWidth);
|
||
|
var sourceHeight = this.dispHeight = img.height * (destHeight / desiredHeight);
|
||
|
|
||
|
var zoomCenterX = this.zoomCenterX - (this.panX / this.zoom);
|
||
|
var zoomCenterY = this.zoomCenterY - (this.panY / this.zoom);
|
||
|
|
||
|
// Calculate where the center of the view should be
|
||
|
var centerX = Math.floor(Math.max(sourceWidth / 2,
|
||
|
Math.min(img.width - sourceWidth / 2, zoomCenterX)));
|
||
|
var centerY = Math.floor(Math.max(sourceHeight / 2,
|
||
|
Math.min(img.height - sourceHeight / 2, zoomCenterY)));
|
||
|
|
||
|
|
||
|
var sourceX = Math.max(0,
|
||
|
Math.round((img.width - sourceWidth)/2 + (centerX - img._centerX)) );
|
||
|
var sourceY = Math.max(0,
|
||
|
Math.round((img.height - sourceHeight) / 2 + (centerY - img._centerY))
|
||
|
);
|
||
|
|
||
|
var destX = Math.round(Math.max(0, this.canvas.width - destWidth)/2);
|
||
|
var destY = Math.round(Math.max(0, this.canvas.height - destHeight)/2);
|
||
|
|
||
|
var oldDestWidth = destWidth;
|
||
|
var oldSourceWidth = sourceWidth;
|
||
|
|
||
|
if(this.zoom == 1 && panDir && this.panX){
|
||
|
|
||
|
if(this.panX < 0){
|
||
|
if(panDir > 0){
|
||
|
// If the touch is moving left, and the right side of the
|
||
|
// image should be shown, then reduce the destination width
|
||
|
// by the absolute value of panX
|
||
|
destWidth -= Math.abs(this.panX);
|
||
|
destX = 0;
|
||
|
}else if(panDir < 0){
|
||
|
// If the touch is moving left, and the left side of the
|
||
|
// image should be shown, then set the displayed width
|
||
|
// to the absolute value of panX, less some pixels for
|
||
|
// a padding between images
|
||
|
destWidth = Math.max(1, Math.abs(this.panX) - 5);
|
||
|
destX = this.size.w - destWidth;
|
||
|
}
|
||
|
}else{
|
||
|
if(panDir > 0){
|
||
|
// If the touch is moving right, and the right side of the
|
||
|
// image should be shown, then set the destination width
|
||
|
// to the absolute value of the pan, less some pixels for
|
||
|
// padding
|
||
|
destWidth = Math.max(1, Math.abs(this.panX) - 5);
|
||
|
destX = 0;
|
||
|
}else if(panDir < 0){
|
||
|
// If the touch is moving right, and the left side of the
|
||
|
// image should be shown, then reduce the destination width
|
||
|
// by the widget width minus the absolute value of panX
|
||
|
destWidth -= Math.abs(this.panX);
|
||
|
destX = this.size.w - destWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sourceWidth = Math.max(1,
|
||
|
Math.floor(sourceWidth * (destWidth / oldDestWidth)));
|
||
|
|
||
|
if(panDir > 0){
|
||
|
// If the right side of the image should be displayed, move
|
||
|
// the sourceX to be the width of the image minus the difference
|
||
|
// between the original sourceWidth and the new sourceWidth
|
||
|
sourceX = (sourceX + oldSourceWidth) - (sourceWidth);
|
||
|
}
|
||
|
sourceX = Math.floor(sourceX);
|
||
|
}
|
||
|
|
||
|
try{
|
||
|
|
||
|
// See https://developer.mozilla.org/en/Canvas_tutorial/Using_images
|
||
|
cxt.drawImage(
|
||
|
img,
|
||
|
Math.max(0, sourceX),
|
||
|
sourceY,
|
||
|
Math.min(oldSourceWidth, sourceWidth),
|
||
|
sourceHeight,
|
||
|
destX, // Xpos
|
||
|
destY, // Ypos
|
||
|
Math.min(oldDestWidth, destWidth),
|
||
|
destHeight
|
||
|
);
|
||
|
}catch(e){
|
||
|
console.log("Caught Error",e,
|
||
|
|
||
|
"type=", img._type,
|
||
|
"oldDestWidth = ", oldDestWidth,
|
||
|
"destWidth", destWidth,
|
||
|
"destX", destX
|
||
|
, "oldSourceWidth=",oldSourceWidth,
|
||
|
"sourceWidth=", sourceWidth,
|
||
|
"sourceX = " + sourceX
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_setZoomAttr: function(amount){
|
||
|
this.zoom = Math.min(this.maxZoom, Math.max(1, amount));
|
||
|
|
||
|
if(this.zoom == 1
|
||
|
&& this._centerImg
|
||
|
&& this._centerImg._loaded){
|
||
|
|
||
|
if(!this.isAnimating()){
|
||
|
this.zoomCenterX = this._centerImg.width / 2;
|
||
|
this.zoomCenterY = this._centerImg.height / 2;
|
||
|
}
|
||
|
this.panX = this.panY = 0;
|
||
|
}
|
||
|
|
||
|
this.render();
|
||
|
},
|
||
|
|
||
|
_setZoomCenterXAttr: function(value){
|
||
|
if(value != this.zoomCenterX){
|
||
|
if(this._centerImg && this._centerImg._loaded){
|
||
|
value = Math.min(this._centerImg.width, value);
|
||
|
}
|
||
|
this.zoomCenterX = Math.max(0, Math.round(value));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_setZoomCenterYAttr: function(value){
|
||
|
if(value != this.zoomCenterY){
|
||
|
if(this._centerImg && this._centerImg._loaded){
|
||
|
value = Math.min(this._centerImg.height, value);
|
||
|
}
|
||
|
this.zoomCenterY = Math.max(0, Math.round(value));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_setZoomCenterAttr: function(value){
|
||
|
if(value.x != this.zoomCenterX || value.y != this.zoomCenterY){
|
||
|
this.set("zoomCenterX", value.x);
|
||
|
this.set("zoomCenterY", value.y);
|
||
|
this.render();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_setAnimatedZoomAttr: function(amount){
|
||
|
if(this._anim && this._anim.status() == "playing"){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this._anim = new dojo.Animation({
|
||
|
curve: [this.zoom, amount],
|
||
|
onAnimate: this._updateAnimatedZoom,
|
||
|
onEnd: this._onAnimEnd
|
||
|
});
|
||
|
|
||
|
this._anim.play();
|
||
|
},
|
||
|
|
||
|
_updateAnimatedZoom: function(amount){
|
||
|
this._setZoomAttr(amount);
|
||
|
},
|
||
|
|
||
|
_setCenterUrlAttr: function(urlOrObj){
|
||
|
this._setImage("center", urlOrObj);
|
||
|
},
|
||
|
_setLeftUrlAttr: function(urlOrObj){
|
||
|
this._setImage("left", urlOrObj);
|
||
|
},
|
||
|
_setRightUrlAttr: function(urlOrObj){
|
||
|
this._setImage("right", urlOrObj);
|
||
|
},
|
||
|
|
||
|
_setImage: function(name, urlOrObj){
|
||
|
var smallUrl = null;
|
||
|
|
||
|
var largeUrl = null;
|
||
|
|
||
|
if(dojo.isString(urlOrObj)){
|
||
|
// If the argument is a string, then just load the large url
|
||
|
largeUrl = urlOrObj;
|
||
|
}else{
|
||
|
largeUrl = urlOrObj.large;
|
||
|
smallUrl = urlOrObj.small;
|
||
|
}
|
||
|
|
||
|
if(this["_" + name + "Img"] && this["_" + name + "Img"]._src == largeUrl){
|
||
|
// Identical URL, ignore it
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Just do the large image for now
|
||
|
var largeImg = this["_" + name + "Img"] = new Image();
|
||
|
largeImg._type = name;
|
||
|
largeImg._loaded = false;
|
||
|
largeImg._src = largeUrl;
|
||
|
largeImg._conn = dojo.connect(largeImg, "onload", this.handleLoad);
|
||
|
|
||
|
if(smallUrl){
|
||
|
// If a url to a small version of the image has been provided,
|
||
|
// load that image first.
|
||
|
var smallImg = this["_" + name + "SmallImg"] = new Image();
|
||
|
smallImg._type = name;
|
||
|
smallImg._loaded = false;
|
||
|
smallImg._conn = dojo.connect(smallImg, "onload", this.handleLoad);
|
||
|
smallImg._isSmall = true;
|
||
|
smallImg._src = smallUrl;
|
||
|
smallImg.src = smallUrl;
|
||
|
}
|
||
|
|
||
|
// It's important that the large url's src is set after the small image
|
||
|
// to ensure it's loaded second.
|
||
|
largeImg.src = largeUrl;
|
||
|
},
|
||
|
|
||
|
handleLoad: function(evt){
|
||
|
// summary:
|
||
|
// Handles the loading of an image, both the large and small
|
||
|
// versions. A render is triggered as a result of each image load.
|
||
|
|
||
|
var img = evt.target;
|
||
|
img._loaded = true;
|
||
|
|
||
|
dojo.disconnect(img._conn);
|
||
|
|
||
|
var type = img._type;
|
||
|
|
||
|
switch(type){
|
||
|
case "center":
|
||
|
this.zoomCenterX = img.width / 2;
|
||
|
this.zoomCenterY = img.height / 2;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
var height = img.height;
|
||
|
var width = img.width;
|
||
|
|
||
|
if(width / this.size.w < height / this.size.h){
|
||
|
// Fit the height to the height of the canvas
|
||
|
img._baseHeight = this.canvas.height;
|
||
|
img._baseWidth = width / (height / this.size.h);
|
||
|
}else{
|
||
|
// Fix the width to the width of the canvas
|
||
|
img._baseWidth = this.canvas.width;
|
||
|
img._baseHeight = height / (width / this.size.w);
|
||
|
}
|
||
|
img._centerX = width / 2;
|
||
|
img._centerY = height / 2;
|
||
|
|
||
|
this.render();
|
||
|
|
||
|
this.onLoad(img._type, img._src, img._isSmall);
|
||
|
},
|
||
|
|
||
|
onLoad: function(type, url, isSmall){
|
||
|
// summary:
|
||
|
// Dummy function that is called whenever an image loads.
|
||
|
// type: String
|
||
|
// The position of the image that has loaded, either
|
||
|
// "center", "left" or "right"
|
||
|
// url: String
|
||
|
// The src of the image
|
||
|
// isSmall: Boolean
|
||
|
// True if it is a small version of the image that has loaded,
|
||
|
// false otherwise.
|
||
|
}
|
||
|
});
|
||
|
|
||
|
});
|