Chromium Code Reviews| 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 * The overlay displaying the image. | 8 * The overlay displaying the image. |
| 9 * | 9 * |
| 10 * @param {HTMLElement} container The container element. | 10 * @param {HTMLElement} container The container element. |
| (...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 element.style.webkitTransitionDuration = opt_duration + 'ms'; | 619 element.style.webkitTransitionDuration = opt_duration + 'ms'; |
| 620 element.style.webkitTransitionTimingFunction = opt_effect.getTiming(); | 620 element.style.webkitTransitionTimingFunction = opt_effect.getTiming(); |
| 621 element.style.webkitTransform = opt_effect.transform(element, this.viewport_); | 621 element.style.webkitTransform = opt_effect.transform(element, this.viewport_); |
| 622 }; | 622 }; |
| 623 | 623 |
| 624 /** | 624 /** |
| 625 * @param {Rect} screenRect Target rectangle in screen coordinates. | 625 * @param {Rect} screenRect Target rectangle in screen coordinates. |
| 626 * @return {ImageView.Effect.Zoom} Zoom effect object. | 626 * @return {ImageView.Effect.Zoom} Zoom effect object. |
| 627 */ | 627 */ |
| 628 ImageView.prototype.createZoomEffect = function(screenRect) { | 628 ImageView.prototype.createZoomEffect = function(screenRect) { |
| 629 return new ImageView.Effect.Zoom( | 629 return new ImageView.Effect.ZoomToScreen( |
| 630 this.viewport_.screenToDeviceRect(screenRect), | 630 screenRect, |
| 631 null /* use viewport */, | |
| 632 ImageView.MODE_TRANSITION_DURATION); | 631 ImageView.MODE_TRANSITION_DURATION); |
| 633 }; | 632 }; |
| 634 | 633 |
| 635 /** | 634 /** |
| 636 * Visualizes crop or rotate operation. Hide the old image instantly, animate | 635 * Visualizes crop or rotate operation. Hide the old image instantly, animate |
| 637 * the new image to visualize the operation. | 636 * the new image to visualize the operation. |
| 638 * | 637 * |
| 639 * @param {HTMLCanvasElement} canvas New content canvas. | 638 * @param {HTMLCanvasElement} canvas New content canvas. |
| 640 * @param {Rect} imageCropRect The crop rectangle in image coordinates. | 639 * @param {Rect} imageCropRect The crop rectangle in image coordinates. |
| 641 * Null for rotation operations. | 640 * Null for rotation operations. |
| 642 * @param {number} rotate90 Rotation angle in 90 degree increments. | 641 * @param {number} rotate90 Rotation angle in 90 degree increments. |
| 643 * @return {number} Animation duration. | 642 * @return {number} Animation duration. |
| 644 */ | 643 */ |
| 645 ImageView.prototype.replaceAndAnimate = function( | 644 ImageView.prototype.replaceAndAnimate = function( |
| 646 canvas, imageCropRect, rotate90) { | 645 canvas, imageCropRect, rotate90) { |
| 647 var oldScale = this.viewport_.getScale(); | 646 var oldImageBounds = { |
| 648 var deviceCropRect = imageCropRect && this.viewport_.screenToDeviceRect( | 647 width: this.viewport_.getImageBounds().width, |
| 649 this.viewport_.imageToScreenRect(imageCropRect)); | 648 height: this.viewport_.getImageBounds().height |
| 650 | 649 }; |
| 651 var oldScreenImage = this.screenImage_; | 650 var oldScreenImage = this.screenImage_; |
| 652 this.replaceContent_(canvas); | 651 this.replaceContent_(canvas); |
| 653 var newScreenImage = this.screenImage_; | 652 var newScreenImage = this.screenImage_; |
| 654 | |
| 655 // Display the new canvas, initially transformed. | |
| 656 var deviceFullRect = this.viewport_.getDeviceClipped(); | |
| 657 | |
| 658 var effect = rotate90 ? | 653 var effect = rotate90 ? |
| 659 new ImageView.Effect.Rotate( | 654 new ImageView.Effect.Rotate(rotate90 > 0) : |
|
mtomasz
2014/07/10 07:26:52
rotate90 > 0 is bool, but number is expected
hirono
2014/07/10 08:16:05
Fixed the JSDoc.
| |
| 660 oldScale / this.viewport_.getScale(), -rotate90) : | 655 new ImageView.Effect.Zoom( |
| 661 new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); | 656 oldImageBounds.width, oldImageBounds.height, imageCropRect); |
| 662 | 657 |
| 663 this.setTransform(newScreenImage, effect, 0 /* instant */); | 658 this.setTransform(newScreenImage, effect, 0 /* instant */); |
| 664 | 659 |
| 665 oldScreenImage.parentNode.appendChild(newScreenImage); | 660 oldScreenImage.parentNode.appendChild(newScreenImage); |
| 666 oldScreenImage.parentNode.removeChild(oldScreenImage); | 661 oldScreenImage.parentNode.removeChild(oldScreenImage); |
| 667 | 662 |
| 668 // Let the layout fire, then animate back to non-transformed state. | 663 // Let the layout fire, then animate back to non-transformed state. |
| 669 setTimeout( | 664 setTimeout( |
| 670 this.setTransform.bind( | 665 this.setTransform.bind( |
| 671 this, newScreenImage, null, effect.getDuration()), | 666 this, newScreenImage, null, effect.getDuration()), |
| 672 0); | 667 0); |
| 673 | 668 |
| 674 return effect.getSafeInterval(); | 669 return effect.getSafeInterval(); |
| 675 }; | 670 }; |
| 676 | 671 |
| 677 /** | 672 /** |
| 678 * Visualizes "undo crop". Shrink the current image to the given crop rectangle | 673 * Visualizes "undo crop". Shrink the current image to the given crop rectangle |
| 679 * while fading in the new image. | 674 * while fading in the new image. |
| 680 * | 675 * |
| 681 * @param {HTMLCanvasElement} canvas New content canvas. | 676 * @param {HTMLCanvasElement} canvas New content canvas. |
| 682 * @param {Rect} imageCropRect The crop rectangle in image coordinates. | 677 * @param {Rect} imageCropRect The crop rectangle in image coordinates. |
| 683 * @return {number} Animation duration. | 678 * @return {number} Animation duration. |
| 684 */ | 679 */ |
| 685 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { | 680 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { |
| 686 var deviceFullRect = this.viewport_.getDeviceClipped(); | |
| 687 var oldScale = this.viewport_.getScale(); | |
| 688 | |
| 689 var oldScreenImage = this.screenImage_; | 681 var oldScreenImage = this.screenImage_; |
| 690 this.replaceContent_(canvas); | 682 this.replaceContent_(canvas); |
| 691 var newScreenImage = this.screenImage_; | 683 var newScreenImage = this.screenImage_; |
| 692 | |
| 693 var deviceCropRect = this.viewport_.screenToDeviceRect( | |
| 694 this.viewport_.imageToScreenRect(imageCropRect)); | |
| 695 | |
| 696 var setFade = ImageUtil.setAttribute.bind(null, newScreenImage, 'fade'); | 684 var setFade = ImageUtil.setAttribute.bind(null, newScreenImage, 'fade'); |
| 697 setFade(true); | 685 setFade(true); |
| 698 oldScreenImage.parentNode.insertBefore(newScreenImage, oldScreenImage); | 686 oldScreenImage.parentNode.insertBefore(newScreenImage, oldScreenImage); |
| 687 var effect = new ImageView.Effect.Zoom( | |
| 688 this.viewport_.getImageBounds().width, | |
| 689 this.viewport_.getImageBounds().height, | |
| 690 imageCropRect); | |
| 699 | 691 |
| 700 var effect = new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect); | |
| 701 // Animate to the transformed state. | 692 // Animate to the transformed state. |
| 702 this.setTransform(oldScreenImage, effect); | 693 this.setTransform(oldScreenImage, effect); |
| 703 | |
| 704 setTimeout(setFade.bind(null, false), 0); | 694 setTimeout(setFade.bind(null, false), 0); |
| 705 | |
| 706 setTimeout(function() { | 695 setTimeout(function() { |
| 707 if (oldScreenImage.parentNode) | 696 if (oldScreenImage.parentNode) |
| 708 oldScreenImage.parentNode.removeChild(oldScreenImage); | 697 oldScreenImage.parentNode.removeChild(oldScreenImage); |
| 709 }, effect.getSafeInterval()); | 698 }, effect.getSafeInterval()); |
| 710 | 699 |
| 711 return effect.getSafeInterval(); | 700 return effect.getSafeInterval(); |
| 712 }; | 701 }; |
| 713 | 702 |
| 714 | |
| 715 /** | 703 /** |
| 716 * Generic cache with a limited capacity and LRU eviction. | 704 * Generic cache with a limited capacity and LRU eviction. |
| 717 * @param {number} capacity Maximum number of cached item. | 705 * @param {number} capacity Maximum number of cached item. |
| 718 * @constructor | 706 * @constructor |
| 719 */ | 707 */ |
| 720 ImageView.Cache = function(capacity) { | 708 ImageView.Cache = function(capacity) { |
| 721 this.capacity_ = capacity; | 709 this.capacity_ = capacity; |
| 722 this.map_ = {}; | 710 this.map_ = {}; |
| 723 this.order_ = []; | 711 this.order_ = []; |
| 724 }; | 712 }; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 845 ImageView.Effect.prototype.getSafeInterval = function() { | 833 ImageView.Effect.prototype.getSafeInterval = function() { |
| 846 return this.getDuration() + ImageView.Effect.MARGIN; | 834 return this.getDuration() + ImageView.Effect.MARGIN; |
| 847 }; | 835 }; |
| 848 | 836 |
| 849 /** | 837 /** |
| 850 * @return {string} CSS transition timing function name. | 838 * @return {string} CSS transition timing function name. |
| 851 */ | 839 */ |
| 852 ImageView.Effect.prototype.getTiming = function() { return this.timing_; }; | 840 ImageView.Effect.prototype.getTiming = function() { return this.timing_; }; |
| 853 | 841 |
| 854 /** | 842 /** |
| 855 * @param {HTMLCanvasElement} element Element. | |
| 856 * @return {number} Preferred pixel ration to use with this element. | |
| 857 * @private | |
| 858 */ | |
| 859 ImageView.Effect.getPixelRatio_ = function(element) { | |
| 860 if (element.constructor.name === 'HTMLCanvasElement') | |
| 861 return Viewport.getDevicePixelRatio(); | |
| 862 else | |
| 863 return 1; | |
| 864 }; | |
| 865 | |
| 866 /** | |
| 867 * Default effect. It is not a no-op as it needs to adjust a canvas scale | 843 * Default effect. It is not a no-op as it needs to adjust a canvas scale |
| 868 * for devicePixelRatio. | 844 * for devicePixelRatio. |
| 869 * | 845 * |
| 870 * @constructor | 846 * @constructor |
| 847 * @extends {ImageView.Effect} | |
| 871 */ | 848 */ |
| 872 ImageView.Effect.None = function() { | 849 ImageView.Effect.None = function() { |
| 873 ImageView.Effect.call(this, 0); | 850 ImageView.Effect.call(this, 0); |
| 874 }; | 851 }; |
| 875 | 852 |
| 876 /** | 853 /** |
| 877 * Inherits from ImageView.Effect. | 854 * Inherits from ImageView.Effect. |
| 878 */ | 855 */ |
| 879 ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype }; | 856 ImageView.Effect.None.prototype = { __proto__: ImageView.Effect.prototype }; |
| 880 | 857 |
| 881 /** | 858 /** |
| 882 * @param {HTMLCanvasElement} element Element. | 859 * @param {HTMLCanvasElement} element Element. |
| 860 * @param {Viewport} viewport Current viewport. | |
| 883 * @return {string} Transform string. | 861 * @return {string} Transform string. |
| 884 */ | 862 */ |
| 885 ImageView.Effect.None.prototype.transform = function(element) { | 863 ImageView.Effect.None.prototype.transform = function(element, viewport) { |
| 886 var ratio = ImageView.Effect.getPixelRatio_(element); | 864 return viewport.getTransformation(); |
| 887 return 'scale(' + (1 / ratio) + ')'; | |
| 888 }; | 865 }; |
| 889 | 866 |
| 890 /** | 867 /** |
| 891 * Slide effect. | 868 * Slide effect. |
| 892 * | 869 * |
| 893 * @param {number} direction -1 for left, 1 for right. | 870 * @param {number} direction -1 for left, 1 for right. |
| 894 * @param {boolean=} opt_slow True if slow (as in slideshow). | 871 * @param {boolean=} opt_slow True if slow (as in slideshow). |
| 895 * @constructor | 872 * @constructor |
| 873 * @extends {ImageView.Effect} | |
| 896 */ | 874 */ |
| 897 ImageView.Effect.Slide = function Slide(direction, opt_slow) { | 875 ImageView.Effect.Slide = function Slide(direction, opt_slow) { |
| 898 ImageView.Effect.call(this, | 876 ImageView.Effect.call(this, |
| 899 opt_slow ? 800 : ImageView.Effect.DEFAULT_DURATION, 'ease-in-out'); | 877 opt_slow ? 800 : ImageView.Effect.DEFAULT_DURATION, 'ease-in-out'); |
| 900 this.direction_ = direction; | 878 this.direction_ = direction; |
| 901 this.slow_ = opt_slow; | 879 this.slow_ = opt_slow; |
| 902 this.shift_ = opt_slow ? 100 : 40; | 880 this.shift_ = opt_slow ? 100 : 40; |
| 903 if (this.direction_ < 0) this.shift_ = -this.shift_; | 881 if (this.direction_ < 0) this.shift_ = -this.shift_; |
| 904 }; | 882 }; |
| 905 | 883 |
| 906 /** | |
| 907 * Inherits from ImageView.Effect. | |
| 908 */ | |
| 909 ImageView.Effect.Slide.prototype = { __proto__: ImageView.Effect.prototype }; | 884 ImageView.Effect.Slide.prototype = { __proto__: ImageView.Effect.prototype }; |
| 910 | 885 |
| 911 /** | 886 /** |
| 912 * @return {ImageView.Effect.Slide} Reverse Slide effect. | 887 * Reverses the slide effect. |
| 888 * @return {ImageView.Effect.Slide} Reversed effect. | |
| 913 */ | 889 */ |
| 914 ImageView.Effect.Slide.prototype.getReverse = function() { | 890 ImageView.Effect.Slide.prototype.getReverse = function() { |
| 915 return new ImageView.Effect.Slide(-this.direction_, this.slow_); | 891 return new ImageView.Effect.Slide(-this.direction_, this.slow_); |
| 916 }; | 892 }; |
| 917 | 893 |
| 918 /** | 894 /** |
| 919 * @param {HTMLCanvasElement} element Element. | 895 * @override |
|
mtomasz
2014/07/10 07:26:52
ImageView.Effect doesn't have transform() so shoul
hirono
2014/07/10 08:16:05
Added an abstract transform method to the super cl
| |
| 920 * @return {string} Transform string. | |
| 921 */ | 896 */ |
| 922 ImageView.Effect.Slide.prototype.transform = function(element) { | 897 ImageView.Effect.Slide.prototype.transform = function(element, viewport) { |
| 923 var ratio = ImageView.Effect.getPixelRatio_(element); | 898 return viewport.getShiftTransformation(this.shift_); |
| 924 return 'scale(' + (1 / ratio) + ') translate(' + this.shift_ + 'px, 0px)'; | |
| 925 }; | 899 }; |
| 926 | 900 |
| 927 /** | 901 /** |
| 928 * Zoom effect. | 902 * Zoom effect. |
| 929 * | 903 * |
| 930 * Animates the original rectangle to the target rectangle. Both parameters | 904 * Animates the original rectangle to the target rectangle. Both parameters |
| 931 * should be given in device coordinates (accounting for devicePixelRatio). | 905 * should be given in device coordinates (accounting for devicePixelRatio). |
| 932 * | 906 * |
| 933 * @param {Rect} deviceTargetRect Target rectangle. | 907 * @param {Rect} deviceTargetRect Target rectangle. |
|
mtomasz
2014/07/10 07:26:52
nit: please update jsdoc
hirono
2014/07/10 08:16:05
Acknowledged.
| |
| 934 * @param {Rect=} opt_deviceOriginalRect Original rectangle. If omitted, | 908 * @param {Rect=} opt_deviceOriginalRect Original rectangle. If omitted, |
| 935 * the full viewport will be used at the time of |transform| call. | 909 * the full viewport will be used at the time of |transform| call. |
| 936 * @param {number=} opt_duration Duration in ms. | 910 * @param {number=} opt_duration Duration in ms. |
| 937 * @constructor | 911 * @constructor |
| 912 * @extends {ImageView.Effect} | |
| 938 */ | 913 */ |
| 939 ImageView.Effect.Zoom = function( | 914 ImageView.Effect.Zoom = function( |
| 940 deviceTargetRect, opt_deviceOriginalRect, opt_duration) { | 915 previousImageWidth, previousImageHeight, imageCropRect, opt_duration) { |
| 941 ImageView.Effect.call(this, | 916 ImageView.Effect.call(this, |
| 942 opt_duration || ImageView.Effect.DEFAULT_DURATION); | 917 opt_duration || ImageView.Effect.DEFAULT_DURATION); |
| 943 this.target_ = deviceTargetRect; | 918 this.previousImageWidth_ = previousImageWidth; |
| 944 this.original_ = opt_deviceOriginalRect; | 919 this.previousImageHeight_ = previousImageHeight; |
| 920 this.imageCropRect_ = imageCropRect; | |
| 921 }; | |
| 922 | |
| 923 ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype }; | |
| 924 | |
| 925 /** | |
| 926 * @override | |
|
mtomasz
2014/07/10 07:26:52
ditto
hirono
2014/07/10 08:16:05
Done.
| |
| 927 */ | |
| 928 ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { | |
| 929 return viewport.getInverseTransformForCroppedImage( | |
| 930 this.previousImageWidth_, this.previousImageHeight_, this.imageCropRect_); | |
| 945 }; | 931 }; |
| 946 | 932 |
| 947 /** | 933 /** |
| 948 * Inherits from ImageView.Effect. | 934 * Effect to zoom to a screen rectangle. |
| 935 * | |
| 936 * @param {Rect} screenRect Rectangle in the application window's coordinate. | |
| 937 * @param {number=} opt_duration Duration of effect. | |
| 938 * @constructor | |
| 939 * @extends {ImageView.Effect} | |
| 949 */ | 940 */ |
| 950 ImageView.Effect.Zoom.prototype = { __proto__: ImageView.Effect.prototype }; | 941 ImageView.Effect.ZoomToScreen = function(screenRect, opt_duration) { |
| 942 ImageView.Effect.call(this, opt_duration); | |
| 943 this.screenRect_ = screenRect; | |
| 944 }; | |
| 951 | 945 |
| 952 /** | 946 ImageView.Effect.ZoomToScreen.prototype = { |
| 953 * @param {HTMLCanvasElement} element Element. | 947 __proto__: ImageView.Effect.prototype |
| 954 * @param {Viewport} viewport Viewport. | |
| 955 * @return {string} Transform string. | |
| 956 */ | |
| 957 ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { | |
| 958 if (!this.original_) | |
| 959 this.original_ = viewport.getDeviceClipped(); | |
| 960 | |
| 961 var ratio = ImageView.Effect.getPixelRatio_(element); | |
| 962 | |
| 963 var dx = (this.target_.left + this.target_.width / 2) - | |
| 964 (this.original_.left + this.original_.width / 2); | |
| 965 var dy = (this.target_.top + this.target_.height / 2) - | |
| 966 (this.original_.top + this.original_.height / 2); | |
| 967 | |
| 968 var scaleX = this.target_.width / this.original_.width; | |
| 969 var scaleY = this.target_.height / this.original_.height; | |
| 970 | |
| 971 return 'translate(' + (dx / ratio) + 'px,' + (dy / ratio) + 'px) ' + | |
| 972 'scaleX(' + (scaleX / ratio) + ') scaleY(' + (scaleY / ratio) + ')'; | |
| 973 }; | 948 }; |
| 974 | 949 |
| 975 /** | 950 /** |
| 976 * Rotate effect. | 951 * @override |
|
mtomasz
2014/07/10 07:26:52
ditto
hirono
2014/07/10 08:16:05
Done.
| |
| 977 * | |
| 978 * @param {number} scale Scale. | |
| 979 * @param {number} rotate90 Rotation in 90 degrees increments. | |
| 980 * @constructor | |
| 981 */ | 952 */ |
| 982 ImageView.Effect.Rotate = function(scale, rotate90) { | 953 ImageView.Effect.ZoomToScreen.prototype.transform = function( |
| 983 ImageView.Effect.call(this, ImageView.Effect.DEFAULT_DURATION); | 954 element, viewport) { |
| 984 this.scale_ = scale; | 955 return viewport.getScreenRectTransformForImage(this.screenRect_); |
| 985 this.rotate90_ = rotate90; | |
| 986 }; | 956 }; |
| 987 | 957 |
| 988 /** | 958 /** |
| 989 * Inherits from ImageView.Effect. | 959 * Rotation effect. |
| 960 * | |
| 961 * @param {number} orientation Orientation of rotation. True is for clockwise | |
| 962 * and false is for counterclockwise. | |
| 963 * @constructor | |
| 964 * @extends {ImageView.Effect} | |
| 990 */ | 965 */ |
| 966 ImageView.Effect.Rotate = function(orientation) { | |
| 967 ImageView.Effect.call(this, ImageView.Effect.DEFAULT_DURATION); | |
| 968 this.orientation_ = orientation; | |
| 969 }; | |
| 970 | |
| 991 ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; | 971 ImageView.Effect.Rotate.prototype = { __proto__: ImageView.Effect.prototype }; |
| 992 | 972 |
| 993 /** | 973 /** |
| 994 * @param {HTMLCanvasElement} element Element. | 974 * @override |
| 995 * @return {string} Transform string. | |
| 996 */ | 975 */ |
| 997 ImageView.Effect.Rotate.prototype.transform = function(element) { | 976 ImageView.Effect.Rotate.prototype.transform = function(element, viewport) { |
| 998 var ratio = ImageView.Effect.getPixelRatio_(element); | 977 return viewport.getInverseTransformForRotatedImage(this.orientation_); |
| 999 return 'rotate(' + (this.rotate90_ * 90) + 'deg) ' + | |
| 1000 'scale(' + (this.scale_ / ratio) + ')'; | |
| 1001 }; | 978 }; |
| OLD | NEW |