Skip to content

Commit 90fefb2

Browse files
committed
tweak
1 parent 496d6ae commit 90fefb2

4 files changed

Lines changed: 120 additions & 6 deletions

File tree

codespeed/static/css/main.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ div.miniplot {
468468
float: left;
469469
height: 130px;
470470
width: 23%;
471+
border: 1px solid #9DADC6;
471472
-moz-border-radius: 10px;
472473
-webkit-border-radius: 10px;
473474
border-radius: 10px;
@@ -476,6 +477,19 @@ div.miniplot:hover { background-color: #F1F1F1; }
476477
.jqplot-highlighter-tooltip {
477478
-moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px;
478479
}
480+
#dygraph-tooltip {
481+
display: none;
482+
position: absolute;
483+
background: rgba(255,255,255,0.92);
484+
border: 1px solid #9DADC6;
485+
border-radius: 6px;
486+
padding: 6px 10px;
487+
font-size: 12px;
488+
pointer-events: none;
489+
z-index: 100;
490+
white-space: nowrap;
491+
box-shadow: 2px 2px 4px rgba(0,0,0,0.15);
492+
}
479493

480494
div.compplot {
481495
text-align: left;

codespeed/static/js/timeline.js

Lines changed: 103 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function updateUrl() {
6060

6161
function destroyPlots() {
6262
if (plotInstance) { plotInstance.destroy(); plotInstance = null; }
63+
$("#plot").off("mousemove.tooltip");
6364
miniplotInstances.forEach(function(g) { g.destroy(); });
6465
miniplotInstances = [];
6566
}
@@ -107,7 +108,8 @@ function buildGraphData(branches, median, equidistant) {
107108

108109
dateIndex[dateKey] = new Date(dateKey.trim());
109110
seriesRaw[exe_id][dateKey] = {low: low, mid: mid, high: high,
110-
commit: commit, tag: tag};
111+
commit: commit, tag: tag,
112+
dateKey: dateKey};
111113
}
112114
}
113115
}
@@ -126,12 +128,15 @@ function buildGraphData(branches, median, equidistant) {
126128

127129
// commitMap[dateKey][exe_id] = {commit, tag}
128130
var commitMap = {};
131+
var tsMap = {}; // timestamp (ms) -> dateKey, for legend lookup
129132
sortedDateKeys.forEach(function(dk) {
133+
tsMap[dateIndex[dk].getTime()] = dk;
130134
commitMap[dk] = {};
131135
seriesIds.forEach(function(id) {
132136
if (seriesRaw[id][dk]) {
133-
commitMap[dk][id] = {commit: seriesRaw[id][dk].commit,
134-
tag: seriesRaw[id][dk].tag};
137+
var pt = seriesRaw[id][dk];
138+
commitMap[dk][id] = {commit: pt.commit, tag: pt.tag,
139+
low: pt.low, high: pt.high};
135140
}
136141
});
137142
});
@@ -148,7 +153,7 @@ function buildGraphData(branches, median, equidistant) {
148153

149154
return {labels: labels, colors: colors, data: graphData,
150155
commitMap: commitMap, sortedDateKeys: sortedDateKeys,
151-
seriesIds: seriesIds};
156+
seriesIds: seriesIds, tsMap: tsMap};
152157
}
153158

154159
function renderPlot(data) {
@@ -186,8 +191,58 @@ function renderPlot(data) {
186191
var commitMap = built.commitMap;
187192
var sortedDateKeys = built.sortedDateKeys;
188193
var seriesIds = built.seriesIds;
194+
var tsMap = built.tsMap;
189195
var env = $("input[name='environments']:checked").val();
190196

197+
// Map label -> color and label -> exeId for tooltip
198+
var colorMap = {};
199+
var labelToExeId = {};
200+
built.labels.slice(1).forEach(function(lbl, i) {
201+
colorMap[lbl] = built.colors[i];
202+
labelToExeId[lbl] = seriesIds[i];
203+
});
204+
205+
function lookupDateKey(x) {
206+
if (equidistant) { return sortedDateKeys[Math.round(x)]; }
207+
var dk = tsMap[x];
208+
if (!dk) {
209+
// find closest
210+
dk = sortedDateKeys.reduce(function(best, curr) {
211+
return Math.abs(new Date(curr.trim()) - x) <
212+
Math.abs(new Date(best.trim()) - x) ? curr : best;
213+
}, sortedDateKeys[0]);
214+
}
215+
return dk;
216+
}
217+
218+
function legendFormatter(ld) {
219+
if (ld.x === undefined) { return ''; }
220+
var dk = lookupDateKey(ld.x);
221+
var html = '<div style="font-weight:bold;margin-bottom:3px">' +
222+
(dk ? dk.slice(0, 16) : '') + '</div>';
223+
ld.series.forEach(function(s) {
224+
if (!s.isVisible || s.y === undefined) { return; }
225+
var exeId = labelToExeId[s.labelHTML] || labelToExeId[s.name];
226+
var color = colorMap[s.labelHTML] || colorMap[s.name] || '#333';
227+
html += '<div style="margin:2px 0;color:' + color + '">' +
228+
'<b>' + s.labelHTML + ': ' + s.y.toPrecision(4) + '</b>';
229+
if (dk && commitMap[dk] && commitMap[dk][exeId]) {
230+
var info = commitMap[dk][exeId];
231+
if (info.low !== info.high) {
232+
html += ' <span style="font-weight:normal">[' +
233+
info.low.toPrecision(3) + ' \u2013 ' +
234+
info.high.toPrecision(3) + ']</span>';
235+
}
236+
html += '<br><span style="font-size:0.85em;font-weight:normal;color:#666">' +
237+
'commit: ' + info.commit;
238+
if (info.tag) { html += '&nbsp;&nbsp;tag: ' + info.tag; }
239+
html += '</span>';
240+
}
241+
html += '</div>';
242+
});
243+
return html;
244+
}
245+
191246
// Per-series options: baseline gets thinner line, no points
192247
var seriesOpts = {};
193248
built.labels.slice(1).forEach(function(lbl, i) {
@@ -211,6 +266,8 @@ function renderPlot(data) {
211266
}
212267
} : {};
213268

269+
var lastHighlightPoints = null, lastHighlightX = null;
270+
214271
plotInstance = new Dygraph(
215272
document.getElementById('plot'),
216273
built.data,
@@ -221,14 +278,23 @@ function renderPlot(data) {
221278
colors: built.colors,
222279
customBars: true,
223280
series: seriesOpts,
224-
legend: 'always',
281+
legend: 'never',
225282
ylabel: data.units + data.lessisbetter,
226283
axes: {
227284
x: xAxisOpts,
228285
y: { valueRange: [0, null] }
229286
},
230287
connectSeparatedPoints: true,
231288
highlightSeriesOpts: { strokeWidth: 3 },
289+
highlightCircleSize: 5,
290+
highlightCallback: function(e, x, points) {
291+
lastHighlightX = x;
292+
lastHighlightPoints = points;
293+
},
294+
unhighlightCallback: function() {
295+
lastHighlightPoints = null;
296+
$("#dygraph-tooltip").hide();
297+
},
232298
// Navigate to changes page on point click
233299
clickCallback: function(e, x, points) {
234300
var dk;
@@ -250,6 +316,38 @@ function renderPlot(data) {
250316
}
251317
}
252318
);
319+
320+
$("#plot").on("mousemove.tooltip", function(e) {
321+
var $tip = $("#dygraph-tooltip");
322+
if (!lastHighlightPoints) { $tip.hide(); return; }
323+
var THRESHOLD = 0.015;
324+
var area = plotInstance.getArea();
325+
var mx = e.offsetX !== undefined ? e.offsetX : e.layerX;
326+
var my = e.offsetY !== undefined ? e.offsetY : e.layerY;
327+
var close = lastHighlightPoints.some(function(pt) {
328+
if (pt.canvasx === undefined) { return false; }
329+
var dx = (mx - pt.canvasx) / area.w;
330+
var dy = (my - pt.canvasy) / area.w;
331+
return Math.sqrt(dx*dx + dy*dy) < THRESHOLD;
332+
});
333+
if (close) {
334+
var chartOffset = $("#plot").offset();
335+
var absX = chartOffset.left + mx;
336+
var onRight = absX > $(window).width() / 2;
337+
$tip.html(legendFormatter({x: lastHighlightX, series: lastHighlightPoints.map(function(pt) {
338+
return {color: colorMap[pt.name] || '#333',
339+
labelHTML: pt.name, name: pt.name,
340+
y: pt.yval, isVisible: true};
341+
})}));
342+
var tipW = $tip.outerWidth();
343+
$tip.css({
344+
left: onRight ? (absX - tipW - 18) + 'px' : (absX + 18) + 'px',
345+
top: (chartOffset.top + my - 10) + 'px'
346+
}).show();
347+
} else {
348+
$tip.hide();
349+
}
350+
});
253351
}
254352

255353
function renderMiniplot(plotid, data) {

codespeed/templates/codespeed/timeline.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
<div id="plotgrid"></div>
104104
<div id="plotdescription"></div>
105105
</div>
106+
<div id="dygraph-tooltip"></div>
106107
{% endblock %}
107108

108109
{% block extra_script %}
@@ -120,7 +121,7 @@
120121
executables: [{% for exe in checkedexecutables %}{{ exe.id }}, {% endfor %}],
121122
branches: [{% for b in branch_list %}"{{ branch }}", {% endfor %}],
122123
benchmark: "{{ defaultbenchmark }}",
123-
environment: "{{ defaultenvironment.id }}",
124+
environment: "{{ defaultenvironment.0.id }}",
124125
equidistant: "{{ defaultequid }}",
125126
quartiles: "{{ defaultquarts }}",
126127
extrema: "{{ defaultextr }}"

speed_pypy/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
]
101101
DEF_ENVIRONMENT = 'benchmarker'
102102
CHART_ORIENTATION = 'horizontal'
103+
DEF_BENCHMARK = 'grid'
103104

104105

105106
from .local_settings import *

0 commit comments

Comments
 (0)