1<!DOCTYPE html>
2<!--
3Copyright (c) 2015 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/base.html">
9
10<script>
11'use strict';
12
13tr.exportTo('tr.model', function() {
14  /**
15   * YComponent is a class that handles storing the stableId and the percentage
16   * offset in the y direction of all tracks within a specific viewX and viewY
17   * coordinate.
18   * @constructor
19   */
20  function YComponent(stableId, yPercentOffset) {
21    this.stableId = stableId;
22    this.yPercentOffset = yPercentOffset;
23  }
24
25  YComponent.prototype = {
26    toDict: function() {
27      return {
28        stableId: this.stableId,
29        yPercentOffset: this.yPercentOffset
30      };
31    }
32  };
33
34  /**
35   * Location is a class that represents a spatial location on the timeline
36   * that is specified by percent offsets within tracks rather than specific
37   * points.
38   *
39   * @constructor
40   */
41  function Location(xWorld, yComponents) {
42    this.xWorld_ = xWorld;
43    this.yComponents_ = yComponents;
44  };
45
46  /**
47   * Returns a new Location given by x and y coordinates with respect to
48   * the timeline's drawing canvas.
49   */
50  Location.fromViewCoordinates = function(viewport, viewX, viewY) {
51    var dt = viewport.currentDisplayTransform;
52    var xWorld = dt.xViewToWorld(viewX);
53    var yComponents = [];
54
55    // Since we're given coordinates within the timeline canvas, we need to
56    // convert them to document coordinates to get the element.
57    var elem = document.elementFromPoint(
58          viewX + viewport.modelTrackContainer.canvas.offsetLeft,
59          viewY + viewport.modelTrackContainer.canvas.offsetTop);
60    // Build yComponents by calculating percentage offset with respect to
61    // each parent track.
62    while (elem instanceof tr.ui.tracks.Track) {
63      if (elem.eventContainer) {
64        var boundRect = elem.getBoundingClientRect();
65        var yPercentOffset = (viewY - boundRect.top) / boundRect.height;
66        yComponents.push(
67            new YComponent(elem.eventContainer.stableId, yPercentOffset));
68      }
69      elem = elem.parentElement;
70    }
71
72    if (yComponents.length == 0)
73      return;
74    return new Location(xWorld, yComponents);
75  }
76
77  Location.fromStableIdAndTimestamp = function(viewport, stableId, ts) {
78    var xWorld = ts;
79    var yComponents = [];
80
81    // The y components' percentage offsets will be calculated with respect to
82    // the boundingRect's top of containing track.
83    var containerToTrack = viewport.containerToTrackMap;
84    var elem = containerToTrack.getTrackByStableId(stableId);
85    if (!elem)
86      return;
87
88    var firstY = elem.getBoundingClientRect().top;
89    while (elem instanceof tr.ui.tracks.Track) {
90      if (elem.eventContainer) {
91        var boundRect = elem.getBoundingClientRect();
92        var yPercentOffset = (firstY - boundRect.top) / boundRect.height;
93        yComponents.push(
94            new YComponent(elem.eventContainer.stableId, yPercentOffset));
95      }
96      elem = elem.parentElement;
97    }
98
99    if (yComponents.length == 0)
100      return;
101    return new Location(xWorld, yComponents);
102  }
103
104  Location.prototype = {
105
106    get xWorld() {
107      return this.xWorld_;
108    },
109
110    /**
111     * Returns the first valid containing track based on the
112     * internal yComponents.
113     */
114    getContainingTrack: function(viewport) {
115      var containerToTrack = viewport.containerToTrackMap;
116      for (var i in this.yComponents_) {
117        var yComponent = this.yComponents_[i];
118        var track = containerToTrack.getTrackByStableId(yComponent.stableId);
119        if (track !== undefined)
120          return track;
121      }
122    },
123
124    /**
125     * Calculates and returns x and y coordinates of the current location with
126     * respect to the timeline's canvas.
127     */
128    toViewCoordinates: function(viewport) {
129      var dt = viewport.currentDisplayTransform;
130      var containerToTrack = viewport.containerToTrackMap;
131      var viewX = dt.xWorldToView(this.xWorld_);
132
133      var viewY = -1;
134      for (var index in this.yComponents_) {
135        var yComponent = this.yComponents_[index];
136        var track = containerToTrack.getTrackByStableId(yComponent.stableId);
137        if (track !== undefined) {
138          var boundRect = track.getBoundingClientRect();
139          viewY = yComponent.yPercentOffset * boundRect.height + boundRect.top;
140          break;
141        }
142      }
143
144      return {
145        viewX: viewX,
146        viewY: viewY
147      };
148    },
149
150    toDict: function() {
151      return {
152        xWorld: this.xWorld_,
153        yComponents: this.yComponents_
154      };
155    }
156  };
157
158  return {
159    Location: Location
160  };
161});
162</script>
163