agentsclimarketplace

Run2 d3 interactive table

Skill cxcscmu/SkillLearnBench/skills/b2-self-feedback-claude-sonnet-4-6/stock-data-visualization/run2_d3-interactive-table

Building a scrollable D3.js HTML table linked to a bubble chart with bidirectional click-highlight, correct scrollIntoView for overflow containers, and sector color badges.From its SKILL.md

Install
npx -y skills add cxcscmu/SkillLearnBench --skill run2_d3-interactive-table

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

3.3 KB, 828 tokens by cl100k_base, as published. Nobody here has run it

D3.js v6 Interactive Table (Improved)

HTML Structure

<div id="table-panel">
    <h2>All Stocks</h2>
    <div id="table-container">  <!-- scrollable wrapper -->
        <table id="stock-table">
            <thead><tr>
                <th>Ticker</th><th>Full Company Name</th>
                <th>Sector</th><th>Market Cap</th>
            </tr></thead>
            <tbody id="table-body"></tbody>
        </table>
    </div>
</div>

CSS — Sticky Header + Scrollable Body

#table-container {
    flex: 1;
    overflow-y: auto;   /* Scroll within panel */
}
#stock-table thead {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #f0f2f5;
}

Building Rows with D3

const sorted = [...data].sort((a, b) => a.ticker.localeCompare(b.ticker));
const rows = d3.select('#table-body')
    .selectAll('tr')
    .data(sorted, d => d.ticker)
    .join('tr')
    .attr('data-ticker', d => d.ticker);

rows.each(function(d) {
    const tr = d3.select(this);
    tr.append('td').text(d.ticker);
    tr.append('td').text(d['full name']);
    // Sector badge with matching bubble color
    tr.append('td').append('span')
        .attr('class', 'sector-badge')
        .style('background-color', getSectorColor(d.sector))
        .text(d.sector);
    tr.append('td').text(formatMarketCap(d.marketCapNum));
});

Bidirectional Selection

let currentSelected = null;

function handleSelection(ticker) {
    if (currentSelected === ticker) {
        // Toggle off
        currentSelected = null;
        d3.selectAll('circle.bubble').classed('highlighted', false);
        d3.selectAll('#table-body tr').classed('highlighted', false);
    } else {
        currentSelected = ticker;
        d3.selectAll('circle.bubble').classed('highlighted', d => d.ticker === ticker);
        d3.selectAll('#table-body tr').classed('highlighted', d => d.ticker === ticker);
        scrollTableToTicker(ticker);
    }
}

// Wire up table rows and circles to the same handler
rows.on('click', (event, d) => handleSelection(d.ticker));
circles.on('click', (event, d) => handleSelection(d.ticker));

Correct scrollIntoView for Nested Overflow Container

IMPORTANT: scrollIntoView() scrolls the nearest scrollable ancestor. Since #table-container is the scrollable container, this just works:

function scrollTableToTicker(ticker) {
    const row = document.querySelector(`#table-body tr[data-ticker="${ticker}"]`);
    if (row) {
        row.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }
}

block: 'nearest' is key — it scrolls only if the element is out of view, and scrolls within the nearest scrollable ancestor (#table-container).

CSS for Highlight States

#stock-table tbody tr.highlighted {
    background-color: #fff3cd;
    font-weight: 600;
}

circle.bubble.highlighted {
    stroke: #222;
    stroke-width: 3px;
    filter: drop-shadow(0 0 5px rgba(0,0,0,0.5));
}

.sector-badge {
    display: inline-block;
    padding: 2px 7px;
    border-radius: 10px;
    font-size: 0.75rem;
    color: white;
}

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.