Upload index.html with huggingface_hub
Browse files- index.html +242 -49
index.html
CHANGED
|
@@ -50,36 +50,29 @@
|
|
| 50 |
.btn-danger { color: #e63946; border-color: #e6394640; }
|
| 51 |
.btn-danger:hover { background: #e6394610; }
|
| 52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
/* ββ Panel βββββββββββββββββββββββββββββββββββββ */
|
| 54 |
.panel {
|
| 55 |
background: #fff;
|
| 56 |
border: 1px solid #dee2e6;
|
| 57 |
border-radius: 8px;
|
| 58 |
-
margin-bottom: 20px;
|
| 59 |
overflow: hidden;
|
| 60 |
}
|
| 61 |
-
.panel-
|
| 62 |
display: flex;
|
| 63 |
align-items: center;
|
| 64 |
-
|
| 65 |
-
|
|
|
|
| 66 |
border-bottom: 1px solid #dee2e6;
|
| 67 |
background: #f8f9fa;
|
| 68 |
}
|
| 69 |
-
.panel-title {
|
| 70 |
-
flex: 1;
|
| 71 |
-
font-size: 0.875rem;
|
| 72 |
-
font-weight: 600;
|
| 73 |
-
color: #1a1a2e;
|
| 74 |
-
white-space: nowrap;
|
| 75 |
-
overflow: hidden;
|
| 76 |
-
text-overflow: ellipsis;
|
| 77 |
-
}
|
| 78 |
-
.panel-info {
|
| 79 |
-
font-size: 0.7rem;
|
| 80 |
-
color: #6c757d;
|
| 81 |
-
font-weight: 400;
|
| 82 |
-
}
|
| 83 |
.panel-controls {
|
| 84 |
padding: 16px;
|
| 85 |
border-bottom: 1px solid #dee2e6;
|
|
@@ -162,8 +155,58 @@
|
|
| 162 |
}
|
| 163 |
|
| 164 |
/* ββ Chart βββββββββββββββββββββββββββββββββββββ */
|
|
|
|
|
|
|
|
|
|
| 165 |
.panel-chart {
|
| 166 |
min-height: 100px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
}
|
| 168 |
.loading {
|
| 169 |
display: flex;
|
|
@@ -178,16 +221,23 @@
|
|
| 178 |
.custom-tooltip {
|
| 179 |
position: fixed;
|
| 180 |
pointer-events: none;
|
| 181 |
-
background: rgba(0, 0, 0, 0.
|
| 182 |
color: #fff;
|
| 183 |
-
padding:
|
| 184 |
border-radius: 4px;
|
| 185 |
-
font-size:
|
| 186 |
-
line-height: 1.
|
| 187 |
z-index: 9999;
|
| 188 |
display: none;
|
| 189 |
white-space: nowrap;
|
| 190 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
/* ββ Add panel button ββββββββββββββββββββββββββ */
|
| 193 |
.add-panel-row {
|
|
@@ -381,9 +431,7 @@
|
|
| 381 |
panel.id = `panel-${this.id}`;
|
| 382 |
|
| 383 |
panel.innerHTML = `
|
| 384 |
-
<div class="panel-
|
| 385 |
-
<span class="panel-title" id="ptitle-${this.id}">New Panel</span>
|
| 386 |
-
<span class="panel-info" id="pinfo-${this.id}"></span>
|
| 387 |
<button class="btn btn-sm" id="ptoggle-${this.id}">Collapse</button>
|
| 388 |
<button class="btn btn-sm" id="pexport-png-${this.id}">PNG</button>
|
| 389 |
<button class="btn btn-sm" id="pexport-svg-${this.id}">SVG</button>
|
|
@@ -437,15 +485,17 @@
|
|
| 437 |
<div class="checkbox-grid" id="pmodels-${this.id}"></div>
|
| 438 |
</div>
|
| 439 |
</div>
|
| 440 |
-
<div class="panel-chart"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
`;
|
| 442 |
|
| 443 |
container.appendChild(panel);
|
| 444 |
|
| 445 |
// Cache refs
|
| 446 |
this.el.panel = panel;
|
| 447 |
-
this.el.title = panel.querySelector(`#ptitle-${this.id}`);
|
| 448 |
-
this.el.info = panel.querySelector(`#pinfo-${this.id}`);
|
| 449 |
this.el.controls = panel.querySelector(`#pcontrols-${this.id}`);
|
| 450 |
this.el.suite = panel.querySelector(`#psuite-${this.id}`);
|
| 451 |
this.el.group = panel.querySelector(`#pgroup-${this.id}`);
|
|
@@ -455,6 +505,9 @@
|
|
| 455 |
this.el.chartType = panel.querySelector(`#pchart-type-${this.id}`);
|
| 456 |
this.el.models = panel.querySelector(`#pmodels-${this.id}`);
|
| 457 |
this.el.chart = panel.querySelector(`#pchart-${this.id}`);
|
|
|
|
|
|
|
|
|
|
| 458 |
|
| 459 |
// Events
|
| 460 |
panel.querySelector(`#ptoggle-${this.id}`).addEventListener('click', () => this.toggleControls());
|
|
@@ -474,6 +527,9 @@
|
|
| 474 |
panel.querySelector(`#pmodels-ckpt-${this.id}`).addEventListener('click', () => this.setModelsByType(true));
|
| 475 |
panel.querySelector(`#pmodels-base-${this.id}`).addEventListener('click', () => this.setModelsByType(false));
|
| 476 |
|
|
|
|
|
|
|
|
|
|
| 477 |
this.buildModelCheckboxes();
|
| 478 |
}
|
| 479 |
|
|
@@ -632,7 +688,6 @@
|
|
| 632 |
|
| 633 |
if (!task || !metric || models.length === 0) {
|
| 634 |
this.el.chart.innerHTML = '';
|
| 635 |
-
this.updateTitle(task, metric);
|
| 636 |
return;
|
| 637 |
}
|
| 638 |
|
|
@@ -649,7 +704,6 @@
|
|
| 649 |
|
| 650 |
if (rows.length === 0) {
|
| 651 |
this.el.chart.innerHTML = '<div class="loading">No data for this selection</div>';
|
| 652 |
-
this.updateTitle(task, metric);
|
| 653 |
return;
|
| 654 |
}
|
| 655 |
|
|
@@ -657,13 +711,27 @@
|
|
| 657 |
const chartType = this.resolveChartType(rows);
|
| 658 |
const higherIsBetter = rows[0]?.higher_is_better;
|
| 659 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 660 |
if (chartType === 'bar') {
|
| 661 |
-
this.drawBarChart(rows, task, metric, higherIsBetter);
|
| 662 |
} else {
|
| 663 |
-
this.drawLineChart(rows, task, metric, higherIsBetter);
|
| 664 |
}
|
| 665 |
-
|
| 666 |
-
this.updateTitle(task, metric, higherIsBetter);
|
| 667 |
}
|
| 668 |
|
| 669 |
resolveChartType(rows) {
|
|
@@ -685,11 +753,112 @@
|
|
| 685 |
return `${task} \u2014 ${metric}${arrow}`;
|
| 686 |
}
|
| 687 |
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
const
|
| 691 |
-
|
| 692 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
}
|
| 694 |
|
| 695 |
cleanupTooltip() {
|
|
@@ -706,9 +875,24 @@
|
|
| 706 |
chart.removeEventListener('mouseleave', this._tooltipMouseLeave);
|
| 707 |
this._tooltipMouseLeave = null;
|
| 708 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 709 |
}
|
| 710 |
|
| 711 |
-
drawLineChart(rows, task, metric, higherIsBetter) {
|
| 712 |
this.cleanupTooltip();
|
| 713 |
const w = this.getSmoothing();
|
| 714 |
|
|
@@ -774,11 +958,13 @@
|
|
| 774 |
margin: { t: 80, r: 20, b: 70, l: 50 },
|
| 775 |
plot_bgcolor: '#fff', paper_bgcolor: '#fff',
|
| 776 |
font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
| 777 |
-
height:
|
| 778 |
}, { responsive: true });
|
|
|
|
|
|
|
| 779 |
}
|
| 780 |
|
| 781 |
-
drawBarChart(rows, task, metric, higherIsBetter) {
|
| 782 |
this.cleanupTooltip();
|
| 783 |
// For bar chart, use latest checkpoint per model
|
| 784 |
const byModel = {};
|
|
@@ -840,7 +1026,7 @@
|
|
| 840 |
margin: { t: 60, r: 80, b: 60, l: 10 },
|
| 841 |
plot_bgcolor: '#fff', paper_bgcolor: '#fff',
|
| 842 |
font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
| 843 |
-
height: Math.max(
|
| 844 |
showlegend: false,
|
| 845 |
}, { responsive: true });
|
| 846 |
|
|
@@ -848,24 +1034,30 @@
|
|
| 848 |
const tooltip = document.getElementById('custom-tooltip');
|
| 849 |
const chart = this.el.chart;
|
| 850 |
chart.on('plotly_hover', (data) => {
|
|
|
|
| 851 |
const pt = data.points[0];
|
| 852 |
tooltip.innerHTML = pt.customdata;
|
| 853 |
tooltip.style.display = 'block';
|
| 854 |
});
|
| 855 |
chart.on('plotly_unhover', () => {
|
|
|
|
| 856 |
tooltip.style.display = 'none';
|
| 857 |
});
|
| 858 |
this._tooltipMouseMove = (e) => {
|
|
|
|
| 859 |
if (tooltip.style.display === 'block') {
|
| 860 |
tooltip.style.left = (e.clientX + 12) + 'px';
|
| 861 |
tooltip.style.top = (e.clientY - 10) + 'px';
|
| 862 |
}
|
| 863 |
};
|
| 864 |
this._tooltipMouseLeave = () => {
|
|
|
|
| 865 |
tooltip.style.display = 'none';
|
| 866 |
};
|
| 867 |
chart.addEventListener('mousemove', this._tooltipMouseMove);
|
| 868 |
chart.addEventListener('mouseleave', this._tooltipMouseLeave);
|
|
|
|
|
|
|
| 869 |
}
|
| 870 |
|
| 871 |
export(format) {
|
|
@@ -906,12 +1098,13 @@
|
|
| 906 |
elInitLoading.style.display = 'none';
|
| 907 |
elAddPanelRow.style.display = '';
|
| 908 |
|
| 909 |
-
// Create default
|
| 910 |
-
await
|
| 911 |
-
suite: '
|
| 912 |
-
metric: 'bits_per_byte',
|
| 913 |
-
chartType: 'bar',
|
| 914 |
-
|
|
|
|
| 915 |
} catch (err) {
|
| 916 |
elInitLoading.innerHTML = `<span style="color:#e63946">
|
| 917 |
Error: ${err.message}<br>
|
|
|
|
| 50 |
.btn-danger { color: #e63946; border-color: #e6394640; }
|
| 51 |
.btn-danger:hover { background: #e6394610; }
|
| 52 |
|
| 53 |
+
/* ββ Panels grid ββββββββββββββββββββββββββββββ */
|
| 54 |
+
#panels-container {
|
| 55 |
+
display: grid;
|
| 56 |
+
grid-template-columns: repeat(2, 1fr);
|
| 57 |
+
gap: 20px;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
/* ββ Panel βββββββββββββββββββββββββββββββββββββ */
|
| 61 |
.panel {
|
| 62 |
background: #fff;
|
| 63 |
border: 1px solid #dee2e6;
|
| 64 |
border-radius: 8px;
|
|
|
|
| 65 |
overflow: hidden;
|
| 66 |
}
|
| 67 |
+
.panel-toolbar {
|
| 68 |
display: flex;
|
| 69 |
align-items: center;
|
| 70 |
+
justify-content: flex-end;
|
| 71 |
+
gap: 6px;
|
| 72 |
+
padding: 6px 10px;
|
| 73 |
border-bottom: 1px solid #dee2e6;
|
| 74 |
background: #f8f9fa;
|
| 75 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
.panel-controls {
|
| 77 |
padding: 16px;
|
| 78 |
border-bottom: 1px solid #dee2e6;
|
|
|
|
| 155 |
}
|
| 156 |
|
| 157 |
/* ββ Chart βββββββββββββββββββββββββββββββββββββ */
|
| 158 |
+
.panel-chart-wrapper {
|
| 159 |
+
position: relative;
|
| 160 |
+
}
|
| 161 |
.panel-chart {
|
| 162 |
min-height: 100px;
|
| 163 |
+
overflow: hidden;
|
| 164 |
+
}
|
| 165 |
+
.title-hover-zone {
|
| 166 |
+
position: absolute;
|
| 167 |
+
top: 0;
|
| 168 |
+
left: 50px;
|
| 169 |
+
right: 50px;
|
| 170 |
+
height: 40px;
|
| 171 |
+
cursor: pointer;
|
| 172 |
+
z-index: 10;
|
| 173 |
+
display: flex;
|
| 174 |
+
align-items: center;
|
| 175 |
+
justify-content: center;
|
| 176 |
+
}
|
| 177 |
+
.title-info-icon {
|
| 178 |
+
position: absolute;
|
| 179 |
+
top: 50%;
|
| 180 |
+
transform: translateY(-50%);
|
| 181 |
+
width: 18px;
|
| 182 |
+
height: 18px;
|
| 183 |
+
border-radius: 50%;
|
| 184 |
+
background: #e9ecef;
|
| 185 |
+
color: #495057;
|
| 186 |
+
font-size: 11px;
|
| 187 |
+
font-weight: 600;
|
| 188 |
+
display: flex;
|
| 189 |
+
align-items: center;
|
| 190 |
+
justify-content: center;
|
| 191 |
+
opacity: 0.6;
|
| 192 |
+
transition: opacity 0.15s;
|
| 193 |
+
}
|
| 194 |
+
.title-hover-zone:hover .title-info-icon {
|
| 195 |
+
opacity: 1;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
/* ββ Resize handle ββββββββββββββββββββββββββββ */
|
| 199 |
+
.panel-resize-handle {
|
| 200 |
+
height: 6px;
|
| 201 |
+
cursor: ns-resize;
|
| 202 |
+
background: linear-gradient(to bottom, #dee2e6 1px, transparent 1px, transparent 3px, #dee2e6 3px);
|
| 203 |
+
background-size: 100% 4px;
|
| 204 |
+
background-position: center;
|
| 205 |
+
transition: background-color 0.15s;
|
| 206 |
+
}
|
| 207 |
+
.panel-resize-handle:hover,
|
| 208 |
+
.panel-resize-handle.active {
|
| 209 |
+
background-color: #e9ecef;
|
| 210 |
}
|
| 211 |
.loading {
|
| 212 |
display: flex;
|
|
|
|
| 221 |
.custom-tooltip {
|
| 222 |
position: fixed;
|
| 223 |
pointer-events: none;
|
| 224 |
+
background: rgba(0, 0, 0, 0.85);
|
| 225 |
color: #fff;
|
| 226 |
+
padding: 8px 12px 12px;
|
| 227 |
border-radius: 4px;
|
| 228 |
+
font-size: 11px;
|
| 229 |
+
line-height: 1.5;
|
| 230 |
z-index: 9999;
|
| 231 |
display: none;
|
| 232 |
white-space: nowrap;
|
| 233 |
}
|
| 234 |
+
.custom-tooltip.scrollable {
|
| 235 |
+
pointer-events: auto;
|
| 236 |
+
overflow-y: auto;
|
| 237 |
+
white-space: normal;
|
| 238 |
+
min-width: 200px;
|
| 239 |
+
max-width: 400px;
|
| 240 |
+
}
|
| 241 |
|
| 242 |
/* ββ Add panel button ββββββββββββββββββββββββββ */
|
| 243 |
.add-panel-row {
|
|
|
|
| 431 |
panel.id = `panel-${this.id}`;
|
| 432 |
|
| 433 |
panel.innerHTML = `
|
| 434 |
+
<div class="panel-toolbar">
|
|
|
|
|
|
|
| 435 |
<button class="btn btn-sm" id="ptoggle-${this.id}">Collapse</button>
|
| 436 |
<button class="btn btn-sm" id="pexport-png-${this.id}">PNG</button>
|
| 437 |
<button class="btn btn-sm" id="pexport-svg-${this.id}">SVG</button>
|
|
|
|
| 485 |
<div class="checkbox-grid" id="pmodels-${this.id}"></div>
|
| 486 |
</div>
|
| 487 |
</div>
|
| 488 |
+
<div class="panel-chart-wrapper">
|
| 489 |
+
<div class="title-hover-zone" id="ptitle-hover-${this.id}" style="display:none"></div>
|
| 490 |
+
<div class="panel-chart" id="pchart-${this.id}"></div>
|
| 491 |
+
</div>
|
| 492 |
+
<div class="panel-resize-handle" id="presize-${this.id}"></div>
|
| 493 |
`;
|
| 494 |
|
| 495 |
container.appendChild(panel);
|
| 496 |
|
| 497 |
// Cache refs
|
| 498 |
this.el.panel = panel;
|
|
|
|
|
|
|
| 499 |
this.el.controls = panel.querySelector(`#pcontrols-${this.id}`);
|
| 500 |
this.el.suite = panel.querySelector(`#psuite-${this.id}`);
|
| 501 |
this.el.group = panel.querySelector(`#pgroup-${this.id}`);
|
|
|
|
| 505 |
this.el.chartType = panel.querySelector(`#pchart-type-${this.id}`);
|
| 506 |
this.el.models = panel.querySelector(`#pmodels-${this.id}`);
|
| 507 |
this.el.chart = panel.querySelector(`#pchart-${this.id}`);
|
| 508 |
+
this.el.titleHover = panel.querySelector(`#ptitle-hover-${this.id}`);
|
| 509 |
+
this.el.resize = panel.querySelector(`#presize-${this.id}`);
|
| 510 |
+
this.chartHeight = null; // null = use default
|
| 511 |
|
| 512 |
// Events
|
| 513 |
panel.querySelector(`#ptoggle-${this.id}`).addEventListener('click', () => this.toggleControls());
|
|
|
|
| 527 |
panel.querySelector(`#pmodels-ckpt-${this.id}`).addEventListener('click', () => this.setModelsByType(true));
|
| 528 |
panel.querySelector(`#pmodels-base-${this.id}`).addEventListener('click', () => this.setModelsByType(false));
|
| 529 |
|
| 530 |
+
// Resize handle drag
|
| 531 |
+
this.el.resize.addEventListener('mousedown', (e) => this.startResize(e));
|
| 532 |
+
|
| 533 |
this.buildModelCheckboxes();
|
| 534 |
}
|
| 535 |
|
|
|
|
| 688 |
|
| 689 |
if (!task || !metric || models.length === 0) {
|
| 690 |
this.el.chart.innerHTML = '';
|
|
|
|
| 691 |
return;
|
| 692 |
}
|
| 693 |
|
|
|
|
| 704 |
|
| 705 |
if (rows.length === 0) {
|
| 706 |
this.el.chart.innerHTML = '<div class="loading">No data for this selection</div>';
|
|
|
|
| 707 |
return;
|
| 708 |
}
|
| 709 |
|
|
|
|
| 711 |
const chartType = this.resolveChartType(rows);
|
| 712 |
const higherIsBetter = rows[0]?.higher_is_better;
|
| 713 |
|
| 714 |
+
// Fetch subtask tree JSON from the data
|
| 715 |
+
let subtaskTree = null;
|
| 716 |
+
try {
|
| 717 |
+
const stRows = await query(`
|
| 718 |
+
SELECT subtask_tree FROM scores
|
| 719 |
+
WHERE task = '${esc(task)}' AND metric = '${esc(metric)}'
|
| 720 |
+
AND subtask_tree IS NOT NULL
|
| 721 |
+
LIMIT 1
|
| 722 |
+
`);
|
| 723 |
+
if (stRows.length > 0 && stRows[0].subtask_tree) {
|
| 724 |
+
subtaskTree = JSON.parse(stRows[0].subtask_tree);
|
| 725 |
+
}
|
| 726 |
+
} catch (e) {
|
| 727 |
+
// ignore
|
| 728 |
+
}
|
| 729 |
+
|
| 730 |
if (chartType === 'bar') {
|
| 731 |
+
this.drawBarChart(rows, task, metric, higherIsBetter, subtaskTree);
|
| 732 |
} else {
|
| 733 |
+
this.drawLineChart(rows, task, metric, higherIsBetter, subtaskTree);
|
| 734 |
}
|
|
|
|
|
|
|
| 735 |
}
|
| 736 |
|
| 737 |
resolveChartType(rows) {
|
|
|
|
| 753 |
return `${task} \u2014 ${metric}${arrow}`;
|
| 754 |
}
|
| 755 |
|
| 756 |
+
renderSubtaskTree(map, keys, depth = 0) {
|
| 757 |
+
if (!keys || keys.length === 0) return '';
|
| 758 |
+
const indent = depth * 16;
|
| 759 |
+
return keys.map(key => {
|
| 760 |
+
const children = map[key];
|
| 761 |
+
let html = `<div style="padding-left:${indent}px">${key}</div>`;
|
| 762 |
+
if (children) {
|
| 763 |
+
html += this.renderSubtaskTree(map, children, depth + 1);
|
| 764 |
+
}
|
| 765 |
+
return html;
|
| 766 |
+
}).join('');
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
+
setupTitleTooltip(subtaskTree) {
|
| 770 |
+
const hoverZone = this.el.titleHover;
|
| 771 |
+
hoverZone.innerHTML = '';
|
| 772 |
+
if (!subtaskTree || typeof subtaskTree !== 'object' || Object.keys(subtaskTree).length === 0) {
|
| 773 |
+
hoverZone.style.display = 'none';
|
| 774 |
+
return;
|
| 775 |
+
}
|
| 776 |
+
hoverZone.style.display = '';
|
| 777 |
+
|
| 778 |
+
// Position icon right before the title text
|
| 779 |
+
const icon = document.createElement('span');
|
| 780 |
+
icon.className = 'title-info-icon';
|
| 781 |
+
icon.textContent = 'i';
|
| 782 |
+
hoverZone.appendChild(icon);
|
| 783 |
+
const titleEl = this.el.chart.querySelector('.gtitle');
|
| 784 |
+
if (titleEl) {
|
| 785 |
+
const wrapperRect = this.el.chart.closest('.panel-chart-wrapper').getBoundingClientRect();
|
| 786 |
+
const titleRect = titleEl.getBoundingClientRect();
|
| 787 |
+
icon.style.left = (titleRect.right - wrapperRect.left - 50 + 6) + 'px'; // 50 = hover zone left offset, 6 = gap
|
| 788 |
+
} else {
|
| 789 |
+
icon.style.right = '0px';
|
| 790 |
+
}
|
| 791 |
+
const tooltip = document.getElementById('custom-tooltip');
|
| 792 |
+
// Find true roots: keys that never appear as a child value
|
| 793 |
+
const allChildren = new Set(Object.values(subtaskTree).flat());
|
| 794 |
+
const rootKeys = Object.keys(subtaskTree).filter(k => !allChildren.has(k));
|
| 795 |
+
const html = this.renderSubtaskTree(subtaskTree, rootKeys);
|
| 796 |
+
|
| 797 |
+
this._titleClick = (e) => {
|
| 798 |
+
// Toggle: if already visible for this panel, hide it
|
| 799 |
+
if (tooltip.style.display === 'block' && tooltip._panelId === this.id) {
|
| 800 |
+
tooltip.style.display = 'none';
|
| 801 |
+
tooltip.classList.remove('scrollable');
|
| 802 |
+
tooltip._panelId = null;
|
| 803 |
+
return;
|
| 804 |
+
}
|
| 805 |
+
tooltip.innerHTML = html;
|
| 806 |
+
tooltip.classList.add('scrollable');
|
| 807 |
+
tooltip.style.display = 'block';
|
| 808 |
+
tooltip._panelId = this.id;
|
| 809 |
+
// Position: top-left of tooltip below bottom-left of title text
|
| 810 |
+
const titleEl = this.el.chart.querySelector('.gtitle');
|
| 811 |
+
const chartRect = this.el.chart.getBoundingClientRect();
|
| 812 |
+
const tw = tooltip.offsetWidth;
|
| 813 |
+
if (titleEl) {
|
| 814 |
+
const titleRect = titleEl.getBoundingClientRect();
|
| 815 |
+
const titleCenter = (titleRect.left + titleRect.right) / 2;
|
| 816 |
+
tooltip.style.left = (titleCenter - tw / 2) + 'px';
|
| 817 |
+
tooltip.style.top = (titleRect.bottom + 4) + 'px';
|
| 818 |
+
} else {
|
| 819 |
+
tooltip.style.left = (chartRect.left + chartRect.width / 2 - tw / 2) + 'px';
|
| 820 |
+
tooltip.style.top = (chartRect.top + 40) + 'px';
|
| 821 |
+
}
|
| 822 |
+
tooltip.style.maxHeight = chartRect.height + 'px';
|
| 823 |
+
};
|
| 824 |
+
|
| 825 |
+
this._titleOutsideClick = (e) => {
|
| 826 |
+
if (tooltip._panelId !== this.id) return;
|
| 827 |
+
if (tooltip.contains(e.target) || hoverZone.contains(e.target)) return;
|
| 828 |
+
tooltip.style.display = 'none';
|
| 829 |
+
tooltip.classList.remove('scrollable');
|
| 830 |
+
tooltip._panelId = null;
|
| 831 |
+
};
|
| 832 |
+
|
| 833 |
+
hoverZone.addEventListener('click', this._titleClick);
|
| 834 |
+
document.addEventListener('mousedown', this._titleOutsideClick);
|
| 835 |
+
}
|
| 836 |
+
|
| 837 |
+
startResize(e) {
|
| 838 |
+
e.preventDefault();
|
| 839 |
+
const startY = e.clientY;
|
| 840 |
+
const startH = this.el.chart.offsetHeight;
|
| 841 |
+
this.el.resize.classList.add('active');
|
| 842 |
+
|
| 843 |
+
const onMove = (ev) => {
|
| 844 |
+
const delta = ev.clientY - startY;
|
| 845 |
+
const newH = Math.max(200, startH + delta);
|
| 846 |
+
this.chartHeight = newH;
|
| 847 |
+
Plotly.relayout(this.el.chart, { height: newH });
|
| 848 |
+
};
|
| 849 |
+
|
| 850 |
+
const onUp = () => {
|
| 851 |
+
this.el.resize.classList.remove('active');
|
| 852 |
+
document.removeEventListener('mousemove', onMove);
|
| 853 |
+
document.removeEventListener('mouseup', onUp);
|
| 854 |
+
};
|
| 855 |
+
|
| 856 |
+
document.addEventListener('mousemove', onMove);
|
| 857 |
+
document.addEventListener('mouseup', onUp);
|
| 858 |
+
}
|
| 859 |
+
|
| 860 |
+
getChartHeight(fallback) {
|
| 861 |
+
return this.chartHeight || fallback;
|
| 862 |
}
|
| 863 |
|
| 864 |
cleanupTooltip() {
|
|
|
|
| 875 |
chart.removeEventListener('mouseleave', this._tooltipMouseLeave);
|
| 876 |
this._tooltipMouseLeave = null;
|
| 877 |
}
|
| 878 |
+
// Clean up title click popup
|
| 879 |
+
if (this._titleClick) {
|
| 880 |
+
const hz = this.el.titleHover;
|
| 881 |
+
hz.removeEventListener('click', this._titleClick);
|
| 882 |
+
hz.style.display = 'none';
|
| 883 |
+
this._titleClick = null;
|
| 884 |
+
}
|
| 885 |
+
if (this._titleOutsideClick) {
|
| 886 |
+
document.removeEventListener('mousedown', this._titleOutsideClick);
|
| 887 |
+
this._titleOutsideClick = null;
|
| 888 |
+
}
|
| 889 |
+
if (tooltip._panelId === this.id) {
|
| 890 |
+
tooltip.classList.remove('scrollable');
|
| 891 |
+
tooltip._panelId = null;
|
| 892 |
+
}
|
| 893 |
}
|
| 894 |
|
| 895 |
+
drawLineChart(rows, task, metric, higherIsBetter, subtasks) {
|
| 896 |
this.cleanupTooltip();
|
| 897 |
const w = this.getSmoothing();
|
| 898 |
|
|
|
|
| 958 |
margin: { t: 80, r: 20, b: 70, l: 50 },
|
| 959 |
plot_bgcolor: '#fff', paper_bgcolor: '#fff',
|
| 960 |
font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
| 961 |
+
height: this.getChartHeight(600),
|
| 962 |
}, { responsive: true });
|
| 963 |
+
|
| 964 |
+
this.setupTitleTooltip(subtasks);
|
| 965 |
}
|
| 966 |
|
| 967 |
+
drawBarChart(rows, task, metric, higherIsBetter, subtasks) {
|
| 968 |
this.cleanupTooltip();
|
| 969 |
// For bar chart, use latest checkpoint per model
|
| 970 |
const byModel = {};
|
|
|
|
| 1026 |
margin: { t: 60, r: 80, b: 60, l: 10 },
|
| 1027 |
plot_bgcolor: '#fff', paper_bgcolor: '#fff',
|
| 1028 |
font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
|
| 1029 |
+
height: this.getChartHeight(Math.max(400, names.length * 40 + 100)),
|
| 1030 |
showlegend: false,
|
| 1031 |
}, { responsive: true });
|
| 1032 |
|
|
|
|
| 1034 |
const tooltip = document.getElementById('custom-tooltip');
|
| 1035 |
const chart = this.el.chart;
|
| 1036 |
chart.on('plotly_hover', (data) => {
|
| 1037 |
+
if (tooltip.classList.contains('scrollable')) return;
|
| 1038 |
const pt = data.points[0];
|
| 1039 |
tooltip.innerHTML = pt.customdata;
|
| 1040 |
tooltip.style.display = 'block';
|
| 1041 |
});
|
| 1042 |
chart.on('plotly_unhover', () => {
|
| 1043 |
+
if (tooltip.classList.contains('scrollable')) return;
|
| 1044 |
tooltip.style.display = 'none';
|
| 1045 |
});
|
| 1046 |
this._tooltipMouseMove = (e) => {
|
| 1047 |
+
if (tooltip.classList.contains('scrollable')) return;
|
| 1048 |
if (tooltip.style.display === 'block') {
|
| 1049 |
tooltip.style.left = (e.clientX + 12) + 'px';
|
| 1050 |
tooltip.style.top = (e.clientY - 10) + 'px';
|
| 1051 |
}
|
| 1052 |
};
|
| 1053 |
this._tooltipMouseLeave = () => {
|
| 1054 |
+
if (tooltip.classList.contains('scrollable')) return;
|
| 1055 |
tooltip.style.display = 'none';
|
| 1056 |
};
|
| 1057 |
chart.addEventListener('mousemove', this._tooltipMouseMove);
|
| 1058 |
chart.addEventListener('mouseleave', this._tooltipMouseLeave);
|
| 1059 |
+
|
| 1060 |
+
this.setupTitleTooltip(subtasks);
|
| 1061 |
}
|
| 1062 |
|
| 1063 |
export(format) {
|
|
|
|
| 1098 |
elInitLoading.style.display = 'none';
|
| 1099 |
elAddPanelRow.style.display = '';
|
| 1100 |
|
| 1101 |
+
// Create 2x2 default panels
|
| 1102 |
+
await Promise.all([
|
| 1103 |
+
addPanel({ suite: 'eng_base_easy', group: 'eng_base_easy_bpb', metric: 'bits_per_byte', chartType: 'bar' }),
|
| 1104 |
+
addPanel({ suite: 'deu_base_easy', group: 'deu_base_easy_bpb', metric: 'bits_per_byte', chartType: 'bar' }),
|
| 1105 |
+
addPanel({ suite: 'eng_base_easy', group: 'eng_base_easy_rc', metric: 'acc_norm', chartType: 'bar' }),
|
| 1106 |
+
addPanel({ suite: 'deu_base_easy', group: 'deu_base_easy_rc', metric: 'acc_norm', chartType: 'bar' }),
|
| 1107 |
+
]);
|
| 1108 |
} catch (err) {
|
| 1109 |
elInitLoading.innerHTML = `<span style="color:#e63946">
|
| 1110 |
Error: ${err.message}<br>
|