Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / tracks / counter_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/counter_track.css">
9
10 <link rel="import" href="/tracing/trace_model/event.html">
11 <link rel="import" href="/tracing/tracks/heading_track.html">
12 <link rel="import" href="/tracing/color_scheme.html">
13 <link rel="import" href="/base/ui.html">
14
15 <script>
16 'use strict';
17
18 tv.exportTo('tracing.tracks', function() {
19
20   var SelectionState = tracing.trace_model.SelectionState;
21   var EventPresenter = tracing.EventPresenter;
22   var LAST_SAMPLE_PIXELS = 8;
23
24   var LINE_WIDTH = 1;
25   var BACKGROUND_ALPHA_MULTIPLIER = 0.5;
26   var SQUARE_WIDTH = 3; // Unselected sample point.
27   var CIRCLE_RADIUS = 2; // Selected sample point.
28
29   var POINT_DENSITY_TRANSPARENT = 0.10;
30   var POINT_DENSITY_OPAQUE = 0.05;
31   var POINT_DENSITY_RANGE = POINT_DENSITY_TRANSPARENT - POINT_DENSITY_OPAQUE;
32
33   /**
34    * A track that displays a Counter object.
35    * @constructor
36    * @extends {HeadingTrack}
37    */
38
39   var CounterTrack =
40       tv.ui.define('counter-track', tracing.tracks.HeadingTrack);
41
42   CounterTrack.prototype = {
43     __proto__: tracing.tracks.HeadingTrack.prototype,
44
45     decorate: function(viewport) {
46       tracing.tracks.HeadingTrack.prototype.decorate.call(this, viewport);
47       this.classList.add('counter-track');
48     },
49
50     get counter() {
51       return this.counter_;
52     },
53
54     set counter(counter) {
55       this.counter_ = counter;
56       this.heading = counter.name + ': ';
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       }
65     },
66
67     drawSlices_: function(viewLWorld, viewRWorld) {
68       var ctx = this.context();
69       var pixelRatio = window.devicePixelRatio || 1;
70
71       var bounds = this.getBoundingClientRect();
72       var height = bounds.height * pixelRatio;
73
74       var counter = this.counter_;
75
76       // Culling parametrs.
77       var vp = this.viewport;
78       var dt = vp.currentDisplayTransform;
79       var pixWidth = dt.xViewVectorToWorld(1);
80
81       // Drop samples that are less than skipDistancePix apart.
82       var skipDistancePix = 1;
83       var skipDistanceWorld = dt.xViewVectorToWorld(skipDistancePix);
84
85       // Figure out where drawing should begin.
86       var numSeries = counter.numSeries;
87       var numSamples = counter.numSamples;
88       var startIndex = tv.findLowIndexInSortedArray(
89           counter.timestamps,
90           function(x) { return x; },
91           viewLWorld);
92       var timestamps = counter.timestamps;
93
94       startIndex = startIndex - 1 > 0 ? startIndex - 1 : 0;
95       // Draw indices one by one until we fall off the viewRWorld.
96       var yScale = height / counter.maxTotal;
97
98       for (var seriesIndex = counter.numSeries - 1;
99            seriesIndex >= 0; seriesIndex--) {
100         var series = counter.series[seriesIndex];
101         ctx.strokeStyle = EventPresenter.getCounterSeriesColor(
102             series.color, SelectionState.NONE);
103
104         // Draw the background and the line.
105         var drawSeries = function(background) {
106           var selectionStateLast = -1;
107
108           // Set i and x such that the first sample we draw is the
109           // startIndex sample.
110           var i = startIndex - 1;
111           var xLast = i >= 0 ?
112               timestamps[i] - skipDistanceWorld : -1;
113           var yLastView = height;
114
115           // Iterate over samples from i onward until we either fall off the
116           // viewRWorld or we run out of samples. To avoid drawing too much,
117           // after drawing a sample at xLast, skip subsequent samples that are
118           // less than skipDistanceWorld from xLast.
119           var hasMoved = false;
120
121           while (true) {
122             i++;
123             if (i >= numSamples) {
124               break;
125             }
126
127             var x = timestamps[i];
128             var y = counter.totals[i * numSeries + seriesIndex];
129             var yView = height - (yScale * y);
130
131             // If the sample is to the right of the viewport, we add a fixed
132             // margin to reduce zooming clipping errors.
133             if (x > viewRWorld) {
134               if (hasMoved) {
135                 xLast = x = viewRWorld;
136                 ctx.lineTo(dt.xWorldToView(x), yLastView);
137               }
138               break;
139             }
140
141             if (i + 1 < numSamples) {
142               var xNext = timestamps[i + 1];
143               if (xNext - xLast <= skipDistanceWorld && xNext < viewRWorld) {
144                 continue;
145               }
146
147               // If the sample is to the left of the viewport, we add a fixed
148               // margin to reduce zooming clipping errors.
149               if (x < viewLWorld) {
150                 x = viewLWorld;
151               }
152             }
153
154             if (x - xLast < skipDistanceWorld && xLast < x) {
155               // We know that xNext > xLast + skipDistanceWorld, so we can
156               // safely move this sample's x over that much without passing
157               // xNext.  This ensure that the previous sample is visible when
158               // zoomed out very far.
159               x = xLast + skipDistanceWorld;
160             }
161
162             var selectionState = series.samples[i].selectionState;
163
164             if (hasMoved) {
165               ctx.lineTo(dt.xWorldToView(x), yLastView);
166               if (selectionState != selectionStateLast) {
167                 if (background) {
168                   ctx.lineTo(dt.xWorldToView(x), height);
169                   ctx.closePath();
170                   ctx.fill();
171                 } else {
172                   ctx.lineTo(dt.xWorldToView(x), yView);
173                   ctx.stroke();
174                 }
175               }
176             }
177
178             if (selectionState != selectionStateLast) {
179               ctx.fillStyle = EventPresenter.getCounterSeriesColor(
180                   series.color, selectionState, BACKGROUND_ALPHA_MULTIPLIER);
181               ctx.lineWidth = LINE_WIDTH * pixelRatio;
182               ctx.beginPath();
183
184               if (background) {
185                 ctx.moveTo(dt.xWorldToView(x), height);
186               } else {
187                 ctx.moveTo(dt.xWorldToView(x), hasMoved ? yLastView : yView);
188               }
189             }
190
191             if (background) {
192                 ctx.lineTo(dt.xWorldToView(x), yView);
193             } else {
194                 ctx.lineTo(dt.xWorldToView(x), yView);
195             }
196
197             hasMoved = true;
198             xLast = x;
199             yLastView = yView;
200             selectionStateLast = selectionState;
201           }
202
203           if (hasMoved) {
204             if (background) {
205               ctx.lineTo(dt.xWorldToView(xLast), height);
206               ctx.closePath();
207               ctx.fill();
208             } else {
209               ctx.stroke();
210             }
211           }
212         }
213
214         drawSeries(true);
215         drawSeries(false);
216
217         // Calculate point density and, consequently, opacity of sample points.
218         var endIndex = tv.findLowIndexInSortedArray(
219             counter.timestamps, function(x) { return x; }, viewRWorld);
220         if (counter.timestamps[endIndex] == viewRWorld) {
221           endIndex++;
222         }
223         var minVisible = (startIndex >= counter.timestamps.length ?
224                           viewLWorld : counter.timestamps[startIndex]);
225         var maxVisible = (endIndex < 1 ?
226                           viewRWorld : counter.timestamps[endIndex - 1]);
227         var rangeVisible = (minVisible >= maxVisible ?
228                             viewRWorld - viewLWorld : maxVisible - minVisible);
229
230         var density = (endIndex - startIndex) / (dt.scaleX * rangeVisible);
231         var clampedDensity = tv.clamp(density, POINT_DENSITY_OPAQUE,
232                                       POINT_DENSITY_TRANSPARENT);
233         var opacity =
234             (POINT_DENSITY_TRANSPARENT - clampedDensity) / POINT_DENSITY_RANGE;
235
236         // Draw sample points.
237         ctx.strokeStyle = EventPresenter.getCounterSeriesColor(
238             series.color, SelectionState.NONE);
239         for (var i = startIndex; timestamps[i] < viewRWorld; i++) {
240           var x = timestamps[i];
241           var y = counter.totals[i * numSeries + seriesIndex];
242           var yView = height - (yScale * y);
243
244           if (series.samples[i].selected) {
245             ctx.fillStyle = EventPresenter.getCounterSeriesColor(
246               series.color, series.samples[i].selectionState);
247             ctx.beginPath();
248             ctx.arc(dt.xWorldToView(x), yView, CIRCLE_RADIUS * pixelRatio, 0,
249                     2 * Math.PI);
250             ctx.fill();
251             ctx.stroke();
252           } else {
253             ctx.fillStyle = EventPresenter.getCounterSeriesColor(
254                 series.color, series.samples[i].selectionState, opacity);
255             ctx.fillRect(dt.xWorldToView(x) - (SQUARE_WIDTH / 2) * pixelRatio,
256                          yView - (SQUARE_WIDTH / 2) * pixelRatio,
257                          SQUARE_WIDTH * pixelRatio, SQUARE_WIDTH * pixelRatio);
258           }
259         }
260       }
261     },
262
263     addEventsToTrackMap: function(eventToTrackMap) {
264       var allSeries = this.counter_.series;
265       for (var seriesIndex = 0; seriesIndex < allSeries.length; seriesIndex++) {
266         var samples = allSeries[seriesIndex].samples;
267         for (var i = 0; i < samples.length; i++)
268           eventToTrackMap.addEvent(samples[i], this);
269       }
270     },
271
272     addIntersectingItemsInRangeToSelectionInWorldSpace: function(
273         loWX, hiWX, viewPixWidthWorld, selection) {
274
275       function getSampleWidth(x, i) {
276         if (i === counter.timestamps.length - 1) {
277           var dt = this.viewport.currentDisplayTransform;
278           var pixWidth = dt.xViewVectorToWorld(1);
279           return LAST_SAMPLE_PIXELS * pixWidth;
280         }
281         return counter.timestamps[i + 1] - counter.timestamps[i];
282       }
283
284       var counter = this.counter_;
285       var iLo = tv.findLowIndexInSortedIntervals(counter.timestamps,
286                                                    function(x) { return x; },
287                                                    getSampleWidth.bind(this),
288                                                    loWX);
289       var iHi = tv.findLowIndexInSortedIntervals(counter.timestamps,
290                                                    function(x) { return x; },
291                                                    getSampleWidth.bind(this),
292                                                    hiWX);
293
294       // Iterate over every sample intersecting..
295       for (var sampleIndex = iLo; sampleIndex <= iHi; sampleIndex++) {
296         if (sampleIndex < 0)
297           continue;
298         if (sampleIndex >= counter.timestamps.length)
299           continue;
300
301         // TODO(nduca): Pick the seriesIndexHit based on the loY - hiY values.
302         for (var seriesIndex = 0;
303              seriesIndex < this.counter.numSeries;
304              seriesIndex++) {
305           var series = this.counter.series[seriesIndex];
306           selection.push(series.samples[sampleIndex]);
307         }
308       }
309     },
310
311     addItemNearToProvidedEventToSelection: function(sample, offset, selection) {
312       var index = sample.getSampleIndex();
313       var newIndex = index + offset;
314       if (newIndex < 0 || newIndex >= sample.series.samples.length)
315         return false;
316
317       selection.push(sample.series.samples[newIndex]);
318       return true;
319     },
320
321     addAllObjectsMatchingFilterToSelection: function(filter, selection) {
322     },
323
324     addClosestEventToSelection: function(worldX, worldMaxDist, loY, hiY,
325                                          selection) {
326       var counter = this.counter;
327       if (!counter.numSeries)
328         return;
329
330       var stackHeight = 0;
331
332       for (var i = 0; i < counter.numSeries; i++) {
333         var counterSample = tv.findClosestElementInSortedArray(
334             counter.series_[i].samples_,
335             function(x) { return x.timestamp; },
336             worldX,
337             worldMaxDist);
338
339         if (!counterSample)
340           continue;
341
342         selection.push(counterSample);
343       }
344     }
345   };
346
347   return {
348     CounterTrack: CounterTrack
349   };
350 });
351 </script>