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 |