Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / timing_tool.html
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
8 <link rel="import" href="/tracing/constants.html">
9 <link rel="import" href="/tracing/selection.html">
10 <link rel="import" href="/tvcm/range.html">
11 <link rel="import" href="/tvcm/ui.html">
12 <link rel="import" href="/tracing/trace_model/slice.html">
13
14 <script>
15 'use strict';
16
17 /**
18  * @fileoverview Provides the TimingTool class.
19  */
20 tvcm.exportTo('tracing', function() {
21
22   var constants = tracing.constants;
23
24   /**
25    * Tool for taking time measurements in the TimelineTrackView using
26    * Viewportmarkers.
27    * @constructor
28    */
29   function TimingTool(viewport, targetElement) {
30     this.viewport_ = viewport;
31
32     // Prepare the event handlers to be added and removed repeatedly.
33     this.onMouseMove_ = this.onMouseMove_.bind(this);
34     this.onDblClick_ = this.onDblClick_.bind(this);
35     this.targetElement_ = targetElement;
36
37     // Valid only during mousedown.
38     this.isMovingLeftEdge_ = false;
39   };
40
41   TimingTool.prototype = {
42
43     onEnterTiming: function(e) {
44       this.targetElement_.addEventListener('mousemove', this.onMouseMove_);
45       this.targetElement_.addEventListener('dblclick', this.onDblClick_);
46     },
47
48     onBeginTiming: function(e) {
49       var pt = this.getSnappedToEventPosition_(e);
50       this.mouseDownAt_(pt.x, pt.y);
51
52       this.updateSnapIndicators_(pt);
53     },
54
55     updateSnapIndicators_: function(pt) {
56       if (!pt.snapped)
57         return;
58       var ir = this.viewport_.interestRange;
59       if (ir.min === pt.x)
60         ir.leftSnapIndicator = new tracing.SnapIndicator(pt.y, pt.height);
61       if (ir.max === pt.x)
62         ir.rightSnapIndicator = new tracing.SnapIndicator(pt.y, pt.height);
63     },
64
65     onUpdateTiming: function(e) {
66       var pt = this.getSnappedToEventPosition_(e);
67       this.mouseMoveAt_(pt.x, pt.y, true);
68       this.updateSnapIndicators_(pt);
69     },
70
71     onEndTiming: function(e) {
72       this.mouseUp_();
73     },
74
75     onExitTiming: function(e) {
76       this.targetElement_.removeEventListener('mousemove', this.onMouseMove_);
77       this.targetElement_.removeEventListener('dblclick', this.onDblClick_);
78     },
79
80     onMouseMove_: function(e) {
81       if (e.button)
82         return;
83       var worldX = this.getWorldXFromEvent_(e);
84       this.mouseMoveAt_(worldX, e.clientY, false);
85     },
86
87     onDblClick_: function(e) {
88       // TODO(nduca): Implement dobuleclicking.
89       console.error('not implemented');
90     },
91
92     ////////////////////////////////////////////////////////////////////////////
93
94     mouseDownAt_: function(worldX, y) {
95       var ir = this.viewport_.interestRange;
96       var dt = this.viewport_.currentDisplayTransform;
97
98       var pixelRatio = window.devicePixelRatio || 1;
99       var nearnessThresholdWorld = dt.xViewVectorToWorld(6 * pixelRatio);
100
101       if (ir.isEmpty) {
102         ir.setMinAndMax(worldX, worldX);
103         ir.rightSelected = true;
104         this.isMovingLeftEdge_ = false;
105         return;
106       }
107
108
109       // Left edge test.
110       if (Math.abs(worldX - ir.min) < nearnessThresholdWorld) {
111         ir.leftSelected = true;
112         ir.min = worldX;
113         this.isMovingLeftEdge_ = true;
114         return;
115       }
116
117       // Right edge test.
118       if (Math.abs(worldX - ir.max) < nearnessThresholdWorld) {
119         ir.rightSelected = true;
120         ir.max = worldX;
121         this.isMovingLeftEdge_ = false;
122         return;
123       }
124
125       ir.setMinAndMax(worldX, worldX);
126       ir.rightSelected = true;
127       this.isMovingLeftEdge_ = false;
128     },
129
130     mouseMoveAt_: function(worldX, y, mouseDown) {
131       var ir = this.viewport_.interestRange;
132
133       if (mouseDown) {
134         this.updateMovingEdge_(worldX);
135         return;
136       }
137
138       var ir = this.viewport_.interestRange;
139       var dt = this.viewport_.currentDisplayTransform;
140
141       var pixelRatio = window.devicePixelRatio || 1;
142       var nearnessThresholdWorld = dt.xViewVectorToWorld(6 * pixelRatio);
143
144       // Left edge test.
145       if (Math.abs(worldX - ir.min) < nearnessThresholdWorld) {
146         ir.leftSelected = true;
147         ir.rightSelected = false;
148         return;
149       }
150
151       // Right edge test.
152       if (Math.abs(worldX - ir.max) < nearnessThresholdWorld) {
153         ir.leftSelected = false;
154         ir.rightSelected = true;
155         return;
156       }
157
158       ir.leftSelected = false;
159       ir.rightSelected = false;
160       return;
161     },
162
163     updateMovingEdge_: function(newWorldX) {
164       var ir = this.viewport_.interestRange;
165       var a = ir.min;
166       var b = ir.max;
167       if (this.isMovingLeftEdge_)
168         a = newWorldX;
169       else
170         b = newWorldX;
171
172       if (a <= b)
173         ir.setMinAndMax(a, b);
174       else
175         ir.setMinAndMax(b, a);
176
177       if (ir.min == newWorldX) {
178         this.isMovingLeftEdge_ = true;
179         ir.leftSelected = true;
180         ir.rightSelected = false;
181       } else {
182         this.isMovingLeftEdge_ = false;
183         ir.leftSelected = false;
184         ir.rightSelected = true;
185       }
186     },
187
188     mouseUp_: function() {
189       var dt = this.viewport_.currentDisplayTransform;
190       var ir = this.viewport_.interestRange;
191
192       ir.leftSelected = false;
193       ir.rightSelected = false;
194
195       var pixelRatio = window.devicePixelRatio || 1;
196       var minWidthValue = dt.xViewVectorToWorld(2 * pixelRatio);
197       if (ir.range < minWidthValue)
198         ir.reset();
199     },
200
201     getWorldXFromEvent_: function(e) {
202       var pixelRatio = window.devicePixelRatio || 1;
203       var canvas = this.viewport_.modelTrackContainer.canvas;
204       var worldOffset = canvas.getBoundingClientRect().left;
205       var viewX = (e.clientX - worldOffset) * pixelRatio;
206       return this.viewport_.currentDisplayTransform.xViewToWorld(viewX);
207     },
208
209
210     /**
211      * Get the closest position of an event within a vertical range of the mouse
212      * position if possible, otherwise use the position of the mouse pointer.
213      * @param {MouseEvent} e Mouse event with the current mouse coordinates.
214      * @return {
215      *   {Number} x, The x coordinate in world space.
216      *   {Number} y, The y coordinate in world space.
217      *   {Number} height, The height of the event.
218      *   {boolean} snapped Whether the coordinates are from a snapped event or
219      *     the mouse position.
220      * }
221      */
222     getSnappedToEventPosition_: function(e) {
223       var pixelRatio = window.devicePixelRatio || 1;
224       var EVENT_SNAP_RANGE = 16 * pixelRatio;
225
226       var modelTrackContainer = this.viewport_.modelTrackContainer;
227       var modelTrackContainerRect = modelTrackContainer.getBoundingClientRect();
228
229       var viewport = this.viewport_;
230       var dt = viewport.currentDisplayTransform;
231       var worldMaxDist = dt.xViewVectorToWorld(EVENT_SNAP_RANGE);
232
233       var worldX = this.getWorldXFromEvent_(e);
234       var mouseY = e.clientY;
235
236       var selection = new tracing.Selection();
237
238       // Look at the track under mouse position first for better performance.
239       modelTrackContainer.addClosestEventToSelection(
240           worldX, worldMaxDist, mouseY, mouseY, selection);
241
242       // Look at all tracks visible on screen.
243       if (!selection.length) {
244         modelTrackContainer.addClosestEventToSelection(
245             worldX, worldMaxDist,
246             modelTrackContainerRect.top, modelTrackContainerRect.bottom,
247             selection);
248       }
249
250       var minDistX = worldMaxDist;
251       var minDistY = Infinity;
252       var pixWidth = dt.xViewVectorToWorld(1);
253
254       // Create result object with the mouse coordinates.
255       var result = {
256         x: worldX,
257         y: mouseY - modelTrackContainerRect.top,
258         height: 0,
259         snapped: false
260       };
261
262       var eventBounds = new tvcm.Range();
263       for (var i = 0; i < selection.length; i++) {
264         var event = selection[i];
265         var track = viewport.trackForEvent(event);
266         var trackRect = track.getBoundingClientRect();
267
268         eventBounds.reset();
269         event.addBoundsToRange(eventBounds);
270         var eventX;
271         if (Math.abs(eventBounds.min - worldX) <
272             Math.abs(eventBounds.max - worldX)) {
273           eventX = eventBounds.min;
274         } else {
275           eventX = eventBounds.max;
276         }
277
278         var distX = eventX - worldX;
279
280         var eventY = trackRect.top;
281         var eventHeight = trackRect.height;
282         var distY = Math.abs(eventY + eventHeight / 2 - mouseY);
283
284         // Prefer events with a closer y position if their x difference is below
285         // the width of a pixel.
286         if ((distX <= minDistX || Math.abs(distX - minDistX) < pixWidth) &&
287             distY < minDistY) {
288           minDistX = distX;
289           minDistY = distY;
290
291           // Retrieve the event position from the hit.
292           result.x = eventX;
293           result.y = eventY +
294               modelTrackContainer.scrollTop - modelTrackContainerRect.top;
295           result.height = eventHeight;
296           result.snapped = true;
297         }
298       }
299
300       return result;
301     }
302   };
303
304   return {
305     TimingTool: TimingTool
306   };
307 });
308 </script>