Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / tracks / ruler_track.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="stylesheet" href="/tracing/tracks/ruler_track.css">
9
10 <link rel="import" href="/tracing/constants.html">
11 <link rel="import" href="/tracing/tracks/track.html">
12 <link rel="import" href="/tracing/tracks/heading_track.html">
13 <link rel="import" href="/tracing/draw_helpers.html">
14 <link rel="import" href="/tvcm/ui.html">
15
16 <script>
17 'use strict';
18
19 tvcm.exportTo('tracing.tracks', function() {
20   /**
21    * A track that displays the ruler.
22    * @constructor
23    * @extends {HeadingTrack}
24    */
25   var RulerTrack = tvcm.ui.define('ruler-track', tracing.tracks.HeadingTrack);
26
27   var logOf10 = Math.log(10);
28   function log10(x) {
29     return Math.log(x) / logOf10;
30   }
31
32   RulerTrack.prototype = {
33     __proto__: tracing.tracks.HeadingTrack.prototype,
34
35     decorate: function(viewport) {
36       tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
37       this.classList.add('ruler-track');
38       this.strings_secs_ = [];
39       this.strings_msecs_ = [];
40
41       this.viewportChange_ = this.viewportChange_.bind(this);
42       viewport.addEventListener('change', this.viewportChange_);
43
44     },
45
46     detach: function() {
47       tracing.tracks.HeadingTrack.prototype.detach.call(this);
48       this.viewport.removeEventListener('change',
49                                         this.viewportChange_);
50     },
51
52     viewportChange_: function() {
53       if (this.viewport.interestRange.isEmpty)
54         this.classList.remove('tall-mode');
55       else
56         this.classList.add('tall-mode');
57     },
58
59     draw: function(type, viewLWorld, viewRWorld) {
60       switch (type) {
61         case tracing.tracks.DrawType.SLICE:
62           this.drawSlices_(viewLWorld, viewRWorld);
63           break;
64         case tracing.tracks.DrawType.MARKERS:
65           if (!this.viewport.interestRange.isEmpty)
66             this.viewport.interestRange.draw(this.context(),
67                                              viewLWorld, viewRWorld);
68           break;
69       }
70     },
71
72     drawSlices_: function(viewLWorld, viewRWorld) {
73       var ctx = this.context();
74       var pixelRatio = window.devicePixelRatio || 1;
75
76       var bounds = ctx.canvas.getBoundingClientRect();
77       var width = bounds.width * pixelRatio;
78       var height = bounds.height * pixelRatio;
79
80       var hasInterestRange = !this.viewport.interestRange.isEmpty;
81
82       var rulerHeight = hasInterestRange ? (height * 2) / 5 : height;
83
84       var vp = this.viewport;
85       var dt = vp.currentDisplayTransform;
86
87       var idealMajorMarkDistancePix = 150 * pixelRatio;
88       var idealMajorMarkDistanceWorld =
89           dt.xViewVectorToWorld(idealMajorMarkDistancePix);
90
91       var majorMarkDistanceWorld;
92
93       // The conservative guess is the nearest enclosing 0.1, 1, 10, 100, etc.
94       var conservativeGuess =
95           Math.pow(10, Math.ceil(log10(idealMajorMarkDistanceWorld)));
96
97       // Once we have a conservative guess, consider things that evenly add up
98       // to the conservative guess, e.g. 0.5, 0.2, 0.1 Pick the one that still
99       // exceeds the ideal mark distance.
100       var divisors = [10, 5, 2, 1];
101       for (var i = 0; i < divisors.length; ++i) {
102         var tightenedGuess = conservativeGuess / divisors[i];
103         if (dt.xWorldVectorToView(tightenedGuess) < idealMajorMarkDistancePix)
104           continue;
105         majorMarkDistanceWorld = conservativeGuess / divisors[i - 1];
106         break;
107       }
108
109       var unit;
110       var unitDivisor;
111       var tickLabels = undefined;
112       if (majorMarkDistanceWorld < 100) {
113         unit = 'ms';
114         unitDivisor = 1;
115         tickLabels = this.strings_msecs_;
116       } else {
117         unit = 's';
118         unitDivisor = 1000;
119         tickLabels = this.strings_secs_;
120       }
121
122       var numTicksPerMajor = 5;
123       var minorMarkDistanceWorld = majorMarkDistanceWorld / numTicksPerMajor;
124       var minorMarkDistancePx = dt.xWorldVectorToView(minorMarkDistanceWorld);
125
126       var firstMajorMark =
127           Math.floor(viewLWorld / majorMarkDistanceWorld) *
128               majorMarkDistanceWorld;
129
130       var minorTickH = Math.floor(rulerHeight * 0.25);
131
132       ctx.save();
133
134       var pixelRatio = window.devicePixelRatio || 1;
135       ctx.lineWidth = Math.round(pixelRatio);
136
137       // Apply subpixel translate to get crisp lines.
138       // http://www.mobtowers.com/html5-canvas-crisp-lines-every-time/
139       var crispLineCorrection = (ctx.lineWidth % 2) / 2;
140       ctx.translate(crispLineCorrection, -crispLineCorrection);
141
142       ctx.fillStyle = 'rgb(0, 0, 0)';
143       ctx.strokeStyle = 'rgb(0, 0, 0)';
144       ctx.textAlign = 'left';
145       ctx.textBaseline = 'top';
146
147       ctx.font = (9 * pixelRatio) + 'px sans-serif';
148
149       vp.majorMarkPositions = [];
150
151       // Each iteration of this loop draws one major mark
152       // and numTicksPerMajor minor ticks.
153       //
154       // Rendering can't be done in world space because canvas transforms
155       // affect line width. So, do the conversions manually.
156       ctx.beginPath();
157       for (var curX = firstMajorMark;
158            curX < viewRWorld;
159            curX += majorMarkDistanceWorld) {
160
161         var curXView = Math.floor(dt.xWorldToView(curX));
162
163         var unitValue = curX / unitDivisor;
164         var roundedUnitValue = Math.floor(unitValue * 100000) / 100000;
165
166         if (!tickLabels[roundedUnitValue])
167           tickLabels[roundedUnitValue] = roundedUnitValue + ' ' + unit;
168         ctx.fillText(tickLabels[roundedUnitValue],
169                      curXView + (2 * pixelRatio), 0);
170
171         vp.majorMarkPositions.push(curXView);
172
173         // Major mark
174         tracing.drawLine(ctx, curXView, 0, curXView, rulerHeight);
175
176         // Minor marks
177         for (var i = 1; i < numTicksPerMajor; ++i) {
178           var xView = Math.floor(curXView + minorMarkDistancePx * i);
179           tracing.drawLine(ctx,
180               xView, rulerHeight - minorTickH,
181               xView, rulerHeight);
182         }
183       }
184
185       // Draw bottom bar.
186       ctx.strokeStyle = 'rgb(0, 0, 0)';
187       tracing.drawLine(ctx, 0, height, width, height);
188       ctx.stroke();
189
190       // Give distance between directly adjacent markers.
191       if (!hasInterestRange)
192         return;
193
194       // Draw middle bar.
195       tracing.drawLine(ctx, 0, rulerHeight, width, rulerHeight);
196       ctx.stroke();
197
198       // Distance Variables.
199       var displayDistance;
200       var displayTextColor = 'rgb(0,0,0)';
201
202       // Arrow Variables.
203       var arrowSpacing = 10 * pixelRatio;
204       var arrowColor = 'rgb(128,121,121)';
205       var arrowPosY = rulerHeight * 1.75;
206       var arrowWidthView = 3 * pixelRatio;
207       var arrowLengthView = 10 * pixelRatio;
208       var spaceForArrowsView = 2 * (arrowWidthView + arrowSpacing);
209
210       ctx.textBaseline = 'middle';
211       ctx.font = (14 * pixelRatio) + 'px sans-serif';
212       var textPosY = arrowPosY;
213
214       var interestRange = vp.interestRange;
215
216       // If the range is zero, draw it's min timestamp next to the line.
217       if (interestRange.range === 0) {
218         var markerWorld = interestRange.min;
219         var markerView = dt.xWorldToView(markerWorld);
220         var displayValue = markerWorld / unitDivisor;
221         displayValue = Math.abs((Math.floor(displayValue * 1000) / 1000));
222
223         var textToDraw = displayValue + ' ' + unit;
224         var textLeftView = markerView + 4 * pixelRatio;
225         var textWidthView = ctx.measureText(textToDraw).width;
226
227         // Put text to the left in case it gets cut off.
228         if (textLeftView + textWidthView > width)
229           textLeftView = markerView - 4 * pixelRatio - textWidthView;
230
231         ctx.fillStyle = displayTextColor;
232         ctx.fillText(textToDraw, textLeftView, textPosY);
233         return;
234       }
235
236       var leftMarker = interestRange.min;
237       var rightMarker = interestRange.max;
238
239       var leftMarkerView = dt.xWorldToView(leftMarker);
240       var rightMarkerView = dt.xWorldToView(rightMarker);
241
242       var distanceBetweenMarkers = interestRange.range;
243       var distanceBetweenMarkersView =
244           dt.xWorldVectorToView(distanceBetweenMarkers);
245       var positionInMiddleOfMarkersView =
246           leftMarkerView + (distanceBetweenMarkersView / 2);
247
248       // Determine units.
249       if (distanceBetweenMarkers < 100) {
250         unit = 'ms';
251         unitDivisor = 1;
252       } else {
253         unit = 's';
254         unitDivisor = 1000;
255       }
256
257       // Calculate display value to print.
258       displayDistance = distanceBetweenMarkers / unitDivisor;
259       var roundedDisplayDistance =
260           Math.abs((Math.floor(displayDistance * 1000) / 1000));
261       var textToDraw = roundedDisplayDistance + ' ' + unit;
262       var textWidthView = ctx.measureText(textToDraw).width;
263       var spaceForArrowsAndTextView =
264           textWidthView + spaceForArrowsView + arrowSpacing;
265
266       // Set text positions.
267       var textLeftView = positionInMiddleOfMarkersView - textWidthView / 2;
268       var textRightView = textLeftView + textWidthView;
269
270       if (spaceForArrowsAndTextView > distanceBetweenMarkersView) {
271         // Print the display distance text right of the 2 markers.
272         textLeftView = rightMarkerView + 2 * arrowSpacing;
273
274         // Put text to the left in case it gets cut off.
275         if (textLeftView + textWidthView > width)
276           textLeftView = leftMarkerView - 2 * arrowSpacing - textWidthView;
277
278         ctx.fillStyle = displayTextColor;
279         ctx.fillText(textToDraw, textLeftView, textPosY);
280
281         // Draw the arrows pointing from outside in and a line in between.
282         ctx.strokeStyle = arrowColor;
283         ctx.beginPath();
284         tracing.drawLine(ctx, leftMarkerView, arrowPosY, rightMarkerView,
285             arrowPosY);
286         ctx.stroke();
287
288         ctx.fillStyle = arrowColor;
289         tracing.drawArrow(ctx,
290             leftMarkerView - 1.5 * arrowSpacing, arrowPosY,
291             leftMarkerView, arrowPosY,
292             arrowLengthView, arrowWidthView);
293         tracing.drawArrow(ctx,
294             rightMarkerView + 1.5 * arrowSpacing, arrowPosY,
295             rightMarkerView, arrowPosY,
296             arrowLengthView, arrowWidthView);
297
298       } else if (spaceForArrowsView <= distanceBetweenMarkersView) {
299         var leftArrowStart;
300         var rightArrowStart;
301         if (spaceForArrowsAndTextView <= distanceBetweenMarkersView) {
302           // Print the display distance text.
303           ctx.fillStyle = displayTextColor;
304           ctx.fillText(textToDraw, textLeftView, textPosY);
305
306           leftArrowStart = textLeftView - arrowSpacing;
307           rightArrowStart = textRightView + arrowSpacing;
308         } else {
309           leftArrowStart = positionInMiddleOfMarkersView;
310           rightArrowStart = positionInMiddleOfMarkersView;
311         }
312
313         // Draw the arrows pointing inside out.
314         ctx.strokeStyle = arrowColor;
315         ctx.fillStyle = arrowColor;
316         tracing.drawArrow(ctx,
317             leftArrowStart, arrowPosY,
318             leftMarkerView, arrowPosY,
319             arrowLengthView, arrowWidthView);
320         tracing.drawArrow(ctx,
321             rightArrowStart, arrowPosY,
322             rightMarkerView, arrowPosY,
323             arrowLengthView, arrowWidthView);
324       }
325
326       ctx.restore();
327     },
328
329     /**
330      * Adds items intersecting the given range to a selection.
331      * @param {number} loVX Lower X bound of the interval to search, in
332      *     viewspace.
333      * @param {number} hiVX Upper X bound of the interval to search, in
334      *     viewspace.
335      * @param {number} loVY Lower Y bound of the interval to search, in
336      *     viewspace.
337      * @param {number} hiVY Upper Y bound of the interval to search, in
338      *     viewspace.
339      * @param {Selection} selection Selection to which to add results.
340      */
341     addIntersectingItemsInRangeToSelection: function(
342         loVX, hiVX, loY, hiY, selection) {
343       // Does nothing. There's nothing interesting to pick on the ruler
344       // track.
345     },
346
347     addAllObjectsMatchingFilterToSelection: function(filter, selection) {
348     }
349   };
350
351   return {
352     RulerTrack: RulerTrack
353   };
354 });
355 </script>