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() { |
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 */ | |
mtomasz
2014/07/10 07:26:52
optional: // for normal comments, /** ... */ for j
hirono
2014/07/10 08:16:06
Done.
| |
15 this.scale_ = 1; | 30 this.scale_ = 1; |
16 this.offsetX_ = 0; | 31 this.offsetX_ = 0; |
17 this.offsetY_ = 0; | 32 this.offsetY_ = 0; |
18 | 33 |
19 this.generation_ = 0; | 34 this.generation_ = 0; |
20 | 35 |
21 this.scaleControl_ = null; | |
22 this.repaintCallbacks_ = []; | 36 this.repaintCallbacks_ = []; |
23 this.update(); | 37 this.update(); |
24 } | 38 } |
25 | 39 |
26 /* | |
27 * Viewport modification. | |
28 */ | |
29 | |
30 /** | |
31 * @param {Object} scaleControl The UI object responsible for scaling. | |
32 */ | |
33 Viewport.prototype.setScaleControl = function(scaleControl) { | |
34 this.scaleControl_ = scaleControl; | |
35 }; | |
36 | |
37 /** | 40 /** |
38 * @param {number} width Image width. | 41 * @param {number} width Image width. |
39 * @param {number} height Image height. | 42 * @param {number} height Image height. |
40 */ | 43 */ |
41 Viewport.prototype.setImageSize = function(width, height) { | 44 Viewport.prototype.setImageSize = function(width, height) { |
42 this.imageBounds_ = new Rect(width, height); | 45 this.imageBounds_ = new Rect(width, height); |
43 if (this.scaleControl_) this.scaleControl_.displayImageSize(width, height); | |
44 this.invalidateCaches(); | 46 this.invalidateCaches(); |
45 }; | 47 }; |
46 | 48 |
47 /** | 49 /** |
48 * @param {number} width Screen width. | 50 * @param {number} width Screen width. |
49 * @param {number} height Screen height. | 51 * @param {number} height Screen height. |
50 */ | 52 */ |
51 Viewport.prototype.setScreenSize = function(width, height) { | 53 Viewport.prototype.setScreenSize = function(width, height) { |
52 this.screenBounds_ = new Rect(width, height); | 54 this.screenBounds_ = new Rect(width, height); |
53 if (this.scaleControl_) | |
54 this.scaleControl_.setMinScale(this.getFittingScale()); | |
55 this.invalidateCaches(); | 55 this.invalidateCaches(); |
56 }; | 56 }; |
57 | 57 |
58 /** | 58 /** |
59 * Set the size by an HTML element. | 59 * Set the size by an HTML element. |
60 * | 60 * |
61 * @param {HTMLElement} frame The element acting as the "screen". | 61 * @param {HTMLElement} frame The element acting as the "screen". |
62 */ | 62 */ |
63 Viewport.prototype.sizeByFrame = function(frame) { | 63 Viewport.prototype.sizeByFrame = function(frame) { |
64 this.setScreenSize(frame.clientWidth, frame.clientHeight); | 64 this.setScreenSize(frame.clientWidth, frame.clientHeight); |
(...skipping 18 matching lines...) Expand all Loading... | |
83 */ | 83 */ |
84 Viewport.prototype.getScale = function() { return this.scale_; }; | 84 Viewport.prototype.getScale = function() { return this.scale_; }; |
85 | 85 |
86 /** | 86 /** |
87 * @param {number} scale The new scale. | 87 * @param {number} scale The new scale. |
88 * @param {boolean} notify True if the change should be reflected in the UI. | 88 * @param {boolean} notify True if the change should be reflected in the UI. |
89 */ | 89 */ |
90 Viewport.prototype.setScale = function(scale, notify) { | 90 Viewport.prototype.setScale = function(scale, notify) { |
91 if (this.scale_ == scale) return; | 91 if (this.scale_ == scale) return; |
92 this.scale_ = scale; | 92 this.scale_ = scale; |
93 if (notify && this.scaleControl_) this.scaleControl_.displayScale(scale); | |
94 this.invalidateCaches(); | 93 this.invalidateCaches(); |
95 }; | 94 }; |
96 | 95 |
97 /** | 96 /** |
98 * @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. |
99 */ | 98 */ |
100 Viewport.prototype.getFittingScale = function() { | 99 Viewport.prototype.getFittingScale = function() { |
101 var scaleX = this.screenBounds_.width / this.imageBounds_.width; | 100 return this.getFittingScaleForImageSize_( |
102 var scaleY = this.screenBounds_.height / this.imageBounds_.height; | 101 this.imageBounds_.width, this.imageBounds_.height); |
102 }; | |
103 | |
104 Viewport.prototype.getFittingScaleForImageSize_ = function(width, height) { | |
mtomasz
2014/07/10 07:26:52
nit: Please add jsdoc.
hirono
2014/07/10 08:16:05
Done.
| |
105 var scaleX = this.screenBounds_.width / width; | |
106 var scaleY = this.screenBounds_.height / height; | |
103 // Scales > (1 / this.getDevicePixelRatio()) do not look good. Also they are | 107 // Scales > (1 / this.getDevicePixelRatio()) do not look good. Also they are |
mtomasz
2014/07/10 07:26:52
Please update the comment (this.getDevicePixelRati
hirono
2014/07/10 08:16:06
Done.
| |
104 // 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. |
105 return Math.min(1 / Viewport.getDevicePixelRatio(), scaleX, scaleY); | 109 return Math.min(1 / devicePixelRatio, scaleX, scaleY); |
mtomasz
2014/07/10 07:26:52
nit: devicePixelRatio looks undefined. How about:
hirono
2014/07/10 08:16:06
Done.
| |
106 }; | 110 } |
107 | 111 |
108 /** | 112 /** |
109 * Set the scale to fit the image into the screen. | 113 * Set the scale to fit the image into the screen. |
110 */ | 114 */ |
111 Viewport.prototype.fitImage = function() { | 115 Viewport.prototype.fitImage = function() { |
112 var scale = this.getFittingScale(); | 116 var scale = this.getFittingScale(); |
113 if (this.scaleControl_) this.scaleControl_.setMinScale(scale); | |
114 this.setScale(scale, true); | 117 this.setScale(scale, true); |
115 }; | 118 }; |
116 | 119 |
117 /** | 120 /** |
118 * @return {number} X-offset of the viewport. | 121 * @return {number} X-offset of the viewport. |
119 */ | 122 */ |
120 Viewport.prototype.getOffsetX = function() { return this.offsetX_; }; | 123 Viewport.prototype.getOffsetX = function() { return this.offsetX_; }; |
121 | 124 |
122 /** | 125 /** |
123 * @return {number} Y-offset of the viewport. | 126 * @return {number} Y-offset of the viewport. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 */ | 291 */ |
289 Viewport.prototype.imageToScreenRect = function(rect) { | 292 Viewport.prototype.imageToScreenRect = function(rect) { |
290 return new Rect( | 293 return new Rect( |
291 this.imageToScreenX(rect.left), | 294 this.imageToScreenX(rect.left), |
292 this.imageToScreenY(rect.top), | 295 this.imageToScreenY(rect.top), |
293 Math.round(this.imageToScreenSize(rect.width)), | 296 Math.round(this.imageToScreenSize(rect.width)), |
294 Math.round(this.imageToScreenSize(rect.height))); | 297 Math.round(this.imageToScreenSize(rect.height))); |
295 }; | 298 }; |
296 | 299 |
297 /** | 300 /** |
298 * @return {number} The number of physical pixels in one CSS pixel. | |
299 */ | |
300 Viewport.getDevicePixelRatio = function() { return window.devicePixelRatio; }; | |
301 | |
302 /** | |
303 * Convert a rectangle from screen coordinates to 'device' coordinates. | 301 * Convert a rectangle from screen coordinates to 'device' coordinates. |
304 * | 302 * |
305 * This conversion enlarges the original rectangle devicePixelRatio times | 303 * This conversion enlarges the original rectangle devicePixelRatio times |
306 * with the screen center as a fixed point. | 304 * with the screen center as a fixed point. |
307 * | 305 * |
308 * @param {Rect} rect Rectangle in screen coordinates. | 306 * @param {Rect} rect Rectangle in screen coordinates. |
309 * @return {Rect} Rectangle in device coordinates. | 307 * @return {Rect} Rectangle in device coordinates. |
310 */ | 308 */ |
311 Viewport.prototype.screenToDeviceRect = function(rect) { | 309 Viewport.prototype.screenToDeviceRect = function(rect) { |
312 var ratio = Viewport.getDevicePixelRatio(); | 310 var ratio = devicePixelRatio; |
313 var screenCenterX = Math.round( | 311 var screenCenterX = Math.round( |
314 this.screenBounds_.left + this.screenBounds_.width / 2); | 312 this.screenBounds_.left + this.screenBounds_.width / 2); |
315 var screenCenterY = Math.round( | 313 var screenCenterY = Math.round( |
316 this.screenBounds_.top + this.screenBounds_.height / 2); | 314 this.screenBounds_.top + this.screenBounds_.height / 2); |
317 return new Rect(screenCenterX + (rect.left - screenCenterX) * ratio, | 315 return new Rect(screenCenterX + (rect.left - screenCenterX) * ratio, |
318 screenCenterY + (rect.top - screenCenterY) * ratio, | 316 screenCenterY + (rect.top - screenCenterY) * ratio, |
319 rect.width * ratio, | 317 rect.width * ratio, |
320 rect.height * ratio); | 318 rect.height * ratio); |
321 }; | 319 }; |
322 | 320 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
423 }; | 421 }; |
424 | 422 |
425 /** | 423 /** |
426 * Repaint all clients. | 424 * Repaint all clients. |
427 */ | 425 */ |
428 Viewport.prototype.repaint = function() { | 426 Viewport.prototype.repaint = function() { |
429 this.update(); | 427 this.update(); |
430 for (var i = 0; i != this.repaintCallbacks_.length; i++) | 428 for (var i = 0; i != this.repaintCallbacks_.length; i++) |
431 this.repaintCallbacks_[i](); | 429 this.repaintCallbacks_[i](); |
432 }; | 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) + ')', | |
mtomasz
2014/07/10 07:26:52
nit: inner () redundant?
hirono
2014/07/10 08:16:06
Done.
| |
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; | |
mtomasz
2014/07/10 07:26:52
nit: space after '/'.
hirono
2014/07/10 08:16:06
Done.
| |
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 |