Baselines: drop persistent labels, identify on hover with thicker line + tooltip
Browse files- static/index.html +25 -45
static/index.html
CHANGED
|
@@ -1715,59 +1715,27 @@ function renderChart(entries) {
|
|
| 1715 |
// Horizontal dashed line per baseline, spanning the full visible x-range.
|
| 1716 |
// Added *after* the three core datasets so the bestLabels (idx 1) and
|
| 1717 |
// nonBestLabels (idx 2) plugins continue to find their dataset metas.
|
|
|
|
| 1718 |
const BASELINE_COLOR = 'rgba(107,114,128,0.55)';
|
|
|
|
| 1719 |
const baselineDatasets = baselineEntries.map(e => ({
|
| 1720 |
-
label:
|
| 1721 |
-
data: [{ x: xMin, y: e.score }, { x: extendedEnd, y: e.score }],
|
| 1722 |
type: 'line',
|
| 1723 |
borderColor: BASELINE_COLOR,
|
|
|
|
| 1724 |
backgroundColor: 'transparent',
|
| 1725 |
-
borderWidth: 1,
|
|
|
|
| 1726 |
borderDash: [5, 4],
|
| 1727 |
pointRadius: 0,
|
| 1728 |
pointHoverRadius: 0,
|
| 1729 |
fill: false,
|
| 1730 |
tension: 0,
|
| 1731 |
order: 100,
|
|
|
|
| 1732 |
}));
|
| 1733 |
|
| 1734 |
-
// Right-edge label per baseline. Stack vertically when y-values cluster.
|
| 1735 |
-
const baselineLabels = {
|
| 1736 |
-
id: 'baselineLabels',
|
| 1737 |
-
afterDatasetsDraw(c) {
|
| 1738 |
-
if (!baselineEntries.length) return;
|
| 1739 |
-
const ctx2 = c.ctx;
|
| 1740 |
-
const a = c.chartArea;
|
| 1741 |
-
const yScale = c.scales.y;
|
| 1742 |
-
ctx2.save();
|
| 1743 |
-
ctx2.font = '500 10px "JetBrains Mono", monospace';
|
| 1744 |
-
const placed = [];
|
| 1745 |
-
// Draw smallest-score (top of chart) first so stacking pushes downward.
|
| 1746 |
-
baselineEntries.forEach(e => {
|
| 1747 |
-
const text = `${e.method || 'baseline'} ${e.score.toLocaleString()}`;
|
| 1748 |
-
const tw = ctx2.measureText(text).width;
|
| 1749 |
-
const px = 6, boxH = 18, boxW = tw + px * 2;
|
| 1750 |
-
let yc = yScale.getPixelForValue(e.score);
|
| 1751 |
-
for (const p of placed) {
|
| 1752 |
-
if (Math.abs(yc - p) < boxH + 2) yc = p + boxH + 2;
|
| 1753 |
-
}
|
| 1754 |
-
placed.push(yc);
|
| 1755 |
-
let lx = a.right - boxW - 4;
|
| 1756 |
-
let ly = yc - boxH / 2;
|
| 1757 |
-
if (ly < a.top) ly = a.top + 1;
|
| 1758 |
-
if (ly + boxH > a.bottom) ly = a.bottom - boxH - 1;
|
| 1759 |
-
ctx2.fillStyle = 'rgba(243,244,246,0.95)';
|
| 1760 |
-
ctx2.strokeStyle = 'rgba(107,114,128,0.45)';
|
| 1761 |
-
ctx2.lineWidth = 1;
|
| 1762 |
-
ctx2.beginPath(); ctx2.roundRect(lx, ly, boxW, boxH, 5); ctx2.fill(); ctx2.stroke();
|
| 1763 |
-
ctx2.fillStyle = '#6b7280';
|
| 1764 |
-
ctx2.textBaseline = 'middle';
|
| 1765 |
-
ctx2.fillText(text, lx + px, ly + boxH / 2);
|
| 1766 |
-
});
|
| 1767 |
-
ctx2.restore();
|
| 1768 |
-
},
|
| 1769 |
-
};
|
| 1770 |
-
|
| 1771 |
const ctx = document.getElementById('evolutionChart').getContext('2d');
|
| 1772 |
chart = new Chart(ctx, {
|
| 1773 |
type: 'line',
|
|
@@ -1791,11 +1759,23 @@ function renderChart(entries) {
|
|
| 1791 |
titleFont: { family: "'Source Sans 3', sans-serif", size: 12, weight: '700' },
|
| 1792 |
bodyFont: { family: "'JetBrains Mono', monospace", size: 11 },
|
| 1793 |
titleColor: '#fff', bodyColor: '#d1d5db',
|
| 1794 |
-
//
|
| 1795 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1796 |
callbacks: {
|
| 1797 |
-
title: items =>
|
| 1798 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1799 |
},
|
| 1800 |
},
|
| 1801 |
},
|
|
@@ -1825,7 +1805,7 @@ function renderChart(entries) {
|
|
| 1825 |
},
|
| 1826 |
interaction: { mode: 'nearest', intersect: true },
|
| 1827 |
},
|
| 1828 |
-
plugins: [bestLabels, nonBestLabels
|
| 1829 |
});
|
| 1830 |
}
|
| 1831 |
|
|
|
|
| 1715 |
// Horizontal dashed line per baseline, spanning the full visible x-range.
|
| 1716 |
// Added *after* the three core datasets so the bestLabels (idx 1) and
|
| 1717 |
// nonBestLabels (idx 2) plugins continue to find their dataset metas.
|
| 1718 |
+
// Identified by name on hover (tooltip), not by always-on labels.
|
| 1719 |
const BASELINE_COLOR = 'rgba(107,114,128,0.55)';
|
| 1720 |
+
const BASELINE_HOVER_COLOR = 'rgba(55,65,81,0.95)';
|
| 1721 |
const baselineDatasets = baselineEntries.map(e => ({
|
| 1722 |
+
label: e.method || 'baseline',
|
| 1723 |
+
data: [{ x: xMin, y: e.score, agent: 'baseline', method: e.method }, { x: extendedEnd, y: e.score, agent: 'baseline', method: e.method }],
|
| 1724 |
type: 'line',
|
| 1725 |
borderColor: BASELINE_COLOR,
|
| 1726 |
+
hoverBorderColor: BASELINE_HOVER_COLOR,
|
| 1727 |
backgroundColor: 'transparent',
|
| 1728 |
+
borderWidth: 1.5,
|
| 1729 |
+
hoverBorderWidth: 3.5,
|
| 1730 |
borderDash: [5, 4],
|
| 1731 |
pointRadius: 0,
|
| 1732 |
pointHoverRadius: 0,
|
| 1733 |
fill: false,
|
| 1734 |
tension: 0,
|
| 1735 |
order: 100,
|
| 1736 |
+
_isBaseline: true,
|
| 1737 |
}));
|
| 1738 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1739 |
const ctx = document.getElementById('evolutionChart').getContext('2d');
|
| 1740 |
chart = new Chart(ctx, {
|
| 1741 |
type: 'line',
|
|
|
|
| 1759 |
titleFont: { family: "'Source Sans 3', sans-serif", size: 12, weight: '700' },
|
| 1760 |
bodyFont: { family: "'JetBrains Mono', monospace", size: 11 },
|
| 1761 |
titleColor: '#fff', bodyColor: '#d1d5db',
|
| 1762 |
+
// Run datasets (idx 0..2): only real points, skip line-extension synthetic point.
|
| 1763 |
+
// Baseline datasets (idx >= 3): always allowed (hover line → identify it).
|
| 1764 |
+
filter: it => {
|
| 1765 |
+
if (it.datasetIndex >= 3) return true;
|
| 1766 |
+
return it.raw && !it.raw._ext && it.raw.agent;
|
| 1767 |
+
},
|
| 1768 |
callbacks: {
|
| 1769 |
+
title: items => {
|
| 1770 |
+
const it = items[0];
|
| 1771 |
+
if (it.datasetIndex >= 3) return `baseline · ${it.dataset.label}`;
|
| 1772 |
+
return it.raw?.agent || '';
|
| 1773 |
+
},
|
| 1774 |
+
label: it => {
|
| 1775 |
+
if (it.datasetIndex >= 3) return [`Bytes: ${it.raw.y.toLocaleString()}`];
|
| 1776 |
+
const d = new Date(it.raw.x);
|
| 1777 |
+
return [`Bytes: ${it.raw.y.toLocaleString()}`, `Date: ${d.toLocaleString()}`];
|
| 1778 |
+
}
|
| 1779 |
},
|
| 1780 |
},
|
| 1781 |
},
|
|
|
|
| 1805 |
},
|
| 1806 |
interaction: { mode: 'nearest', intersect: true },
|
| 1807 |
},
|
| 1808 |
+
plugins: [bestLabels, nonBestLabels],
|
| 1809 |
});
|
| 1810 |
}
|
| 1811 |
|