Spaces:
Running
Running
Fix resize, watermark visibility, and live speed slider
Browse files- index.html +45 -15
index.html
CHANGED
|
@@ -118,6 +118,7 @@
|
|
| 118 |
svg {
|
| 119 |
width: 100%;
|
| 120 |
height: auto;
|
|
|
|
| 121 |
display: block;
|
| 122 |
}
|
| 123 |
|
|
@@ -149,7 +150,7 @@
|
|
| 149 |
}
|
| 150 |
|
| 151 |
.date-watermark {
|
| 152 |
-
fill: rgba(0, 0, 0, 0.
|
| 153 |
font-size: 64px;
|
| 154 |
font-weight: 700;
|
| 155 |
pointer-events: none;
|
|
@@ -203,10 +204,17 @@
|
|
| 203 |
const margin = { top: 30, right: 90, bottom: 10, left: 6 };
|
| 204 |
const width = 1050;
|
| 205 |
|
| 206 |
-
//
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
|
| 211 |
// ---- Populate dropdown ----
|
| 212 |
const select = d3.select("#benchmark-select");
|
|
@@ -238,27 +246,29 @@
|
|
| 238 |
return y(rank) ?? margin.top + barHeight * topN;
|
| 239 |
}
|
| 240 |
|
| 241 |
-
// Groups (layered bottom to top)
|
| 242 |
-
const watermarkG = svg.append("g");
|
| 243 |
const axisG = svg.append("g").attr("class", "axis");
|
| 244 |
const barG = svg.append("g");
|
| 245 |
const logoG = svg.append("g");
|
| 246 |
const nameG = svg.append("g");
|
| 247 |
const scoreG = svg.append("g");
|
|
|
|
| 248 |
|
| 249 |
-
//
|
| 250 |
-
const nameFontSize = Math.max(9, Math.min(13, barHeight * 0.36));
|
| 251 |
-
const scoreFontSize = Math.max(8, Math.min(12, barHeight * 0.33));
|
| 252 |
-
const watermarkSize = Math.max(36, Math.min(64, height * 0.11));
|
| 253 |
-
|
| 254 |
-
// Date watermark
|
| 255 |
const ticker = watermarkG.append("text")
|
| 256 |
.attr("class", "date-watermark")
|
| 257 |
-
.style("font-size", watermarkSize + "px")
|
| 258 |
.attr("x", width - margin.right - 10)
|
| 259 |
-
.attr("y", height - 20)
|
| 260 |
.attr("text-anchor", "end");
|
| 261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
// ---- Build keyframes for a benchmark ----
|
| 263 |
function buildKeyframes(benchmarkKey) {
|
| 264 |
const bm = raw.benchmarks[benchmarkKey];
|
|
@@ -582,6 +592,26 @@
|
|
| 582 |
d3.select("#speed-slider").on("input", function () {
|
| 583 |
frameDuration = +this.value;
|
| 584 |
d3.select("#speed-label").text(this.value + "ms");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
});
|
| 586 |
|
| 587 |
// ---- Initialize: load default benchmark and auto-play ----
|
|
|
|
| 118 |
svg {
|
| 119 |
width: 100%;
|
| 120 |
height: auto;
|
| 121 |
+
max-height: calc(100vh - 180px);
|
| 122 |
display: block;
|
| 123 |
}
|
| 124 |
|
|
|
|
| 150 |
}
|
| 151 |
|
| 152 |
.date-watermark {
|
| 153 |
+
fill: rgba(0, 0, 0, 0.18);
|
| 154 |
font-size: 64px;
|
| 155 |
font-weight: 700;
|
| 156 |
pointer-events: none;
|
|
|
|
| 204 |
const margin = { top: 30, right: 90, bottom: 10, left: 6 };
|
| 205 |
const width = 1050;
|
| 206 |
|
| 207 |
+
// Dynamic dimensions — recomputed on resize so all bars stay in view
|
| 208 |
+
let barHeight, height, nameFontSize, scoreFontSize, watermarkSize;
|
| 209 |
+
function computeDimensions() {
|
| 210 |
+
const availableHeight = Math.max(400, window.innerHeight - 160);
|
| 211 |
+
barHeight = Math.min(38, Math.floor((availableHeight - margin.top - margin.bottom) / topN));
|
| 212 |
+
height = margin.top + barHeight * topN + margin.bottom;
|
| 213 |
+
nameFontSize = Math.max(9, Math.min(13, barHeight * 0.36));
|
| 214 |
+
scoreFontSize = Math.max(8, Math.min(12, barHeight * 0.33));
|
| 215 |
+
watermarkSize = Math.max(36, Math.min(64, height * 0.11));
|
| 216 |
+
}
|
| 217 |
+
computeDimensions();
|
| 218 |
|
| 219 |
// ---- Populate dropdown ----
|
| 220 |
const select = d3.select("#benchmark-select");
|
|
|
|
| 246 |
return y(rank) ?? margin.top + barHeight * topN;
|
| 247 |
}
|
| 248 |
|
| 249 |
+
// Groups (layered bottom to top) — watermark on top so it overlays bars
|
|
|
|
| 250 |
const axisG = svg.append("g").attr("class", "axis");
|
| 251 |
const barG = svg.append("g");
|
| 252 |
const logoG = svg.append("g");
|
| 253 |
const nameG = svg.append("g");
|
| 254 |
const scoreG = svg.append("g");
|
| 255 |
+
const watermarkG = svg.append("g");
|
| 256 |
|
| 257 |
+
// Date watermark — position/size refreshed on resize via applyDimensions()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
const ticker = watermarkG.append("text")
|
| 259 |
.attr("class", "date-watermark")
|
|
|
|
| 260 |
.attr("x", width - margin.right - 10)
|
|
|
|
| 261 |
.attr("text-anchor", "end");
|
| 262 |
|
| 263 |
+
function applyDimensions() {
|
| 264 |
+
svg.attr("viewBox", [0, 0, width, height]);
|
| 265 |
+
y.range([margin.top, margin.top + barHeight * topN]);
|
| 266 |
+
ticker
|
| 267 |
+
.style("font-size", watermarkSize + "px")
|
| 268 |
+
.attr("y", height - 20);
|
| 269 |
+
}
|
| 270 |
+
applyDimensions();
|
| 271 |
+
|
| 272 |
// ---- Build keyframes for a benchmark ----
|
| 273 |
function buildKeyframes(benchmarkKey) {
|
| 274 |
const bm = raw.benchmarks[benchmarkKey];
|
|
|
|
| 592 |
d3.select("#speed-slider").on("input", function () {
|
| 593 |
frameDuration = +this.value;
|
| 594 |
d3.select("#speed-label").text(this.value + "ms");
|
| 595 |
+
// Interrupt running transitions so the new speed applies immediately
|
| 596 |
+
if (playing) svg.selectAll("*").interrupt();
|
| 597 |
+
});
|
| 598 |
+
|
| 599 |
+
// ---- Resize: keep all bars in view when the window changes ----
|
| 600 |
+
let resizeTimer;
|
| 601 |
+
window.addEventListener("resize", () => {
|
| 602 |
+
clearTimeout(resizeTimer);
|
| 603 |
+
resizeTimer = setTimeout(() => {
|
| 604 |
+
const prevHeight = height;
|
| 605 |
+
const prevBarHeight = barHeight;
|
| 606 |
+
computeDimensions();
|
| 607 |
+
if (height === prevHeight && barHeight === prevBarHeight) return;
|
| 608 |
+
applyDimensions();
|
| 609 |
+
if (keyframes.length > 0) {
|
| 610 |
+
// Clear and re-render so font sizes / bar heights pick up new dimensions
|
| 611 |
+
clearChart();
|
| 612 |
+
renderFrame(currentFrame, 0);
|
| 613 |
+
}
|
| 614 |
+
}, 150);
|
| 615 |
});
|
| 616 |
|
| 617 |
// ---- Initialize: load default benchmark and auto-play ----
|