Upload benchmark-chart.js with huggingface_hub
Browse files- benchmark-chart.js +18 -2
benchmark-chart.js
CHANGED
|
@@ -9,7 +9,8 @@ class ResmpBenchmarkChart extends HTMLElement {
|
|
| 9 |
render() {
|
| 10 |
const cfg = this._config;
|
| 11 |
if (!cfg) return;
|
| 12 |
-
|
|
|
|
| 13 |
const min = Math.min(0, ...all), max = Math.max(1, ...all);
|
| 14 |
this.innerHTML = `<section class="resmp-chart">
|
| 15 |
<header class="chart-head">
|
|
@@ -33,13 +34,28 @@ class ResmpBenchmarkChart extends HTMLElement {
|
|
| 33 |
const gap = 7, barW = Math.min(36, (width-left-right-gap*(series.length-1))/series.length);
|
| 34 |
const total = series.length * barW + (series.length - 1) * gap, start = (width - total) / 2;
|
| 35 |
const bars = series.map((s, i) => {
|
| 36 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
const y = Math.min(yv, zeroY), h = Math.max(1, Math.abs(zeroY - yv)), x = start + i * (barW + gap);
|
| 38 |
const labelY = v >= 0 ? y - 5 : y + h + 11;
|
| 39 |
return `<g><rect x="${x}" y="${y}" width="${barW}" height="${h}" fill="${this.escape(s.color)}"/><text x="${x+barW/2}" y="${labelY}" text-anchor="middle" class="value">${v.toFixed(2)}</text><text x="${x+barW/2}" y="${Math.min(y+h-7, zeroY-7)}" text-anchor="middle" class="series-code">${this.escape(s.id.slice(0,2).toUpperCase())}</text></g>`;
|
| 40 |
}).join('');
|
| 41 |
return `<figure><svg viewBox="0 0 ${width} ${height}" role="img" aria-label="${this.escape(panel.name)} benchmark"><line x1="${left}" y1="${zeroY}" x2="${width-right}" y2="${zeroY}" class="baseline"/>${bars}<text x="${width/2}" y="${height-8}" text-anchor="middle" class="panel-name">${this.escape(panel.name)}</text></svg></figure>`;
|
| 42 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
exportSvg() {
|
| 44 |
const chart = this.querySelector('.resmp-chart').cloneNode(true); chart.querySelector('.chart-actions')?.remove();
|
| 45 |
const css = [...document.styleSheets].flatMap(s => { try { return [...s.cssRules].map(r=>r.cssText) } catch { return [] } }).join('\n');
|
|
|
|
| 9 |
render() {
|
| 10 |
const cfg = this._config;
|
| 11 |
if (!cfg) return;
|
| 12 |
+
this.validate(cfg);
|
| 13 |
+
const all = cfg.groups.flatMap(g => g.panels.flatMap(p => Object.values(p.values))).filter(Number.isFinite);
|
| 14 |
const min = Math.min(0, ...all), max = Math.max(1, ...all);
|
| 15 |
this.innerHTML = `<section class="resmp-chart">
|
| 16 |
<header class="chart-head">
|
|
|
|
| 34 |
const gap = 7, barW = Math.min(36, (width-left-right-gap*(series.length-1))/series.length);
|
| 35 |
const total = series.length * barW + (series.length - 1) * gap, start = (width - total) / 2;
|
| 36 |
const bars = series.map((s, i) => {
|
| 37 |
+
const raw = panel.values[s.id];
|
| 38 |
+
if (raw === null || raw === undefined || !Number.isFinite(Number(raw))) {
|
| 39 |
+
const x = start + i * (barW + gap);
|
| 40 |
+
return `<g><rect x="${x}" y="${top}" width="${barW}" height="${plotH}" fill="none" stroke="${this.escape(s.color)}" stroke-dasharray="3 3" opacity=".35"/><text x="${x+barW/2}" y="${zeroY-6}" text-anchor="middle" class="value">N/A</text></g>`;
|
| 41 |
+
}
|
| 42 |
+
const v = Number(raw), yv = top + ((max - v) / (max - min)) * plotH;
|
| 43 |
const y = Math.min(yv, zeroY), h = Math.max(1, Math.abs(zeroY - yv)), x = start + i * (barW + gap);
|
| 44 |
const labelY = v >= 0 ? y - 5 : y + h + 11;
|
| 45 |
return `<g><rect x="${x}" y="${y}" width="${barW}" height="${h}" fill="${this.escape(s.color)}"/><text x="${x+barW/2}" y="${labelY}" text-anchor="middle" class="value">${v.toFixed(2)}</text><text x="${x+barW/2}" y="${Math.min(y+h-7, zeroY-7)}" text-anchor="middle" class="series-code">${this.escape(s.id.slice(0,2).toUpperCase())}</text></g>`;
|
| 46 |
}).join('');
|
| 47 |
return `<figure><svg viewBox="0 0 ${width} ${height}" role="img" aria-label="${this.escape(panel.name)} benchmark"><line x1="${left}" y1="${zeroY}" x2="${width-right}" y2="${zeroY}" class="baseline"/>${bars}<text x="${width/2}" y="${height-8}" text-anchor="middle" class="panel-name">${this.escape(panel.name)}</text></svg></figure>`;
|
| 48 |
}
|
| 49 |
+
validate(cfg) {
|
| 50 |
+
if (!cfg || typeof cfg !== 'object') throw new TypeError('Benchmark config must be an object.');
|
| 51 |
+
if (!Array.isArray(cfg.series) || cfg.series.length < 1) throw new TypeError('Benchmark config requires at least one series.');
|
| 52 |
+
if (!Array.isArray(cfg.groups) || cfg.groups.length < 1) throw new TypeError('Benchmark config requires at least one group.');
|
| 53 |
+
const ids = cfg.series.map(s => s.id);
|
| 54 |
+
if (new Set(ids).size !== ids.length) throw new TypeError('Series IDs must be unique.');
|
| 55 |
+
for (const group of cfg.groups) {
|
| 56 |
+
if (!Array.isArray(group.panels) || group.panels.length < 1) throw new TypeError(`Group ${group.name || '(unnamed)'} requires panels.`);
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
exportSvg() {
|
| 60 |
const chart = this.querySelector('.resmp-chart').cloneNode(true); chart.querySelector('.chart-actions')?.remove();
|
| 61 |
const css = [...document.styleSheets].flatMap(s => { try { return [...s.cssRules].map(r=>r.cssText) } catch { return [] } }).join('\n');
|