Chart: include negatives in x-axis range, bump trailing pad to 15%, clip:false on scatters
Browse files- static/index.html +17 -12
static/index.html
CHANGED
|
@@ -1842,15 +1842,21 @@ function renderChart(entries) {
|
|
| 1842 |
const bestEntries = sorted.filter(e => e.isRecord);
|
| 1843 |
const nonBestEntries = sorted.filter(e => !e.isRecord);
|
| 1844 |
|
| 1845 |
-
// X axis
|
| 1846 |
-
//
|
|
|
|
|
|
|
| 1847 |
const now = Date.now();
|
| 1848 |
const runDates = sorted.map(e => new Date(e.date).getTime());
|
| 1849 |
-
const
|
| 1850 |
-
const
|
|
|
|
|
|
|
| 1851 |
const timeRange = latestDate - minDate || 3600000;
|
| 1852 |
const datePadding = timeRange * 0.05;
|
| 1853 |
-
|
|
|
|
|
|
|
| 1854 |
const xMin = minDate - datePadding;
|
| 1855 |
|
| 1856 |
const bestLineData = bestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
|
@@ -1860,10 +1866,9 @@ function renderChart(entries) {
|
|
| 1860 |
}
|
| 1861 |
const bestScatter = bestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
| 1862 |
const nonBestData = nonBestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
| 1863 |
-
// Negatives
|
| 1864 |
-
//
|
| 1865 |
-
//
|
| 1866 |
-
// tooltip so the hover-info still shows the real timestamp.
|
| 1867 |
const negativeData = negativeEntries.map(e => {
|
| 1868 |
const t = new Date(e.date).getTime();
|
| 1869 |
const clamped = Math.max(xMin, Math.min(extendedEnd, t));
|
|
@@ -1939,11 +1944,11 @@ function renderChart(entries) {
|
|
| 1939 |
data: {
|
| 1940 |
datasets: [
|
| 1941 |
{ label: 'Running Best', data: bestLineData, borderColor: HF_ORANGE, backgroundColor: HF_ORANGE_DIM, borderWidth: 2.5, stepped: 'after', fill: true, pointRadius: 0, pointHoverRadius: 0, tension: 0, order: 2 },
|
| 1942 |
-
{ label: 'Records', data: bestScatter, type: 'scatter', backgroundColor: HF_ORANGE, borderColor: '#fff', borderWidth: 2, pointRadius: 7, pointHoverRadius: 9, pointStyle: 'circle', order: 1 },
|
| 1943 |
-
{ label: 'Non-Records', data: nonBestData, type: 'scatter', backgroundColor: NON_BEST_COLOR, borderColor: '#fff', borderWidth: 1.5, pointRadius: 5, pointHoverRadius: 7, pointStyle: 'circle', order: 0 },
|
| 1944 |
// Negatives: same styling as Non-Records, also unlabeled. Tooltip
|
| 1945 |
// on hover identifies any non-record dot.
|
| 1946 |
-
{ label: 'Negatives', data: negativeData, type: 'scatter', backgroundColor: NON_BEST_COLOR, borderColor: '#fff', borderWidth: 1.5, pointRadius: 5, pointHoverRadius: 7, pointStyle: 'circle', order: 0 },
|
| 1947 |
...baselineDatasets,
|
| 1948 |
],
|
| 1949 |
},
|
|
|
|
| 1842 |
const bestEntries = sorted.filter(e => e.isRecord);
|
| 1843 |
const nonBestEntries = sorted.filter(e => !e.isRecord);
|
| 1844 |
|
| 1845 |
+
// X axis covers BOTH agent-runs and negatives so no dot sits exactly on
|
| 1846 |
+
// the right edge (which Chart.js would clip). Fallback to a window around
|
| 1847 |
+
// "now" when no agent-runs exist yet, so baselines still have a sensible
|
| 1848 |
+
// x-range to span.
|
| 1849 |
const now = Date.now();
|
| 1850 |
const runDates = sorted.map(e => new Date(e.date).getTime());
|
| 1851 |
+
const negDates = negativeEntries.map(e => new Date(e.date).getTime());
|
| 1852 |
+
const allDotDates = [...runDates, ...negDates];
|
| 1853 |
+
const minDate = allDotDates.length ? Math.min(...allDotDates) : now - 30 * 60 * 1000;
|
| 1854 |
+
const latestDate = allDotDates.length ? Math.max(...allDotDates) : now;
|
| 1855 |
const timeRange = latestDate - minDate || 3600000;
|
| 1856 |
const datePadding = timeRange * 0.05;
|
| 1857 |
+
// 15% trailing breathing room past the latest dot so labels and the
|
| 1858 |
+
// running-best line extension have somewhere to live.
|
| 1859 |
+
const extendedEnd = latestDate + timeRange * 0.15;
|
| 1860 |
const xMin = minDate - datePadding;
|
| 1861 |
|
| 1862 |
const bestLineData = bestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
|
|
|
| 1866 |
}
|
| 1867 |
const bestScatter = bestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
| 1868 |
const nonBestData = nonBestEntries.map(e => ({ x: new Date(e.date).getTime(), y: e.score, agent: e.agent }));
|
| 1869 |
+
// Negatives now use their real timestamps directly — the x-axis is wide
|
| 1870 |
+
// enough to include them. Defensive clamp keeps any pathological out-of-
|
| 1871 |
+
// range value visible. _origDate is preserved for the tooltip.
|
|
|
|
| 1872 |
const negativeData = negativeEntries.map(e => {
|
| 1873 |
const t = new Date(e.date).getTime();
|
| 1874 |
const clamped = Math.max(xMin, Math.min(extendedEnd, t));
|
|
|
|
| 1944 |
data: {
|
| 1945 |
datasets: [
|
| 1946 |
{ label: 'Running Best', data: bestLineData, borderColor: HF_ORANGE, backgroundColor: HF_ORANGE_DIM, borderWidth: 2.5, stepped: 'after', fill: true, pointRadius: 0, pointHoverRadius: 0, tension: 0, order: 2 },
|
| 1947 |
+
{ label: 'Records', data: bestScatter, type: 'scatter', backgroundColor: HF_ORANGE, borderColor: '#fff', borderWidth: 2, pointRadius: 7, pointHoverRadius: 9, pointStyle: 'circle', order: 1, clip: false },
|
| 1948 |
+
{ label: 'Non-Records', data: nonBestData, type: 'scatter', backgroundColor: NON_BEST_COLOR, borderColor: '#fff', borderWidth: 1.5, pointRadius: 5, pointHoverRadius: 7, pointStyle: 'circle', order: 0, clip: false },
|
| 1949 |
// Negatives: same styling as Non-Records, also unlabeled. Tooltip
|
| 1950 |
// on hover identifies any non-record dot.
|
| 1951 |
+
{ label: 'Negatives', data: negativeData, type: 'scatter', backgroundColor: NON_BEST_COLOR, borderColor: '#fff', borderWidth: 1.5, pointRadius: 5, pointHoverRadius: 7, pointStyle: 'circle', order: 0, clip: false },
|
| 1952 |
...baselineDatasets,
|
| 1953 |
],
|
| 1954 |
},
|