dojox/mobile/app/ImageView.js

  • Provides:

    • dojox.mobile.app.ImageView
  • Requires:

    • dojox.mobile.app._Widget in common
    • dojo.fx.easing in common in project dojo
  • dojox.mobile.app.ImageView

    • type
      Function
    • chains:
      • dojox.mobile.app._Widget: (prototype)
      • dojox.mobile.app._Widget: (call)
    • source: [view]
        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);
    • summary
  • dojox.mobile.app.ImageView.zoom

    • type
      Number
    • summary
      The current level of zoom.  This should not be set manually.
  • dojox.mobile.app.ImageView.zoomCenterX

    • type
      Number
    • summary
      The X coordinate in the image where the zoom is focused
  • dojox.mobile.app.ImageView.zoomCenterY

    • type
      Number
    • summary
      The Y coordinate in the image where the zoom is focused
  • dojox.mobile.app.ImageView.maxZoom

    • type
      Number
    • summary
      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
  • dojox.mobile.app.ImageView.autoZoomLevel

    • type
      Number
    • summary
      The degree to which the image is zoomed when auto zoom is invoked.
      The higher the number, the more the image is zoomed in.
  • dojox.mobile.app.ImageView.disableAutoZoom

    • type
      Boolean
    • summary
      Disables auto zoom
  • dojox.mobile.app.ImageView.disableSwipe

    • type
      Boolean
    • summary
      Disables the users ability to swipe from one image to the next.
  • dojox.mobile.app.ImageView.autoZoomEvent

    • type
      String
    • summary
      Overrides the default event listened to which invokes auto zoom
  • dojox.mobile.app.ImageView._leftImg

    • type
      Node
    • summary
      The small sized image to the left
  • dojox.mobile.app.ImageView._centerImg

    • type
      Node
    • summary
      The small sized image in the center
  • dojox.mobile.app.ImageView._rightImg

    • type
      Node
    • summary
      The small sized image to the right
  • dojox.mobile.app.ImageView._leftSmallImg

    • summary
  • dojox.mobile.app.ImageView._centerSmallImg

    • summary
  • dojox.mobile.app.ImageView._rightSmallImg

    • summary
  • dojox.mobile.app.ImageView.buildRendering

    • type
      Function
    • source: [view]
        this.inherited(arguments);


        this.canvas = dojo.create("canvas", {}, this.domNode);


        dojo.addClass(this.domNode, "mblImageView");
    • summary
  • dojox.mobile.app.ImageView.postCreate

    • type
      Function
    • source: [view]
        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");
    • summary
  • dojox.mobile.app.ImageView.isAnimating

    • type
      Function
    • source: [view]
        return this._anim && this._anim.status() == "playing";
    • summary
      Returns true if an animation is in progress, false otherwise.
  • dojox.mobile.app.ImageView.handleDragEnd

    • type
      Function
    • source: [view]
        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;
        }
    • summary
      Handles the end of a dragging event. If not zoomed in, it
      determines if the next or previous image should be transitioned
      to.
  • dojox.mobile.app.ImageView.handleFlick

    • type
      Function
    • parameters:
      • event: (typeof )
    • source: [view]
        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;
        }
    • summary
      Handle a flick event.
  • dojox.mobile.app.ImageView.moveTo

    • type
      Function
    • parameters:
      • direction: (typeof )
    • source: [view]
        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);
        }
    • summary
  • dojox.mobile.app.ImageView._switchImage

    • type
      Function
    • parameters:
      • toImg: (typeof )
      • fromImg: (typeof )
    • source: [view]
        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;
    • summary
  • dojox.mobile.app.ImageView._animPanTo

    • type
      Function
    • parameters:
      • to: (typeof )
      • easing: (typeof )
      • duration: (typeof )
      • callback: (typeof )
    • source: [view]
        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;
    • summary
  • dojox.mobile.app.ImageView.onChange

    • type
      Function
    • parameters:
      • direction: (typeof )
    • source: [view]
        // summary:
        //  Stub function that can be listened to in order to provide
        //  new images when the displayed image changes
    • summary
      Stub function that can be listened to in order to provide
      new images when the displayed image changes
  • dojox.mobile.app.ImageView._updateAnimatedPan

    • type
      Function
    • parameters:
      • amount: (typeof )
    • source: [view]
        this.panX = amount;
        this.render();
    • summary
  • dojox.mobile.app.ImageView._onAnimPanEnd

    • type
      Function
    • source: [view]
        this.panX = this.panY = 0;


        if(this._animCallback){
         this._animCallback();
        }
    • summary
  • dojox.mobile.app.ImageView.zoomTo

    • type
      Function
    • parameters:
      • centerX: (typeof )
      • centerY: (typeof )
      • zoom: (typeof )
    • source: [view]
        this.set("zoomCenterX", centerX);
        this.set("zoomCenterY", centerY);


        this.set("animatedZoom", zoom);
    • summary
  • dojox.mobile.app.ImageView.render

    • type
      Function
    • source: [view]
        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);
         }
        }
    • summary
  • dojox.mobile.app.ImageView._renderImg

    • type
      Function
    • parameters:
      • smallImg: (typeof )
      • largeImg: (typeof )
      • panDir: (typeof )
    • source: [view]
      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
         );
        }
    • summary
  • dojox.mobile.app.ImageView._setZoomAttr

    • type
      Function
    • parameters:
      • amount: (typeof )
    • source: [view]
        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();
    • summary
  • dojox.mobile.app.ImageView._setZoomCenterXAttr

    • type
      Function
    • parameters:
      • value: (typeof )
    • source: [view]
        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));
        }
    • summary
  • dojox.mobile.app.ImageView._setZoomCenterYAttr

    • type
      Function
    • parameters:
      • value: (typeof )
    • source: [view]
        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));
        }
    • summary
  • dojox.mobile.app.ImageView._setZoomCenterAttr

    • type
      Function
    • parameters:
      • value: (typeof )
    • source: [view]
        if(value.x != this.zoomCenterX || value.y != this.zoomCenterY){
         this.set("zoomCenterX", value.x);
         this.set("zoomCenterY", value.y);
         this.render();
        }
    • summary
  • dojox.mobile.app.ImageView._setAnimatedZoomAttr

    • type
      Function
    • parameters:
      • amount: (typeof )
    • source: [view]
        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();
    • summary
  • dojox.mobile.app.ImageView._updateAnimatedZoom

    • type
      Function
    • parameters:
      • amount: (typeof )
    • source: [view]
        this._setZoomAttr(amount);
    • summary
  • dojox.mobile.app.ImageView._setCenterUrlAttr

    • type
      Function
    • parameters:
      • urlOrObj: (typeof )
    • source: [view]
        this._setImage("center", urlOrObj);
    • summary
  • dojox.mobile.app.ImageView._setLeftUrlAttr

    • type
      Function
    • parameters:
      • urlOrObj: (typeof )
    • source: [view]
        this._setImage("left", urlOrObj);
    • summary
  • dojox.mobile.app.ImageView._setRightUrlAttr

    • type
      Function
    • parameters:
      • urlOrObj: (typeof )
    • source: [view]
        this._setImage("right", urlOrObj);
    • summary
  • dojox.mobile.app.ImageView._setImage

    • type
      Function
    • parameters:
      • name: (typeof )
      • urlOrObj: (typeof )
    • source: [view]
        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;
    • summary
  • dojox.mobile.app.ImageView.handleLoad

    • type
      Function
    • parameters:
      • evt: (typeof )
    • source: [view]
        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);
    • summary
      Handles the loading of an image, both the large and small
      versions.  A render is triggered as a result of each image load.
  • dojox.mobile.app.ImageView.onLoad

    • type
      Function
    • parameters:
      • type: (typeof String)
        The position of the image that has loaded, either
        &quot;center&quot;, &quot;left&quot; or &quot;right&quot;
      • url: (typeof String)
        The src of the image
      • isSmall: (typeof Boolean)
        True if it is a small version of the image that has loaded,
        false otherwise.
    • source: [view]
        // 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.
    • summary
      Dummy function that is called whenever an image loads.
  • dojox.mobile.app.ImageView.canvas

    • summary
  • dojox.mobile.app.ImageView.size

    • summary
  • dojox.mobile.app.ImageView.canvas.height

    • summary
  • dojox.mobile.app.ImageView.canvas.width

    • summary
  • dojox.mobile.app.ImageView.downX

    • summary
  • dojox.mobile.app.ImageView.panX

    • summary
  • dojox.mobile.app.ImageView._moveDir

    • summary
  • dojox.mobile.app.ImageView._centerImg._type

    • summary
  • dojox.mobile.app.ImageView._centerSmallImg._type

    • summary
  • dojox.mobile.app.ImageView._animCallback

    • summary
  • dojox.mobile.app.ImageView._anim

    • summary
  • dojox.mobile.app.ImageView.dispWidth

    • summary
  • dojox.mobile.app.ImageView.dispHeight

    • summary
  • dojox.mobile.app.ImageView.panY

    • summary
  • dojox.mobile.app

    • type
      Object
    • summary
  • dojox.mobile

    • type
      Object
    • summary
  • dojox

    • type
      Object
    • summary