(nodes)
| 4 | import { selectPerformanceNodeById } from './performance.js'; |
| 5 | |
| 6 | export function renderNodeList(nodes) { |
| 7 | setAllNodeData(nodes); |
| 8 | const container = document.getElementById('node-list-container'); |
| 9 | if (!container) return; |
| 10 | const search = document.getElementById('list-search').value.trim().toLowerCase(); |
| 11 | const sort = document.getElementById('list-sort').value; |
| 12 | let filtered = nodes; |
| 13 | if (search) { |
| 14 | filtered = nodes.filter(n => (n.id + '').toLowerCase().includes(search)); |
| 15 | } |
| 16 | const metric = getSelectedMetric(); |
| 17 | if (sort === 'id') { |
| 18 | filtered = filtered.slice().sort((a, b) => (a.id + '').localeCompare(b.id + '')); |
| 19 | } else if (sort === 'generation') { |
| 20 | filtered = filtered.slice().sort((a, b) => (a.generation || 0) - (b.generation || 0)); |
| 21 | } else if (sort === 'island') { |
| 22 | filtered = filtered.slice().sort((a, b) => (a.island || 0) - (b.island || 0)); |
| 23 | } else if (sort === 'score') { |
| 24 | filtered = filtered.slice().sort((a, b) => { |
| 25 | const aScore = a.metrics && typeof a.metrics[metric] === 'number' ? a.metrics[metric] : -Infinity; |
| 26 | const bScore = b.metrics && typeof b.metrics[metric] === 'number' ? b.metrics[metric] : -Infinity; |
| 27 | return bScore - aScore; |
| 28 | }); |
| 29 | } |
| 30 | const highlightFilter = document.getElementById('highlight-select').value; |
| 31 | const highlightNodes = getHighlightNodes(nodes, highlightFilter, metric); |
| 32 | const highlightIds = new Set(highlightNodes.map(n => n.id)); |
| 33 | const allScores = nodes.map(n => (n.metrics && typeof n.metrics[metric] === 'number') ? n.metrics[metric] : null).filter(x => x !== null && !isNaN(x)); |
| 34 | const minScore = allScores.length ? Math.min(...allScores) : 0; |
| 35 | const maxScore = allScores.length ? Math.max(...allScores) : 1; |
| 36 | const topScore = allScores.length ? Math.max(...allScores) : 0; |
| 37 | const avgScore = allScores.length ? (allScores.reduce((a, b) => a + b, 0) / allScores.length) : 0; |
| 38 | |
| 39 | let summaryBar = document.getElementById('list-summary-bar'); |
| 40 | if (!summaryBar) { |
| 41 | summaryBar = document.createElement('div'); |
| 42 | summaryBar.id = 'list-summary-bar'; |
| 43 | summaryBar.className = 'list-summary-bar'; |
| 44 | container.parentElement.insertBefore(summaryBar, container); |
| 45 | } |
| 46 | summaryBar.innerHTML = ` |
| 47 | <div class="summary-block"> |
| 48 | <span class="summary-icon">🏆</span> |
| 49 | <span class="summary-label">Top score</span> |
| 50 | <span class="summary-value">${topScore.toFixed(4)}</span> |
| 51 | ${renderMetricBar(topScore, minScore, maxScore)} |
| 52 | </div> |
| 53 | <div class="summary-block"> |
| 54 | <span class="summary-icon">📊</span> |
| 55 | <span class="summary-label">Average</span> |
| 56 | <span class="summary-value">${avgScore.toFixed(4)}</span> |
| 57 | ${renderMetricBar(avgScore, minScore, maxScore)} |
| 58 | <span style="margin-left:1.2em;font-size:0.98em;color:#888;vertical-align:middle;"> |
| 59 | <span title="Total programs, generations, islands">📦</span> Total: ${nodes.length} programs, ${new Set(nodes.map(n => n.generation)).size} generations, ${new Set(nodes.map(n => n.island)).size} islands |
| 60 | </span> |
| 61 | </div> |
| 62 | `; |
| 63 | container.innerHTML = ''; |
no test coverage detected