ImageView.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.mobile.app.ImageView"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.mobile.app.ImageView"] = true;
  8. dojo.provide("dojox.mobile.app.ImageView");
  9. dojo.experimental("dojox.mobile.app.ImageView");
  10. dojo.require("dojox.mobile.app._Widget");
  11. dojo.require("dojo.fx.easing");
  12. dojo.declare("dojox.mobile.app.ImageView", dojox.mobile.app._Widget, {
  13. // zoom: Number
  14. // The current level of zoom. This should not be set manually.
  15. zoom: 1,
  16. // zoomCenterX: Number
  17. // The X coordinate in the image where the zoom is focused
  18. zoomCenterX: 0,
  19. // zoomCenterY: Number
  20. // The Y coordinate in the image where the zoom is focused
  21. zoomCenterY: 0,
  22. // maxZoom: Number
  23. // The highest degree to which an image can be zoomed. For example,
  24. // a maxZoom of 5 means that the image will be 5 times larger than normal
  25. maxZoom: 5,
  26. // autoZoomLevel: Number
  27. // The degree to which the image is zoomed when auto zoom is invoked.
  28. // The higher the number, the more the image is zoomed in.
  29. autoZoomLevel: 3,
  30. // disableAutoZoom: Boolean
  31. // Disables auto zoom
  32. disableAutoZoom: false,
  33. // disableSwipe: Boolean
  34. // Disables the users ability to swipe from one image to the next.
  35. disableSwipe: false,
  36. // autoZoomEvent: String
  37. // Overrides the default event listened to which invokes auto zoom
  38. autoZoomEvent: null,
  39. // _leftImg: Node
  40. // The full sized image to the left
  41. _leftImg: null,
  42. // _centerImg: Node
  43. // The full sized image in the center
  44. _centerImg: null,
  45. // _rightImg: Node
  46. // The full sized image to the right
  47. _rightImg: null,
  48. // _leftImg: Node
  49. // The small sized image to the left
  50. _leftSmallImg: null,
  51. // _centerImg: Node
  52. // The small sized image in the center
  53. _centerSmallImg: null,
  54. // _rightImg: Node
  55. // The small sized image to the right
  56. _rightSmallImg: null,
  57. constructor: function(){
  58. this.panX = 0;
  59. this.panY = 0;
  60. this.handleLoad = dojo.hitch(this, this.handleLoad);
  61. this._updateAnimatedZoom = dojo.hitch(this, this._updateAnimatedZoom);
  62. this._updateAnimatedPan = dojo.hitch(this, this._updateAnimatedPan);
  63. this._onAnimPanEnd = dojo.hitch(this, this._onAnimPanEnd);
  64. },
  65. buildRendering: function(){
  66. this.inherited(arguments);
  67. this.canvas = dojo.create("canvas", {}, this.domNode);
  68. dojo.addClass(this.domNode, "mblImageView");
  69. },
  70. postCreate: function(){
  71. this.inherited(arguments);
  72. this.size = dojo.marginBox(this.domNode);
  73. dojo.style(this.canvas, {
  74. width: this.size.w + "px",
  75. height: this.size.h + "px"
  76. });
  77. this.canvas.height = this.size.h;
  78. this.canvas.width = this.size.w;
  79. var _this = this;
  80. // Listen to the mousedown/touchstart event. Record the position
  81. // so we can use it to pan the image.
  82. this.connect(this.domNode, "onmousedown", function(event){
  83. if(_this.isAnimating()){
  84. return;
  85. }
  86. if(_this.panX){
  87. _this.handleDragEnd();
  88. }
  89. _this.downX = event.targetTouches ? event.targetTouches[0].clientX : event.clientX;
  90. _this.downY = event.targetTouches ? event.targetTouches[0].clientY : event.clientY;
  91. });
  92. // record the movement of the mouse.
  93. this.connect(this.domNode, "onmousemove", function(event){
  94. if(_this.isAnimating()){
  95. return;
  96. }
  97. if((!_this.downX && _this.downX !== 0) || (!_this.downY && _this.downY !== 0)){
  98. // If the touch didn't begin on this widget, ignore the movement
  99. return;
  100. }
  101. if((!_this.disableSwipe && _this.zoom == 1)
  102. || (!_this.disableAutoZoom && _this.zoom != 1)){
  103. var x = event.targetTouches ?
  104. event.targetTouches[0].clientX : event.pageX;
  105. var y = event.targetTouches ?
  106. event.targetTouches[0].clientY : event.pageY;
  107. _this.panX = x - _this.downX;
  108. _this.panY = y - _this.downY;
  109. if(_this.zoom == 1){
  110. // If not zoomed in, then try to move to the next or prev image
  111. // but only if the mouse has moved more than 10 pixels
  112. // in the X direction
  113. if(Math.abs(_this.panX) > 10){
  114. _this.render();
  115. }
  116. }else{
  117. // If zoomed in, pan the image if the mouse has moved more
  118. // than 10 pixels in either direction.
  119. if(Math.abs(_this.panX) > 10 || Math.abs(_this.panY) > 10){
  120. _this.render();
  121. }
  122. }
  123. }
  124. });
  125. this.connect(this.domNode, "onmouseout", function(event){
  126. if(!_this.isAnimating() && _this.panX){
  127. _this.handleDragEnd();
  128. }
  129. });
  130. this.connect(this.domNode, "onmouseover", function(event){
  131. _this.downX = _this.downY = null;
  132. });
  133. // Set up AutoZoom, which zooms in a fixed amount when the user taps
  134. // a part of the canvas
  135. this.connect(this.domNode, "onclick", function(event){
  136. if(_this.isAnimating()){
  137. return;
  138. }
  139. if(_this.downX == null || _this.downY == null){
  140. return;
  141. }
  142. var x = (event.targetTouches ?
  143. event.targetTouches[0].clientX : event.pageX);
  144. var y = (event.targetTouches ?
  145. event.targetTouches[0].clientY : event.pageY);
  146. // If the mouse/finger has moved more than 14 pixels from where it
  147. // started, do not treat it as a click. It is a drag.
  148. if(Math.abs(_this.panX) > 14 || Math.abs(_this.panY) > 14){
  149. _this.downX = _this.downY = null;
  150. _this.handleDragEnd();
  151. return;
  152. }
  153. _this.downX = _this.downY = null;
  154. if(!_this.disableAutoZoom){
  155. if(!_this._centerImg || !_this._centerImg._loaded){
  156. // Do nothing until the image is loaded
  157. return;
  158. }
  159. if(_this.zoom != 1){
  160. _this.set("animatedZoom", 1);
  161. return;
  162. }
  163. var pos = dojo._abs(_this.domNode);
  164. // Translate the clicked point to a point on the source image
  165. var xRatio = _this.size.w / _this._centerImg.width;
  166. var yRatio = _this.size.h / _this._centerImg.height;
  167. // Do an animated zoom to the point which was clicked.
  168. _this.zoomTo(
  169. ((x - pos.x) / xRatio) - _this.panX,
  170. ((y - pos.y) / yRatio) - _this.panY,
  171. _this.autoZoomLevel);
  172. }
  173. });
  174. // Listen for Flick events
  175. dojo.connect(this.domNode, "flick", this, "handleFlick");
  176. },
  177. isAnimating: function(){
  178. // summary:
  179. // Returns true if an animation is in progress, false otherwise.
  180. return this._anim && this._anim.status() == "playing";
  181. },
  182. handleDragEnd: function(){
  183. // summary:
  184. // Handles the end of a dragging event. If not zoomed in, it
  185. // determines if the next or previous image should be transitioned
  186. // to.
  187. this.downX = this.downY = null;
  188. console.log("handleDragEnd");
  189. if(this.zoom == 1){
  190. if(!this.panX){
  191. return;
  192. }
  193. var leftLoaded = (this._leftImg && this._leftImg._loaded)
  194. || (this._leftSmallImg && this._leftSmallImg._loaded);
  195. var rightLoaded = (this._rightImg && this._rightImg._loaded)
  196. || (this._rightSmallImg && this._rightSmallImg._loaded);
  197. // Check if the drag has moved the image more than half its length.
  198. // If so, move to either the previous or next image.
  199. var doMove =
  200. !(Math.abs(this.panX) < this._centerImg._baseWidth / 2) &&
  201. (
  202. (this.panX > 0 && leftLoaded ? 1 : 0) ||
  203. (this.panX < 0 && rightLoaded ? 1 : 0)
  204. );
  205. if(!doMove){
  206. // If not moving to another image, animate the sliding of the
  207. // image back into place.
  208. this._animPanTo(0, dojo.fx.easing.expoOut, 700);
  209. }else{
  210. // Move to another image.
  211. this.moveTo(this.panX);
  212. }
  213. }else{
  214. if(!this.panX && !this.panY){
  215. return;
  216. }
  217. // Recenter the zoomed image based on where it was panned to
  218. // previously
  219. this.zoomCenterX -= (this.panX / this.zoom);
  220. this.zoomCenterY -= (this.panY / this.zoom);
  221. this.panX = this.panY = 0;
  222. }
  223. },
  224. handleFlick: function(event){
  225. // summary:
  226. // Handle a flick event.
  227. if(this.zoom == 1 && event.duration < 500){
  228. // Only handle quick flicks here, less than 0.5 seconds
  229. // If not zoomed in, then check if we should move to the next photo
  230. // or not
  231. if(event.direction == "ltr"){
  232. this.moveTo(1);
  233. }else if(event.direction == "rtl"){
  234. this.moveTo(-1);
  235. }
  236. // If an up or down flick occurs, it means nothing so ignore it
  237. this.downX = this.downY = null;
  238. }
  239. },
  240. moveTo: function(direction){
  241. direction = direction > 0 ? 1 : -1;
  242. var toImg;
  243. if(direction < 1){
  244. if(this._rightImg && this._rightImg._loaded){
  245. toImg = this._rightImg;
  246. }else if(this._rightSmallImg && this._rightSmallImg._loaded){
  247. toImg = this._rightSmallImg;
  248. }
  249. }else{
  250. if(this._leftImg && this._leftImg._loaded){
  251. toImg = this._leftImg;
  252. }else if(this._leftSmallImg && this._leftSmallImg._loaded){
  253. toImg = this._leftSmallImg;
  254. }
  255. }
  256. this._moveDir = direction;
  257. var _this = this;
  258. if(toImg && toImg._loaded){
  259. // If the image is loaded, make a linear animation to show it
  260. this._animPanTo(this.size.w * direction, null, 500, function(){
  261. _this.panX = 0;
  262. _this.panY = 0;
  263. if(direction < 0){
  264. // Moving to show the right image
  265. _this._switchImage("left", "right");
  266. }else{
  267. // Moving to show the left image
  268. _this._switchImage("right", "left");
  269. }
  270. _this.render();
  271. _this.onChange(direction * -1);
  272. });
  273. }else{
  274. // If the next image is not loaded, make an animation to
  275. // move the center image to half the width of the widget and back
  276. // again
  277. console.log("moveTo image not loaded!", toImg);
  278. this._animPanTo(0, dojo.fx.easing.expoOut, 700);
  279. }
  280. },
  281. _switchImage: function(toImg, fromImg){
  282. var toSmallImgName = "_" + toImg + "SmallImg";
  283. var toImgName = "_" + toImg + "Img";
  284. var fromSmallImgName = "_" + fromImg + "SmallImg";
  285. var fromImgName = "_" + fromImg + "Img";
  286. this[toImgName] = this._centerImg;
  287. this[toSmallImgName] = this._centerSmallImg;
  288. this[toImgName]._type = toImg;
  289. if(this[toSmallImgName]){
  290. this[toSmallImgName]._type = toImg;
  291. }
  292. this._centerImg = this[fromImgName];
  293. this._centerSmallImg = this[fromSmallImgName];
  294. this._centerImg._type = "center";
  295. if(this._centerSmallImg){
  296. this._centerSmallImg._type = "center";
  297. }
  298. this[fromImgName] = this[fromSmallImgName] = null;
  299. },
  300. _animPanTo: function(to, easing, duration, callback){
  301. this._animCallback = callback;
  302. this._anim = new dojo.Animation({
  303. curve: [this.panX, to],
  304. onAnimate: this._updateAnimatedPan,
  305. duration: duration || 500,
  306. easing: easing,
  307. onEnd: this._onAnimPanEnd
  308. });
  309. this._anim.play();
  310. return this._anim;
  311. },
  312. onChange: function(direction){
  313. // summary:
  314. // Stub function that can be listened to in order to provide
  315. // new images when the displayed image changes
  316. },
  317. _updateAnimatedPan: function(amount){
  318. this.panX = amount;
  319. this.render();
  320. },
  321. _onAnimPanEnd: function(){
  322. this.panX = this.panY = 0;
  323. if(this._animCallback){
  324. this._animCallback();
  325. }
  326. },
  327. zoomTo: function(centerX, centerY, zoom){
  328. this.set("zoomCenterX", centerX);
  329. this.set("zoomCenterY", centerY);
  330. this.set("animatedZoom", zoom);
  331. },
  332. render: function(){
  333. var cxt = this.canvas.getContext('2d');
  334. cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  335. // Render the center image
  336. this._renderImg(
  337. this._centerSmallImg,
  338. this._centerImg,
  339. this.zoom == 1 ? (this.panX < 0 ? 1 : this.panX > 0 ? -1 : 0) : 0);
  340. if(this.zoom == 1 && this.panX != 0){
  341. if(this.panX > 0){
  342. // Render the left image, showing the right side of it
  343. this._renderImg(this._leftSmallImg, this._leftImg, 1);
  344. }else{
  345. // Render the right image, showing the left side of it
  346. this._renderImg(this._rightSmallImg, this._rightImg, -1);
  347. }
  348. }
  349. },
  350. _renderImg: function(smallImg, largeImg, panDir){
  351. // summary:
  352. // Renders a single image
  353. // If zoomed, we just display the center img
  354. var img = (largeImg && largeImg._loaded) ? largeImg : smallImg;
  355. if(!img || !img._loaded){
  356. // If neither the large or small image is loaded, display nothing
  357. return;
  358. }
  359. var cxt = this.canvas.getContext('2d');
  360. var baseWidth = img._baseWidth;
  361. var baseHeight = img._baseHeight;
  362. // Calculate the size the image would be if there were no bounds
  363. var desiredWidth = baseWidth * this.zoom;
  364. var desiredHeight = baseHeight * this.zoom;
  365. // Calculate the actual size of the viewable image
  366. var destWidth = Math.min(this.size.w, desiredWidth);
  367. var destHeight = Math.min(this.size.h, desiredHeight);
  368. // Calculate the size of the window on the original image to use
  369. var sourceWidth = this.dispWidth = img.width * (destWidth / desiredWidth);
  370. var sourceHeight = this.dispHeight = img.height * (destHeight / desiredHeight);
  371. var zoomCenterX = this.zoomCenterX - (this.panX / this.zoom);
  372. var zoomCenterY = this.zoomCenterY - (this.panY / this.zoom);
  373. // Calculate where the center of the view should be
  374. var centerX = Math.floor(Math.max(sourceWidth / 2,
  375. Math.min(img.width - sourceWidth / 2, zoomCenterX)));
  376. var centerY = Math.floor(Math.max(sourceHeight / 2,
  377. Math.min(img.height - sourceHeight / 2, zoomCenterY)));
  378. var sourceX = Math.max(0,
  379. Math.round((img.width - sourceWidth)/2 + (centerX - img._centerX)) );
  380. var sourceY = Math.max(0,
  381. Math.round((img.height - sourceHeight) / 2 + (centerY - img._centerY))
  382. );
  383. var destX = Math.round(Math.max(0, this.canvas.width - destWidth)/2);
  384. var destY = Math.round(Math.max(0, this.canvas.height - destHeight)/2);
  385. var oldDestWidth = destWidth;
  386. var oldSourceWidth = sourceWidth;
  387. if(this.zoom == 1 && panDir && this.panX){
  388. if(this.panX < 0){
  389. if(panDir > 0){
  390. // If the touch is moving left, and the right side of the
  391. // image should be shown, then reduce the destination width
  392. // by the absolute value of panX
  393. destWidth -= Math.abs(this.panX);
  394. destX = 0;
  395. }else if(panDir < 0){
  396. // If the touch is moving left, and the left side of the
  397. // image should be shown, then set the displayed width
  398. // to the absolute value of panX, less some pixels for
  399. // a padding between images
  400. destWidth = Math.max(1, Math.abs(this.panX) - 5);
  401. destX = this.size.w - destWidth;
  402. }
  403. }else{
  404. if(panDir > 0){
  405. // If the touch is moving right, and the right side of the
  406. // image should be shown, then set the destination width
  407. // to the absolute value of the pan, less some pixels for
  408. // padding
  409. destWidth = Math.max(1, Math.abs(this.panX) - 5);
  410. destX = 0;
  411. }else if(panDir < 0){
  412. // If the touch is moving right, and the left side of the
  413. // image should be shown, then reduce the destination width
  414. // by the widget width minus the absolute value of panX
  415. destWidth -= Math.abs(this.panX);
  416. destX = this.size.w - destWidth;
  417. }
  418. }
  419. sourceWidth = Math.max(1,
  420. Math.floor(sourceWidth * (destWidth / oldDestWidth)));
  421. if(panDir > 0){
  422. // If the right side of the image should be displayed, move
  423. // the sourceX to be the width of the image minus the difference
  424. // between the original sourceWidth and the new sourceWidth
  425. sourceX = (sourceX + oldSourceWidth) - (sourceWidth);
  426. }
  427. sourceX = Math.floor(sourceX);
  428. }
  429. try{
  430. // See https://developer.mozilla.org/en/Canvas_tutorial/Using_images
  431. cxt.drawImage(
  432. img,
  433. Math.max(0, sourceX),
  434. sourceY,
  435. Math.min(oldSourceWidth, sourceWidth),
  436. sourceHeight,
  437. destX, // Xpos
  438. destY, // Ypos
  439. Math.min(oldDestWidth, destWidth),
  440. destHeight
  441. );
  442. }catch(e){
  443. console.log("Caught Error",e,
  444. "type=", img._type,
  445. "oldDestWidth = ", oldDestWidth,
  446. "destWidth", destWidth,
  447. "destX", destX
  448. , "oldSourceWidth=",oldSourceWidth,
  449. "sourceWidth=", sourceWidth,
  450. "sourceX = " + sourceX
  451. );
  452. }
  453. },
  454. _setZoomAttr: function(amount){
  455. this.zoom = Math.min(this.maxZoom, Math.max(1, amount));
  456. if(this.zoom == 1
  457. && this._centerImg
  458. && this._centerImg._loaded){
  459. if(!this.isAnimating()){
  460. this.zoomCenterX = this._centerImg.width / 2;
  461. this.zoomCenterY = this._centerImg.height / 2;
  462. }
  463. this.panX = this.panY = 0;
  464. }
  465. this.render();
  466. },
  467. _setZoomCenterXAttr: function(value){
  468. if(value != this.zoomCenterX){
  469. if(this._centerImg && this._centerImg._loaded){
  470. value = Math.min(this._centerImg.width, value);
  471. }
  472. this.zoomCenterX = Math.max(0, Math.round(value));
  473. }
  474. },
  475. _setZoomCenterYAttr: function(value){
  476. if(value != this.zoomCenterY){
  477. if(this._centerImg && this._centerImg._loaded){
  478. value = Math.min(this._centerImg.height, value);
  479. }
  480. this.zoomCenterY = Math.max(0, Math.round(value));
  481. }
  482. },
  483. _setZoomCenterAttr: function(value){
  484. if(value.x != this.zoomCenterX || value.y != this.zoomCenterY){
  485. this.set("zoomCenterX", value.x);
  486. this.set("zoomCenterY", value.y);
  487. this.render();
  488. }
  489. },
  490. _setAnimatedZoomAttr: function(amount){
  491. if(this._anim && this._anim.status() == "playing"){
  492. return;
  493. }
  494. this._anim = new dojo.Animation({
  495. curve: [this.zoom, amount],
  496. onAnimate: this._updateAnimatedZoom,
  497. onEnd: this._onAnimEnd
  498. });
  499. this._anim.play();
  500. },
  501. _updateAnimatedZoom: function(amount){
  502. this._setZoomAttr(amount);
  503. },
  504. _setCenterUrlAttr: function(urlOrObj){
  505. this._setImage("center", urlOrObj);
  506. },
  507. _setLeftUrlAttr: function(urlOrObj){
  508. this._setImage("left", urlOrObj);
  509. },
  510. _setRightUrlAttr: function(urlOrObj){
  511. this._setImage("right", urlOrObj);
  512. },
  513. _setImage: function(name, urlOrObj){
  514. var smallUrl = null;
  515. var largeUrl = null;
  516. if(dojo.isString(urlOrObj)){
  517. // If the argument is a string, then just load the large url
  518. largeUrl = urlOrObj;
  519. }else{
  520. largeUrl = urlOrObj.large;
  521. smallUrl = urlOrObj.small;
  522. }
  523. if(this["_" + name + "Img"] && this["_" + name + "Img"]._src == largeUrl){
  524. // Identical URL, ignore it
  525. return;
  526. }
  527. // Just do the large image for now
  528. var largeImg = this["_" + name + "Img"] = new Image();
  529. largeImg._type = name;
  530. largeImg._loaded = false;
  531. largeImg._src = largeUrl;
  532. largeImg._conn = dojo.connect(largeImg, "onload", this.handleLoad);
  533. if(smallUrl){
  534. // If a url to a small version of the image has been provided,
  535. // load that image first.
  536. var smallImg = this["_" + name + "SmallImg"] = new Image();
  537. smallImg._type = name;
  538. smallImg._loaded = false;
  539. smallImg._conn = dojo.connect(smallImg, "onload", this.handleLoad);
  540. smallImg._isSmall = true;
  541. smallImg._src = smallUrl;
  542. smallImg.src = smallUrl;
  543. }
  544. // It's important that the large url's src is set after the small image
  545. // to ensure it's loaded second.
  546. largeImg.src = largeUrl;
  547. },
  548. handleLoad: function(evt){
  549. // summary:
  550. // Handles the loading of an image, both the large and small
  551. // versions. A render is triggered as a result of each image load.
  552. var img = evt.target;
  553. img._loaded = true;
  554. dojo.disconnect(img._conn);
  555. var type = img._type;
  556. switch(type){
  557. case "center":
  558. this.zoomCenterX = img.width / 2;
  559. this.zoomCenterY = img.height / 2;
  560. break;
  561. }
  562. var height = img.height;
  563. var width = img.width;
  564. if(width / this.size.w < height / this.size.h){
  565. // Fit the height to the height of the canvas
  566. img._baseHeight = this.canvas.height;
  567. img._baseWidth = width / (height / this.size.h);
  568. }else{
  569. // Fix the width to the width of the canvas
  570. img._baseWidth = this.canvas.width;
  571. img._baseHeight = height / (width / this.size.w);
  572. }
  573. img._centerX = width / 2;
  574. img._centerY = height / 2;
  575. this.render();
  576. this.onLoad(img._type, img._src, img._isSmall);
  577. },
  578. onLoad: function(type, url, isSmall){
  579. // summary:
  580. // Dummy function that is called whenever an image loads.
  581. // type: String
  582. // The position of the image that has loaded, either
  583. // "center", "left" or "right"
  584. // url: String
  585. // The src of the image
  586. // isSmall: Boolean
  587. // True if it is a small version of the image that has loaded,
  588. // false otherwise.
  589. }
  590. });
  591. }