Home | History | Annotate | Download | only in ui
      1 <!DOCTYPE html>
      2 <!--
      3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
      4 Use of this source code is governed by a BSD-style license that can be
      5 found in the LICENSE file.
      6 -->
      7 <link rel="import" href="/tracing/base/utils.html">
      8 <link rel="import" href="/tracing/ui/base/animation.html">
      9 
     10 <script>
     11 'use strict';
     12 
     13 tr.exportTo('tr.ui', function() {
     14   var kDefaultPanAnimationDurationMs = 100.0;
     15 
     16   /**
     17    * Pans a TimelineDisplayTransform by a given amount.
     18    * @constructor
     19    * @extends {tr.ui.b.Animation}
     20    * @param {Number} deltaX The total amount of change to the transform's panX.
     21    * @param {Number} deltaY The total amount of change to the transform's panY.
     22    * @param {Number=} opt_durationMs How long the pan animation should run.
     23    * Defaults to kDefaultPanAnimationDurationMs.
     24    */
     25   function TimelineDisplayTransformPanAnimation(
     26       deltaX, deltaY, opt_durationMs) {
     27     this.deltaX = deltaX;
     28     this.deltaY = deltaY;
     29     if (opt_durationMs === undefined)
     30       this.durationMs = kDefaultPanAnimationDurationMs;
     31     else
     32       this.durationMs = opt_durationMs;
     33 
     34     this.startPanX = undefined;
     35     this.startPanY = undefined;
     36     this.startTimeMs = undefined;
     37   }
     38 
     39   TimelineDisplayTransformPanAnimation.prototype = {
     40     __proto__: tr.ui.b.Animation.prototype,
     41 
     42     get affectsPanY() {
     43       return this.deltaY !== 0;
     44     },
     45 
     46     canTakeOverFor: function(existingAnimation) {
     47       return existingAnimation instanceof TimelineDisplayTransformPanAnimation;
     48     },
     49 
     50     takeOverFor: function(existing, timestamp, target) {
     51       var remainingDeltaXOnExisting = existing.goalPanX - target.panX;
     52       var remainingDeltaYOnExisting = existing.goalPanY - target.panY;
     53       var remainingTimeOnExisting = timestamp - (
     54           existing.startTimeMs + existing.durationMs);
     55       remainingTimeOnExisting = Math.max(remainingTimeOnExisting, 0);
     56 
     57       this.deltaX += remainingDeltaXOnExisting;
     58       this.deltaY += remainingDeltaYOnExisting;
     59       this.durationMs += remainingTimeOnExisting;
     60     },
     61 
     62     start: function(timestamp, target) {
     63       this.startTimeMs = timestamp;
     64       this.startPanX = target.panX;
     65       this.startPanY = target.panY;
     66     },
     67 
     68     tick: function(timestamp, target) {
     69       var percentDone = (timestamp - this.startTimeMs) / this.durationMs;
     70       percentDone = tr.b.clamp(percentDone, 0, 1);
     71 
     72       target.panX = tr.b.lerp(percentDone, this.startPanX, this.goalPanX);
     73       if (this.affectsPanY)
     74         target.panY = tr.b.lerp(percentDone, this.startPanY, this.goalPanY);
     75       return timestamp >= this.startTimeMs + this.durationMs;
     76     },
     77 
     78     get goalPanX() {
     79       return this.startPanX + this.deltaX;
     80     },
     81 
     82     get goalPanY() {
     83       return this.startPanY + this.deltaY;
     84     }
     85   };
     86 
     87   /**
     88    * Zooms in/out on a specified location in the world.
     89    *
     90    * Zooming in and out is all about keeping the area under the mouse cursor,
     91    * here called the "focal point" in the same place under the zoom. If one
     92    * simply changes the scale, the area under the mouse cursor will change. To
     93    * keep the focal point from moving during the zoom, the pan needs to change
     94    * in order to compensate. Thus, a ZoomTo animation is given both a focal
     95    * point in addition to the amount by which to zoom.
     96    *
     97    * @constructor
     98    * @extends {tr.ui.b.Animation}
     99    * @param {Number} goalFocalPointXWorld The X coordinate in the world which is
    100    * of interest.
    101    * @param {Number} goalFocalPointXView Where on the screen the
    102    * goalFocalPointXWorld should stay centered during the zoom.
    103    * @param {Number} goalFocalPointY Where the panY should be when the zoom
    104    * completes.
    105    * @param {Number} zoomInRatioX The ratio of the current scaleX to the goal
    106    * scaleX.
    107    */
    108   function TimelineDisplayTransformZoomToAnimation(
    109       goalFocalPointXWorld,
    110       goalFocalPointXView,
    111       goalFocalPointY,
    112       zoomInRatioX,
    113       opt_durationMs) {
    114     this.goalFocalPointXWorld = goalFocalPointXWorld;
    115     this.goalFocalPointXView = goalFocalPointXView;
    116     this.goalFocalPointY = goalFocalPointY;
    117     this.zoomInRatioX = zoomInRatioX;
    118     if (opt_durationMs === undefined)
    119       this.durationMs = kDefaultPanAnimationDurationMs;
    120     else
    121       this.durationMs = opt_durationMs;
    122 
    123     this.startTimeMs = undefined;
    124     this.startScaleX = undefined;
    125     this.goalScaleX = undefined;
    126     this.startPanY = undefined;
    127   }
    128 
    129   TimelineDisplayTransformZoomToAnimation.prototype = {
    130     __proto__: tr.ui.b.Animation.prototype,
    131 
    132     get affectsPanY() {
    133       return this.startPanY != this.goalFocalPointY;
    134     },
    135 
    136     canTakeOverFor: function(existingAnimation) {
    137       return false;
    138     },
    139 
    140     takeOverFor: function(existingAnimation, timestamp, target) {
    141       this.goalScaleX = target.scaleX * this.zoomInRatioX;
    142     },
    143 
    144     start: function(timestamp, target) {
    145       this.startTimeMs = timestamp;
    146       this.startScaleX = target.scaleX;
    147       this.goalScaleX = this.zoomInRatioX * target.scaleX;
    148       this.startPanY = target.panY;
    149     },
    150 
    151     tick: function(timestamp, target) {
    152       var percentDone = (timestamp - this.startTimeMs) / this.durationMs;
    153       percentDone = tr.b.clamp(percentDone, 0, 1);
    154 
    155       target.scaleX = tr.b.lerp(percentDone, this.startScaleX, this.goalScaleX);
    156       if (this.affectsPanY) {
    157         target.panY = tr.b.lerp(
    158             percentDone, this.startPanY, this.goalFocalPointY);
    159       }
    160 
    161       target.xPanWorldPosToViewPos(
    162           this.goalFocalPointXWorld, this.goalFocalPointXView);
    163       return timestamp >= this.startTimeMs + this.durationMs;
    164     }
    165   };
    166 
    167   return {
    168     TimelineDisplayTransformPanAnimation:
    169         TimelineDisplayTransformPanAnimation,
    170     TimelineDisplayTransformZoomToAnimation:
    171         TimelineDisplayTransformZoomToAnimation
    172   };
    173 });
    174 </script>
    175