Version 1
[yaffs-website] / web / modules / contrib / devel / webprofiler / js / timeline.js
1 /**
2  * @file
3  * Timeline panel app.
4  */
5 (function ($, Drupal, drupalSettings, d3) {
6
7   'use strict';
8
9   Drupal.behaviors.webprofiler_timeline = {
10     attach: function (context) {
11       if (typeof d3 != 'undefined') {
12
13         // data
14         var data = drupalSettings.webprofiler.time.events;
15         var parts = [];
16         var dataL = data.length;
17         var perL;
18         var labelW = [];
19         var rowW;
20         var scalePadding;
21         var endTime = parseInt(data[(dataL - 1)].endtime);
22         var roundTime = Math.ceil(endTime / 1000) * 1000;
23         var endScale;
24
25         for (var j = 0; j < dataL; j++) {
26           perL = data[j].periods.length;
27           for (var k = 0; k < perL; k++) {
28             parts.push({
29               lane: j,
30               category: data[j].category,
31               memory: data[j].memory,
32               name: data[j].name,
33               start: data[j].periods[k].start,
34               end: data[j].periods[k].end
35             });
36           }
37         }
38
39         var tooltipCtrl = function (d, i) {
40           tooltip.html('<span class="tooltip__content">memory usage: ' + d.memory + '</span>' +
41           '<span class="tooltip__content">' + parseInt(d.start) + 'ms ~ ' + parseInt(d.end) + 'ms</span>');
42           tooltip
43             .style('display', 'block')
44             .style('left', (d3.event.layerX - 87) + 'px')
45             .style('top', ((d.lane + 1) * 22) + 'px')
46             .style('opacity', .9);
47         };
48
49         var xscale = d3.scale.linear().domain([0, roundTime]).range([0, 1000]);
50         d3.select('#timeline').append('svg').attr('height', (dataL + 1) * 22 + 'px').attr('width', '100%').attr('class', 'timeline__canvas');
51
52         // tooltips
53         var tooltip = d3.select('#timeline')
54           .append('div')
55           .attr('class', 'tooltip');
56
57
58         // Add a rectangle for every data element.
59         d3.select('.timeline__canvas')
60             .append('g')
61             .attr('class', 'timeline__rows')
62             .attr('x', 0)
63             .attr('y', 0)
64             .selectAll('g')
65             .data(data)
66             .enter()
67             .append('rect')
68             .attr('class', 'timeline__row')
69             .attr('x', 0)
70             .attr('y', function (d, i) {
71               return (i * 22);
72             })
73             .attr('height', 22)
74             .attr('width', '100%')
75             .each(function () {
76               rowW = this.getBoundingClientRect().width;
77             });
78
79         // scale
80         var scale = d3.select('.timeline__canvas')
81           .append('g')
82           .attr('class', 'timeline__scale')
83           .attr('id', 'timeline__scale')
84           .attr('x', 0)
85           .attr('y', 0)
86           .selectAll('g')
87           .data(data)
88           .enter()
89           .append('a')
90           .attr('xlink:href', function (d) {
91             return Drupal.webprofiler.helpers.ideLink(d.link);
92           })
93           .attr('class', function (d) {
94             return 'timeline__label ' + d.category;
95           })
96           .attr('x', xscale(5))
97           .attr('y', function (d, i) {
98             return (((i + 1) * 22) - 5);
99           });
100
101         scale.append('title')
102           .text(function (d) {
103             return d.name;
104           });
105
106         scale.append('text')
107           .attr('x', xscale(5))
108           .attr('y', function (d, i) {
109             return (((i + 1) * 22) - 5);
110           })
111           .text(function (d) {
112             return Drupal.webprofiler.helpers.shortLink(d.name);
113           })
114           .each(function (d) {
115             labelW.push(this.getBoundingClientRect().width);
116           });
117
118         scalePadding = Math.max.apply(null, labelW) + 10;
119
120         scale.insert('rect', 'title')
121           .attr('x', 0)
122           .attr('y', function (d, i) {
123             return (i * 22);
124           })
125           .attr('height', 22)
126           .attr('stroke', 'transparent')
127           .attr('strokw-width', 1)
128           .attr('width', scalePadding);
129
130         // times
131         var events = d3.select('.timeline__canvas')
132           .insert('g', '.timeline__scale')
133           .attr('class', 'timeline__parts')
134           .attr('x', 0)
135           .attr('y', 0)
136           .selectAll('g')
137           .data(parts)
138           .enter();
139
140         events.append('rect').attr('class', function (d) {
141           return 'timeline__period--' + d.category;
142         })
143           .attr('x', function (d) {
144             return xscale(parseInt(d.start)) + scalePadding;
145           })
146           .attr('y', function (d) {
147             return d.lane * 22;
148           })
149           .attr('height', 22)
150           .attr('width', function (d) {
151             return xscale(Math.max(parseInt(d.end - d.start), 1));
152           });
153
154         events.append('rect')
155           .attr('class', function (d) {
156             return 'timeline__period-trigger';
157           })
158           .attr('x', function (d) {
159             return xscale(parseInt(d.start)) + scalePadding - 5;
160           })
161           .attr('y', function (d) {
162             return d.lane * 22;
163           })
164           .attr('height', 22)
165           .attr('width', function (d) {
166             return xscale(Math.max(parseInt(d.end - d.start), 1)) + 11;
167           })
168           .on('mouseover', function (d, i) {
169             tooltipCtrl(d, i);
170           })
171           .on('mouseout', function (d) {
172             tooltip
173             .style('display', 'none');
174           });
175
176         // Draw X-axis grid lines
177         d3.select('.timeline__parts').insert('g', '.timeline__parts')
178           .selectAll('line')
179           .data(xscale.ticks(10))
180           .enter()
181           .append('line')
182           .attr('class', 'timeline__scale--x')
183           .attr('x1', xscale)
184           .attr('x2', xscale)
185           .attr('y1', 0)
186           .attr('y2', data.length * 22)
187           .attr('transform', 'translate( ' + scalePadding + ' , 0)');
188
189         var xAxis = d3.svg.axis().scale(xscale).ticks(10).orient('bottom').tickFormat(function (d) {
190           return d + ' ms';
191         });
192
193         d3.select('.timeline__parts').insert('g', '.timeline__parts')
194           .attr('class', 'axis')
195           .attr('transform', 'translate(' + scalePadding + ', ' + dataL * 22 + ')')
196           .call(xAxis);
197
198         endScale = xscale(endTime) - rowW - parseInt(scalePadding);
199
200         if (parseInt(xscale(endTime)) > (rowW - parseInt(scalePadding))) {
201           d3.select('.timeline__canvas')
202             .call(
203             d3.behavior.zoom()
204                 .scaleExtent([1, 1])
205                 .x(xscale)
206                 .on('zoom', function () {
207
208                   var t = d3.event.translate;
209                   var tx = t[0];
210
211                   tx = tx > 0 ? 0 : tx;
212
213                   tx = tx < endScale ? endScale : tx;
214
215                   d3.select('.timeline__parts').attr('transform', 'translate( ' + tx + ' , 0)');
216                 }));
217         }
218
219       }
220     }
221   };
222
223 })(jQuery, Drupal, drupalSettings, d3);