OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * Viewport class controls the way the image is displayed (scale, offset etc). | 8 * Viewport class controls the way the image is displayed (scale, offset etc). |
9 * @constructor | 9 * @constructor |
10 */ | 10 */ |
11 function Viewport() { | 11 function Viewport() { |
mtomasz
2014/07/10 07:26:52
IIUC, you want to add "zooming by user" and "offse
hirono
2014/07/10 08:16:06
Yes, that is my plan.
| |
12 /** | |
13 * Size of the full resolution image. | |
14 * @type {Rect} | |
15 * @private | |
16 */ | |
12 this.imageBounds_ = new Rect(); | 17 this.imageBounds_ = new Rect(); |
18 | |
19 /** | |
20 * Size of the application window. | |
21 * @type {Rect} | |
22 * @private | |
23 */ | |
13 this.screenBounds_ = new Rect(); | 24 this.screenBounds_ = new Rect(); |
14 | 25 |
26 /** | |
27 * Scale from the full resolution image to the screen displayed image. This is | |
28 * not zoom operated by users. | |
29 */ | |
15 this.scale_ = 1; | 30 this.scale_ = 1; |
mtomasz
2014/07/10 07:26:52
nit: Is scale_, setScale and getFittingScale used?
hirono
2014/07/10 08:16:06
setScale uses it. getFittingScale actually does no
| |
16 this.offsetX_ = 0; | 31 this.offsetX_ = 0; |
mtomasz
2014/07/10 07:26:52
nit: Seems that offsetX and offsetY are not used?
hirono
2014/07/10 08:16:06
This is not used so far. But will start to use soo
| |
17 this.offsetY_ = 0; | 32 this.offsetY_ = 0; |
18 | 33 |
19 this.generation_ = 0; | 34 this.generation_ = 0; |
20 | 35 |
21 this.repaintCallbacks_ = []; | 36 this.repaintCallbacks_ = []; |
22 this.update(); | 37 this.update(); |
23 } | 38 } |
24 | 39 |
25 /* | |
26 * Viewport modification. | |
27 */ | |
28 | |
29 /** | 40 /** |
30 * @param {number} width Image width. | 41 * @param {number} width Image width. |
31 * @param {number} height Image height. | 42 * @param {number} height Image height. |
32 */ | 43 */ |
33 Viewport.prototype.setImageSize = function(width, height) { | 44 Viewport.prototype.setImageSize = function(width, height) { |
34 this.imageBounds_ = new Rect(width, height); | 45 this.imageBounds_ = new Rect(width, height); |
35 this.invalidateCaches(); | 46 this.invalidateCaches(); |
36 }; | 47 }; |
37 | 48 |
38 /** | 49 /** |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 Viewport.prototype.setScale = function(scale, notify) { | 90 Viewport.prototype.setScale = function(scale, notify) { |
80 if (this.scale_ == scale) return; | 91 if (this.scale_ == scale) return; |
81 this.scale_ = scale; | 92 this.scale_ = scale; |
82 this.invalidateCaches(); | 93 this.invalidateCaches(); |
83 }; | 94 }; |
84 | 95 |
85 /** | 96 /** |
86 * @return {number} Best scale to fit the current image into the current screen. | 97 * @return {number} Best scale to fit the current image into the current screen. |
87 */ | 98 */ |
88 Viewport.prototype.getFittingScale = function() { | 99 Viewport.prototype.getFittingScale = function() { |
89 var scaleX = this.screenBounds_.width / this.imageBounds_.width; | 100 return this.getFittingScaleForImageSize_( |
90 var scaleY = this.screenBounds_.height / this.imageBounds_.height; | 101 this.imageBounds_.width, this.imageBounds_.height); |
102 }; | |
103 | |
104 Viewport.prototype.getFittingScaleForImageSize_ = function(width, height) { | |
105 var scaleX = this.screenBounds_.width / width; | |
106 var scaleY = this.screenBounds_.height / height; | |
91 // Scales > (1 / this.getDevicePixelRatio()) do not look good. Also they are | 107 // Scales > (1 / this.getDevicePixelRatio()) do not look good. Also they are |
92 // not really useful as we do not have any pixel-level operations. | 108 // not really useful as we do not have any pixel-level operations. |
93 return Math.min(1 / Viewport.getDevicePixelRatio(), scaleX, scaleY); | 109 return Math.min(1 / devicePixelRatio, scaleX, scaleY); |
94 }; | 110 } |
95 | 111 |
96 /** | 112 /** |
97 * Set the scale to fit the image into the screen. | 113 * Set the scale to fit the image into the screen. |
98 */ | 114 */ |
99 Viewport.prototype.fitImage = function() { | 115 Viewport.prototype.fitImage = function() { |
100 var scale = this.getFittingScale(); | 116 var scale = this.getFittingScale(); |
101 this.setScale(scale, true); | 117 this.setScale(scale, true); |
102 }; | 118 }; |
103 | 119 |
104 /** | 120 /** |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 */ | 291 */ |
276 Viewport.prototype.imageToScreenRect = function(rect) { | 292 Viewport.prototype.imageToScreenRect = function(rect) { |
277 return new Rect( | 293 return new Rect( |
278 this.imageToScreenX(rect.left), | 294 this.imageToScreenX(rect.left), |
279 this.imageToScreenY(rect.top), | 295 this.imageToScreenY(rect.top), |
280 Math.round(this.imageToScreenSize(rect.width)), | 296 Math.round(this.imageToScreenSize(rect.width)), |
281 Math.round(this.imageToScreenSize(rect.height))); | 297 Math.round(this.imageToScreenSize(rect.height))); |
282 }; | 298 }; |
283 | 299 |
284 /** | 300 /** |
285 * @return {number} The number of physical pixels in one CSS pixel. | |
286 */ | |
287 Viewport.getDevicePixelRatio = function() { return window.devicePixelRatio; }; | |
288 | |
289 /** | |
290 * Convert a rectangle from screen coordinates to 'device' coordinates. | 301 * Convert a rectangle from screen coordinates to 'device' coordinates. |
291 * | 302 * |
292 * This conversion enlarges the original rectangle devicePixelRatio times | 303 * This conversion enlarges the original rectangle devicePixelRatio times |
293 * with the screen center as a fixed point. | 304 * with the screen center as a fixed point. |
294 * | 305 * |
295 * @param {Rect} rect Rectangle in screen coordinates. | 306 * @param {Rect} rect Rectangle in screen coordinates. |
296 * @return {Rect} Rectangle in device coordinates. | 307 * @return {Rect} Rectangle in device coordinates. |
297 */ | 308 */ |
298 Viewport.prototype.screenToDeviceRect = function(rect) { | 309 Viewport.prototype.screenToDeviceRect = function(rect) { |
299 var ratio = Viewport.getDevicePixelRatio(); | 310 var ratio = devicePixelRatio; |
300 var screenCenterX = Math.round( | 311 var screenCenterX = Math.round( |
301 this.screenBounds_.left + this.screenBounds_.width / 2); | 312 this.screenBounds_.left + this.screenBounds_.width / 2); |
302 var screenCenterY = Math.round( | 313 var screenCenterY = Math.round( |
303 this.screenBounds_.top + this.screenBounds_.height / 2); | 314 this.screenBounds_.top + this.screenBounds_.height / 2); |
304 return new Rect(screenCenterX + (rect.left - screenCenterX) * ratio, | 315 return new Rect(screenCenterX + (rect.left - screenCenterX) * ratio, |
305 screenCenterY + (rect.top - screenCenterY) * ratio, | 316 screenCenterY + (rect.top - screenCenterY) * ratio, |
306 rect.width * ratio, | 317 rect.width * ratio, |
307 rect.height * ratio); | 318 rect.height * ratio); |
308 }; | 319 }; |
309 | 320 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
410 }; | 421 }; |
411 | 422 |
412 /** | 423 /** |
413 * Repaint all clients. | 424 * Repaint all clients. |
414 */ | 425 */ |
415 Viewport.prototype.repaint = function() { | 426 Viewport.prototype.repaint = function() { |
416 this.update(); | 427 this.update(); |
417 for (var i = 0; i != this.repaintCallbacks_.length; i++) | 428 for (var i = 0; i != this.repaintCallbacks_.length; i++) |
418 this.repaintCallbacks_[i](); | 429 this.repaintCallbacks_[i](); |
419 }; | 430 }; |
431 | |
432 /** | |
433 * Obtains CSS transformation for the screen image. | |
434 * @return {string} Transformation description. | |
435 */ | |
436 Viewport.prototype.getTransformation = function() { | |
437 return 'scale(' + (1 / devicePixelRatio) + ')'; | |
438 }; | |
439 | |
440 /** | |
441 * Obtains shift CSS transformation for the screen image. | |
442 * @param {number} dx Amount of shift. | |
443 * @return {string} Transformation description. | |
444 */ | |
445 Viewport.prototype.getShiftTransformation = function(dx) { | |
446 return 'translateX(' + dx + 'px) ' + this.getTransformation(); | |
447 }; | |
448 | |
449 /** | |
450 * Obtains CSS transformation that makes the rotated image fit the original | |
451 * image. The new rotated image that the transformation is applied to looks the | |
452 * same with original image. | |
453 * | |
454 * @param {boolean} orientation Orientation of the rotation from the original | |
455 * image to the rotated image. True is for clockwise and false is for | |
456 * counterclockwise. | |
457 * @return {string} Transformation description. | |
458 */ | |
459 Viewport.prototype.getInverseTransformForRotatedImage = function(orientation) { | |
460 var previousImageWidth = this.imageBounds_.height; | |
461 var previousImageHeight = this.imageBounds_.width; | |
462 var oldScale = this.getFittingScaleForImageSize_( | |
463 previousImageWidth, previousImageHeight); | |
464 var scaleRatio = oldScale / this.getScale(); | |
465 var degree = orientation ? '-90deg' : '90deg'; | |
466 return [ | |
467 'scale(' + (scaleRatio) + ')', | |
468 'rotate(' + degree + ')', | |
469 this.getTransformation() | |
470 ].join(' '); | |
471 }; | |
472 | |
473 /** | |
474 * Obtains CSS transformation that makes the cropped image fit the original | |
475 * image. The new cropped image that the transformaton is applied to fits to the | |
476 * the cropped rectangle in the original image. | |
477 * | |
478 * @param {number} imageWidth Width of the original image. | |
479 * @param {number} imageHeight Height of the origianl image. | |
480 * @param {Rect} imageCropRect Crop rectangle in the image's coordinate system. | |
481 * @return {string} Transformation description. | |
482 */ | |
483 Viewport.prototype.getInverseTransformForCroppedImage = | |
484 function(imageWidth, imageHeight, imageCropRect) { | |
485 var wholeScale = this.getFittingScaleForImageSize_( | |
486 imageWidth, imageHeight); | |
487 var croppedScale = this.getFittingScaleForImageSize_( | |
488 imageCropRect.width, imageCropRect.height); | |
489 var dx = | |
490 (imageCropRect.left + imageCropRect.width / 2 - imageWidth / 2) * | |
491 wholeScale; | |
492 var dy = | |
493 (imageCropRect.top + imageCropRect.height / 2 - imageHeight / 2) * | |
494 wholeScale; | |
495 return [ | |
496 'translate(' + dx + 'px,' + dy + 'px)', | |
497 'scale(' + wholeScale / croppedScale + ')', | |
498 this.getTransformation() | |
499 ].join(' '); | |
500 }; | |
501 | |
502 /** | |
503 * Obtains CSS transformaton that makes the image fit to the screen rectangle. | |
504 * | |
505 * @param {Rect} screenRect Screen rectangle. | |
506 * @return {string} Transformation description. | |
507 */ | |
508 Viewport.prototype.getScreenRectTransformForImage = function(screenRect) { | |
509 var screenImageWidth = this.imageBounds_.width * this.getScale(); | |
510 var screenImageHeight = this.imageBounds_.height * this.getScale(); | |
511 var scaleX = screenRect.width / screenImageWidth; | |
512 var scaleY = screenRect.height /screenImageHeight; | |
513 var screenWidth = this.screenBounds_.width; | |
514 var screenHeight = this.screenBounds_.height; | |
515 var dx = screenRect.left + screenRect.width / 2 - screenWidth / 2; | |
516 var dy = screenRect.top + screenRect.height / 2 - screenHeight / 2; | |
517 return [ | |
518 'translate(' + dx + 'px,' + dy + 'px)', | |
519 'scale(' + scaleX + ',' + scaleY + ')', | |
520 this.getTransformation() | |
521 ].join(' '); | |
522 }; | |
OLD | NEW |