5 (function ($, Drupal, drupalSettings, d3) {
9 Drupal.behaviors.webprofiler_timeline = {
10 attach: function (context) {
11 if (typeof d3 != 'undefined') {
14 var data = drupalSettings.webprofiler.time.events;
16 var dataL = data.length;
21 var endTime = parseInt(data[(dataL - 1)].endtime);
22 var roundTime = Math.ceil(endTime / 1000) * 1000;
25 for (var j = 0; j < dataL; j++) {
26 perL = data[j].periods.length;
27 for (var k = 0; k < perL; k++) {
30 category: data[j].category,
31 memory: data[j].memory,
33 start: data[j].periods[k].start,
34 end: data[j].periods[k].end
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>');
43 .style('display', 'block')
44 .style('left', (d3.event.layerX - 87) + 'px')
45 .style('top', ((d.lane + 1) * 22) + 'px')
46 .style('opacity', .9);
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');
53 var tooltip = d3.select('#timeline')
55 .attr('class', 'tooltip');
58 // Add a rectangle for every data element.
59 d3.select('.timeline__canvas')
61 .attr('class', 'timeline__rows')
68 .attr('class', 'timeline__row')
70 .attr('y', function (d, i) {
74 .attr('width', '100%')
76 rowW = this.getBoundingClientRect().width;
80 var scale = d3.select('.timeline__canvas')
82 .attr('class', 'timeline__scale')
83 .attr('id', 'timeline__scale')
90 .attr('xlink:href', function (d) {
91 return Drupal.webprofiler.helpers.ideLink(d.link);
93 .attr('class', function (d) {
94 return 'timeline__label ' + d.category;
97 .attr('y', function (d, i) {
98 return (((i + 1) * 22) - 5);
101 scale.append('title')
107 .attr('x', xscale(5))
108 .attr('y', function (d, i) {
109 return (((i + 1) * 22) - 5);
112 return Drupal.webprofiler.helpers.shortLink(d.name);
115 labelW.push(this.getBoundingClientRect().width);
118 scalePadding = Math.max.apply(null, labelW) + 10;
120 scale.insert('rect', 'title')
122 .attr('y', function (d, i) {
126 .attr('stroke', 'transparent')
127 .attr('strokw-width', 1)
128 .attr('width', scalePadding);
131 var events = d3.select('.timeline__canvas')
132 .insert('g', '.timeline__scale')
133 .attr('class', 'timeline__parts')
140 events.append('rect').attr('class', function (d) {
141 return 'timeline__period--' + d.category;
143 .attr('x', function (d) {
144 return xscale(parseInt(d.start)) + scalePadding;
146 .attr('y', function (d) {
150 .attr('width', function (d) {
151 return xscale(Math.max(parseInt(d.end - d.start), 1));
154 events.append('rect')
155 .attr('class', function (d) {
156 return 'timeline__period-trigger';
158 .attr('x', function (d) {
159 return xscale(parseInt(d.start)) + scalePadding - 5;
161 .attr('y', function (d) {
165 .attr('width', function (d) {
166 return xscale(Math.max(parseInt(d.end - d.start), 1)) + 11;
168 .on('mouseover', function (d, i) {
171 .on('mouseout', function (d) {
173 .style('display', 'none');
176 // Draw X-axis grid lines
177 d3.select('.timeline__parts').insert('g', '.timeline__parts')
179 .data(xscale.ticks(10))
182 .attr('class', 'timeline__scale--x')
186 .attr('y2', data.length * 22)
187 .attr('transform', 'translate( ' + scalePadding + ' , 0)');
189 var xAxis = d3.svg.axis().scale(xscale).ticks(10).orient('bottom').tickFormat(function (d) {
193 d3.select('.timeline__parts').insert('g', '.timeline__parts')
194 .attr('class', 'axis')
195 .attr('transform', 'translate(' + scalePadding + ', ' + dataL * 22 + ')')
198 endScale = xscale(endTime) - rowW - parseInt(scalePadding);
200 if (parseInt(xscale(endTime)) > (rowW - parseInt(scalePadding))) {
201 d3.select('.timeline__canvas')
206 .on('zoom', function () {
208 var t = d3.event.translate;
211 tx = tx > 0 ? 0 : tx;
213 tx = tx < endScale ? endScale : tx;
215 d3.select('.timeline__parts').attr('transform', 'translate( ' + tx + ' , 0)');
223 })(jQuery, Drupal, drupalSettings, d3);