/**
* @file
* Timeline panel app.
*/
(function ($, Drupal, drupalSettings, d3) {
'use strict';
Drupal.behaviors.webprofiler_timeline = {
attach: function (context) {
if (typeof d3 != 'undefined') {
// data
var data = drupalSettings.webprofiler.time.events;
var parts = [];
var dataL = data.length;
var perL;
var labelW = [];
var rowW;
var scalePadding;
var endTime = parseInt(data[(dataL - 1)].endtime);
var roundTime = Math.ceil(endTime / 1000) * 1000;
var endScale;
for (var j = 0; j < dataL; j++) {
perL = data[j].periods.length;
for (var k = 0; k < perL; k++) {
parts.push({
lane: j,
category: data[j].category,
memory: data[j].memory,
name: data[j].name,
start: data[j].periods[k].start,
end: data[j].periods[k].end
});
}
}
var tooltipCtrl = function (d, i) {
tooltip.html('memory usage: ' + d.memory + '' +
'' + parseInt(d.start) + 'ms ~ ' + parseInt(d.end) + 'ms');
tooltip
.style('display', 'block')
.style('left', (d3.event.layerX - 87) + 'px')
.style('top', ((d.lane + 1) * 22) + 'px')
.style('opacity', .9);
};
var xscale = d3.scale.linear().domain([0, roundTime]).range([0, 1000]);
d3.select('#timeline').append('svg').attr('height', (dataL + 1) * 22 + 'px').attr('width', '100%').attr('class', 'timeline__canvas');
// tooltips
var tooltip = d3.select('#timeline')
.append('div')
.attr('class', 'tooltip');
// Add a rectangle for every data element.
d3.select('.timeline__canvas')
.append('g')
.attr('class', 'timeline__rows')
.attr('x', 0)
.attr('y', 0)
.selectAll('g')
.data(data)
.enter()
.append('rect')
.attr('class', 'timeline__row')
.attr('x', 0)
.attr('y', function (d, i) {
return (i * 22);
})
.attr('height', 22)
.attr('width', '100%')
.each(function () {
rowW = this.getBoundingClientRect().width;
});
// scale
var scale = d3.select('.timeline__canvas')
.append('g')
.attr('class', 'timeline__scale')
.attr('id', 'timeline__scale')
.attr('x', 0)
.attr('y', 0)
.selectAll('g')
.data(data)
.enter()
.append('a')
.attr('xlink:href', function (d) {
return Drupal.webprofiler.helpers.ideLink(d.link);
})
.attr('class', function (d) {
return 'timeline__label ' + d.category;
})
.attr('x', xscale(5))
.attr('y', function (d, i) {
return (((i + 1) * 22) - 5);
});
scale.append('title')
.text(function (d) {
return d.name;
});
scale.append('text')
.attr('x', xscale(5))
.attr('y', function (d, i) {
return (((i + 1) * 22) - 5);
})
.text(function (d) {
return Drupal.webprofiler.helpers.shortLink(d.name);
})
.each(function (d) {
labelW.push(this.getBoundingClientRect().width);
});
scalePadding = Math.max.apply(null, labelW) + 10;
scale.insert('rect', 'title')
.attr('x', 0)
.attr('y', function (d, i) {
return (i * 22);
})
.attr('height', 22)
.attr('stroke', 'transparent')
.attr('strokw-width', 1)
.attr('width', scalePadding);
// times
var events = d3.select('.timeline__canvas')
.insert('g', '.timeline__scale')
.attr('class', 'timeline__parts')
.attr('x', 0)
.attr('y', 0)
.selectAll('g')
.data(parts)
.enter();
events.append('rect').attr('class', function (d) {
return 'timeline__period--' + d.category;
})
.attr('x', function (d) {
return xscale(parseInt(d.start)) + scalePadding;
})
.attr('y', function (d) {
return d.lane * 22;
})
.attr('height', 22)
.attr('width', function (d) {
return xscale(Math.max(parseInt(d.end - d.start), 1));
});
events.append('rect')
.attr('class', function (d) {
return 'timeline__period-trigger';
})
.attr('x', function (d) {
return xscale(parseInt(d.start)) + scalePadding - 5;
})
.attr('y', function (d) {
return d.lane * 22;
})
.attr('height', 22)
.attr('width', function (d) {
return xscale(Math.max(parseInt(d.end - d.start), 1)) + 11;
})
.on('mouseover', function (d, i) {
tooltipCtrl(d, i);
})
.on('mouseout', function (d) {
tooltip
.style('display', 'none');
});
// Draw X-axis grid lines
d3.select('.timeline__parts').insert('g', '.timeline__parts')
.selectAll('line')
.data(xscale.ticks(10))
.enter()
.append('line')
.attr('class', 'timeline__scale--x')
.attr('x1', xscale)
.attr('x2', xscale)
.attr('y1', 0)
.attr('y2', data.length * 22)
.attr('transform', 'translate( ' + scalePadding + ' , 0)');
var xAxis = d3.svg.axis().scale(xscale).ticks(10).orient('bottom').tickFormat(function (d) {
return d + ' ms';
});
d3.select('.timeline__parts').insert('g', '.timeline__parts')
.attr('class', 'axis')
.attr('transform', 'translate(' + scalePadding + ', ' + dataL * 22 + ')')
.call(xAxis);
endScale = xscale(endTime) - rowW - parseInt(scalePadding);
if (parseInt(xscale(endTime)) > (rowW - parseInt(scalePadding))) {
d3.select('.timeline__canvas')
.call(
d3.behavior.zoom()
.scaleExtent([1, 1])
.x(xscale)
.on('zoom', function () {
var t = d3.event.translate;
var tx = t[0];
tx = tx > 0 ? 0 : tx;
tx = tx < endScale ? endScale : tx;
d3.select('.timeline__parts').attr('transform', 'translate( ' + tx + ' , 0)');
}));
}
}
}
};
})(jQuery, Drupal, drupalSettings, d3);