Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(883)

Side by Side Diff: chrome/browser/resources/file_manager/js/image_editor/image_view.js

Issue 10919292: Photo Editor: better mode transitions (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 /** 5 /**
6 * The overlay displaying the image. 6 * The overlay displaying the image.
7 * @param {HTMLElement} container The container element. 7 * @param {HTMLElement} container The container element.
8 * @param {Viewport} viewport The viewport. 8 * @param {Viewport} viewport The viewport.
9 * @param {MetadataCache} metadataCache The metadataCache. 9 * @param {MetadataCache} metadataCache The metadataCache.
10 */ 10 */
(...skipping 29 matching lines...) Expand all
40 this.screenImage_ = null; 40 this.screenImage_ = null;
41 41
42 this.localImageTransformFetcher_ = function(url, callback) { 42 this.localImageTransformFetcher_ = function(url, callback) {
43 metadataCache.get(url, 'fetchedMedia', function(fetchedMedia) { 43 metadataCache.get(url, 'fetchedMedia', function(fetchedMedia) {
44 callback(fetchedMedia.imageTransform); 44 callback(fetchedMedia.imageTransform);
45 }); 45 });
46 }; 46 };
47 } 47 }
48 48
49 /** 49 /**
50 * Duration of image editing transitions. 50 * Duration for transition between images.
51 */ 51 */
52 ImageView.ANIMATION_DURATION = 180; 52 ImageView.ANIMATION_DURATION = 180;
53 53
54 /** 54 /**
55 * A timeout for use with setTimeout when one wants to wait until the animation 55 * A timeout for use with setTimeout when one wants to wait until the animation
56 * is done. Times 2 is added as a safe margin. 56 * is done. Times 2 is added as a safe margin.
57 */ 57 */
58 ImageView.ANIMATION_WAIT_INTERVAL = ImageView.ANIMATION_DURATION * 2; 58 ImageView.ANIMATION_WAIT_INTERVAL = ImageView.ANIMATION_DURATION * 2;
59 59
60 /** 60 /**
61 * Duration of transition when loading the first image or unloading the last.
62 */
63 ImageView.ZOOM_ANIMATION_DURATION = 350;
64
65 /**
61 * If the user flips though images faster than this interval we do not apply 66 * If the user flips though images faster than this interval we do not apply
62 * the slide-in/slide-out transition. 67 * the slide-in/slide-out transition.
63 */ 68 */
64 ImageView.FAST_SCROLL_INTERVAL = 300; 69 ImageView.FAST_SCROLL_INTERVAL = 300;
65 70
66 /** 71 /**
67 * Image load type: full resolution image loaded from cache. 72 * Image load type: full resolution image loaded from cache.
68 */ 73 */
69 ImageView.LOAD_TYPE_CACHED_FULL = 0; 74 ImageView.LOAD_TYPE_CACHED_FULL = 0;
70 75
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 this.screenCache_.renameItem(this.contentID_, newUrl); 495 this.screenCache_.renameItem(this.contentID_, newUrl);
491 this.contentID_ = newUrl; 496 this.contentID_ = newUrl;
492 }; 497 };
493 498
494 /** 499 /**
495 * Unload content. 500 * Unload content.
496 * 501 *
497 * @param {Rect} zoomToRect Target rectangle for zoom-out-effect. 502 * @param {Rect} zoomToRect Target rectangle for zoom-out-effect.
498 */ 503 */
499 ImageView.prototype.unload = function(zoomToRect) { 504 ImageView.prototype.unload = function(zoomToRect) {
500 if (zoomToRect) { 505 if (this.unloadTimer_) {
501 this.setTransform(this.screenImage_, this.createZoomEffect(zoomToRect)); 506 clearTimeout(this.unloadTimer_);
507 this.unloadTimer_ = null;
508 }
509 if (zoomToRect && this.screenImage_) {
510 var effect = this.createZoomEffect(zoomToRect);
511 this.setTransform(this.screenImage_, effect, effect.duration);
512 this.screenImage_.setAttribute('fade', true);
502 this.unloadTimer_ = setTimeout(function() { 513 this.unloadTimer_ = setTimeout(function() {
503 this.unloadTimer_ = null; 514 this.unloadTimer_ = null;
504 this.unload(null /* force unload */); 515 this.unload(null /* force unload */);
505 }.bind(this), 516 }.bind(this),
506 ImageView.ANIMATION_WAIT_INTERVAL + 100); 517 effect.duration + 100 /* error margin */);
507 return; 518 return;
508 } 519 }
509 if (this.unloadTimer_) {
510 clearTimeout(this.unloadTimer_);
511 this.unloadTimer_ = null;
512 }
513 this.container_.textContent = ''; 520 this.container_.textContent = '';
514 this.contentCanvas_ = null; 521 this.contentCanvas_ = null;
515 this.screenImage_ = null; 522 this.screenImage_ = null;
516 this.videoElement_ = null; 523 this.videoElement_ = null;
517 }; 524 };
518 525
519 /** 526 /**
520 * 527 *
521 * @param {HTMLCanvasElement|HTMLVideoElement} content The image element. 528 * @param {HTMLCanvasElement|HTMLVideoElement} content The image element.
522 * @param {boolean} opt_reuseScreenCanvas True if it is OK to reuse the screen 529 * @param {boolean} opt_reuseScreenCanvas True if it is OK to reuse the screen
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 content, opt_effect, opt_width, opt_height, opt_preview) { 633 content, opt_effect, opt_width, opt_height, opt_preview) {
627 var oldScreenImage = this.screenImage_; 634 var oldScreenImage = this.screenImage_;
628 635
629 this.replaceContent_( 636 this.replaceContent_(
630 content, !opt_effect, opt_width, opt_height, opt_preview); 637 content, !opt_effect, opt_width, opt_height, opt_preview);
631 638
632 if (!opt_effect) return; 639 if (!opt_effect) return;
633 640
634 var newScreenImage = this.screenImage_; 641 var newScreenImage = this.screenImage_;
635 642
636 ImageUtil.setAttribute(newScreenImage, 'fade', true); 643 if (oldScreenImage)
644 ImageUtil.setAttribute(newScreenImage, 'fade', true);
637 this.setTransform(newScreenImage, opt_effect); 645 this.setTransform(newScreenImage, opt_effect);
638 this.container_.appendChild(newScreenImage); 646 this.container_.appendChild(newScreenImage);
639 647
640 setTimeout(function() { 648 setTimeout(function() {
641 ImageUtil.setAttribute(newScreenImage, 'fade', false); 649 this.setTransform(newScreenImage, null, opt_effect && opt_effect.duration);
642 this.setTransform(newScreenImage);
643 if (oldScreenImage) { 650 if (oldScreenImage) {
651 ImageUtil.setAttribute(newScreenImage, 'fade', false);
644 ImageUtil.setAttribute(oldScreenImage, 'fade', true); 652 ImageUtil.setAttribute(oldScreenImage, 'fade', true);
645 if (opt_effect.getReverse) 653 if (opt_effect.getReverse)
646 this.setTransform(oldScreenImage, opt_effect.getReverse()); 654 this.setTransform(oldScreenImage, opt_effect.getReverse());
647 else 655 else
648 console.error('Cannot revert an effect.'); 656 console.error('Cannot revert an effect.');
649 setTimeout(function() { 657 setTimeout(function() {
650 oldScreenImage.parentNode.removeChild(oldScreenImage); 658 oldScreenImage.parentNode.removeChild(oldScreenImage);
651 }, ImageView.ANIMATION_WAIT_INTERVAL); 659 }, ImageView.ANIMATION_WAIT_INTERVAL);
652 } 660 }
653 }.bind(this), 0); 661 }.bind(this), 0);
654 }; 662 };
655 663
656 /** 664 /**
657 * @param {HTMLCanvasElement|HTMLVideoElement} element The element to transform. 665 * @param {HTMLCanvasElement|HTMLVideoElement} element The element to transform.
658 * @param {ImageView.Effect} opt_effect The effect to apply. 666 * @param {ImageView.Effect} opt_effect The effect to apply.
667 * @param {number} opt_duration Transition duration.
dgozman 2012/09/14 15:17:38 number=
659 */ 668 */
660 ImageView.prototype.setTransform = function(element, opt_effect) { 669 ImageView.prototype.setTransform = function(element, opt_effect, opt_duration) {
661 if (!opt_effect) opt_effect = new ImageView.Effect.None(); 670 if (!opt_effect) opt_effect = new ImageView.Effect.None();
671 if (opt_duration == undefined)
dgozman 2012/09/14 15:17:38 I'd use typeof(opt_duration) == "number"
672 element.style.webkitTransitionDuration = ''; // Use CSS-defined default.
673 else
674 element.style.webkitTransitionDuration = opt_duration + 'ms';
662 element.style.webkitTransform = opt_effect.transform(element, this.viewport_); 675 element.style.webkitTransform = opt_effect.transform(element, this.viewport_);
663 }; 676 };
664 677
665 /** 678 /**
666 * @param {Rect} screenRect Target rectangle in screen coordinates. 679 * @param {Rect} screenRect Target rectangle in screen coordinates.
667 * @return {ImageView.Effect.Zoom} Zoom effect object. 680 * @return {ImageView.Effect.Zoom} Zoom effect object.
668 */ 681 */
669 ImageView.prototype.createZoomEffect = function(screenRect) { 682 ImageView.prototype.createZoomEffect = function(screenRect) {
670 return new ImageView.Effect.Zoom( 683 return new ImageView.Effect.Zoom(
671 this.viewport_.screenToDeviceRect(screenRect)); 684 this.viewport_.screenToDeviceRect(screenRect),
685 null /* use viewport */,
686 ImageView.ZOOM_ANIMATION_DURATION);
672 }; 687 };
673 688
674 /** 689 /**
675 * Visualize crop or rotate operation. Hide the old image instantly, animate 690 * Visualize crop or rotate operation. Hide the old image instantly, animate
676 * the new image to visualize the operation. 691 * the new image to visualize the operation.
677 * 692 *
678 * @param {HTMLCanvasElement} canvas New content canvas. 693 * @param {HTMLCanvasElement} canvas New content canvas.
679 * @param {Rect} imageCropRect The crop rectangle in image coordinates. 694 * @param {Rect} imageCropRect The crop rectangle in image coordinates.
680 * Null for rotation operations. 695 * Null for rotation operations.
681 * @param {number} rotate90 Rotation angle in 90 degree increments. 696 * @param {number} rotate90 Rotation angle in 90 degree increments.
682 */ 697 */
683 ImageView.prototype.replaceAndAnimate = function( 698 ImageView.prototype.replaceAndAnimate = function(
684 canvas, imageCropRect, rotate90) { 699 canvas, imageCropRect, rotate90) {
685 var oldScale = this.viewport_.getScale(); 700 var oldScale = this.viewport_.getScale();
686 var deviceCropRect = imageCropRect && this.viewport_.screenToDeviceRect( 701 var deviceCropRect = imageCropRect && this.viewport_.screenToDeviceRect(
687 this.viewport_.imageToScreenRect(imageCropRect)); 702 this.viewport_.imageToScreenRect(imageCropRect));
688 703
689 var oldScreenImage = this.screenImage_; 704 var oldScreenImage = this.screenImage_;
690 this.replaceContent_(canvas); 705 this.replaceContent_(canvas);
691 var newScreenImage = this.screenImage_; 706 var newScreenImage = this.screenImage_;
692 707
693 // Display the new canvas, initially transformed. 708 // Display the new canvas, initially transformed.
694 var deviceFullRect = this.viewport_.getDeviceClipped(); 709 var deviceFullRect = this.viewport_.getDeviceClipped();
695 710
696 //Transform instantly.
697 newScreenImage.style.webkitTransitionDuration = '0ms';
698 this.setTransform(newScreenImage, rotate90 ? 711 this.setTransform(newScreenImage, rotate90 ?
699 new ImageView.Effect.Rotate( 712 new ImageView.Effect.Rotate(
700 oldScale / this.viewport_.getScale(), -rotate90) : 713 oldScale / this.viewport_.getScale(), -rotate90) :
701 new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect)); 714 new ImageView.Effect.Zoom(deviceCropRect, deviceFullRect),
715 0 /* Transform instantly*/);
702 716
703 oldScreenImage.parentNode.appendChild(newScreenImage); 717 oldScreenImage.parentNode.appendChild(newScreenImage);
704 oldScreenImage.parentNode.removeChild(oldScreenImage); 718 oldScreenImage.parentNode.removeChild(oldScreenImage);
705 719
706 // Let the layout fire. 720 // Let the layout fire, then animate back to non-transformed state.
707 setTimeout(function() { 721 setTimeout(this.setTransform.bind(this, newScreenImage), 0);
708 // Animated back to non-transformed state.
709 newScreenImage.style.webkitTransitionDuration = '';
710 this.setTransform(newScreenImage);
711 }.bind(this), 0);
712 }; 722 };
713 723
714 /** 724 /**
715 * Visualize "undo crop". Shrink the current image to the given crop rectangle 725 * Visualize "undo crop". Shrink the current image to the given crop rectangle
716 * while fading in the new image. 726 * while fading in the new image.
717 * 727 *
718 * @param {HTMLCanvasElement} canvas New content canvas. 728 * @param {HTMLCanvasElement} canvas New content canvas.
719 * @param {Rect} imageCropRect The crop rectangle in image coordinates. 729 * @param {Rect} imageCropRect The crop rectangle in image coordinates.
720 */ 730 */
721 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) { 731 ImageView.prototype.animateAndReplace = function(canvas, imageCropRect) {
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 899
890 /** 900 /**
891 * Zoom effect. 901 * Zoom effect.
892 * 902 *
893 * Animates the original rectangle to the target rectangle. Both parameters 903 * Animates the original rectangle to the target rectangle. Both parameters
894 * should be given in device coordinates (accounting for devicePixelRatio). 904 * should be given in device coordinates (accounting for devicePixelRatio).
895 * 905 *
896 * @param {Rect} deviceTargetRect Target rectangle. 906 * @param {Rect} deviceTargetRect Target rectangle.
897 * @param {Rect} opt_deviceOriginalRect Original rectangle. If omitted, 907 * @param {Rect} opt_deviceOriginalRect Original rectangle. If omitted,
898 * the full viewport will be used at the time of |transform| call. 908 * the full viewport will be used at the time of |transform| call.
909 * @param {number} opt_duration Duration in ms.
899 * @constructor 910 * @constructor
900 */ 911 */
901 ImageView.Effect.Zoom = function(deviceTargetRect, opt_deviceOriginalRect) { 912 ImageView.Effect.Zoom = function(
913 deviceTargetRect, opt_deviceOriginalRect, opt_duration) {
902 this.target_ = deviceTargetRect; 914 this.target_ = deviceTargetRect;
903 this.original_ = opt_deviceOriginalRect; 915 this.original_ = opt_deviceOriginalRect;
916 this.duration = opt_duration;
904 }; 917 };
905 918
906 /** 919 /**
907 * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 920 * @param {HTMLCanvasElement|HTMLVideoElement} element Element.
908 * @param {Viewport} viewport Viewport. 921 * @param {Viewport} viewport Viewport.
909 * @return {string} Transform string. 922 * @return {string} Transform string.
910 */ 923 */
911 ImageView.Effect.Zoom.prototype.transform = function(element, viewport) { 924 ImageView.Effect.Zoom.prototype.transform = function(element, viewport) {
912 if (!this.original_) 925 if (!this.original_)
913 this.original_ = viewport.getDeviceClipped(); 926 this.original_ = viewport.getDeviceClipped();
(...skipping 26 matching lines...) Expand all
940 953
941 /** 954 /**
942 * @param {HTMLCanvasElement|HTMLVideoElement} element Element. 955 * @param {HTMLCanvasElement|HTMLVideoElement} element Element.
943 * @return {string} Transform string. 956 * @return {string} Transform string.
944 */ 957 */
945 ImageView.Effect.Rotate.prototype.transform = function(element) { 958 ImageView.Effect.Rotate.prototype.transform = function(element) {
946 var ratio = ImageView.Effect.getPixelRatio_(element); 959 var ratio = ImageView.Effect.getPixelRatio_(element);
947 return 'rotate(' + (this.rotate90_ * 90) + 'deg) ' + 960 return 'rotate(' + (this.rotate90_ * 90) + 'deg) ' +
948 'scale(' + (this.scale_ / ratio) + ')'; 961 'scale(' + (this.scale_ / ratio) + ')';
949 }; 962 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698