chore: auto-commit before merge (loop primary)
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
---
|
||||
name: d3js-visualization
|
||||
description: Build deterministic, verifiable data visualizations with D3.js (v6). Generate standalone HTML/SVG (and optional PNG) from local data files without external network dependencies. Use when tasks require charts, plots, axes/scales, legends, tooltips, or data-driven SVG output.
|
||||
---
|
||||
|
||||
# D3.js Visualization Skill
|
||||
|
||||
Use this skill to turn structured data (CSV/TSV/JSON) into **clean, reproducible** visualizations using **D3.js**. The goal is to produce **stable outputs** that can be verified by diffing files or hashing.
|
||||
|
||||
## When to use
|
||||
|
||||
Activate this skill when the user asks for any of the following:
|
||||
|
||||
- “Make a chart/plot/graph/visualization”
|
||||
- bar/line/scatter/area/histogram/box/violin/heatmap
|
||||
- timelines, small multiples, faceting
|
||||
- axis ticks, scales, legends, tooltips
|
||||
- data-driven SVG output for a report or web page
|
||||
- converting data to a static SVG or HTML visualization
|
||||
|
||||
If the user only needs a quick table or summary, **don’t** use D3—use a spreadsheet or plain markdown instead.
|
||||
|
||||
---
|
||||
|
||||
## Inputs you should expect
|
||||
|
||||
- One or more local data files: `*.csv`, `*.tsv`, `*.json`
|
||||
- A chart intent:
|
||||
- chart type (or you infer the best type)
|
||||
- x/y fields and aggregation rules
|
||||
- sorting/filtering rules
|
||||
- dimensions (width/height) and margins
|
||||
- color rules (categorical / sequential)
|
||||
- any labeling requirements (title, axis labels, units)
|
||||
- Output constraints:
|
||||
- “static only”, “no animation”, “must be deterministic”, “offline”, etc.
|
||||
|
||||
If details are missing, **make reasonable defaults** and document them in comments near the top of the output file.
|
||||
|
||||
---
|
||||
|
||||
## Outputs you should produce
|
||||
|
||||
Prefer producing **all of** the following when feasible:
|
||||
|
||||
1. `dist/chart.html` — standalone HTML that renders the visualization
|
||||
2. `dist/chart.svg` — exported SVG (stable and diff-friendly)
|
||||
3. (Optional) `dist/chart.png` — if the task explicitly needs a raster image
|
||||
|
||||
Always keep outputs in a predictable folder (default: `dist/`), unless the task specifies paths.
|
||||
|
||||
---
|
||||
|
||||
## Determinism rules (non-negotiable)
|
||||
|
||||
To keep results stable across runs and machines:
|
||||
|
||||
### Data determinism
|
||||
- **Sort** input rows deterministically before binding to marks (e.g., by x then by category).
|
||||
- Use stable grouping order (explicit `Array.from(grouped.keys()).sort()`).
|
||||
- Avoid locale-dependent formatting unless fixed (use `d3.format`, `d3.timeFormat` with explicit formats).
|
||||
|
||||
### Rendering determinism
|
||||
- **No randomness**: do not use `Math.random()` or `d3-random`.
|
||||
- **No transitions/animations** by default (transitions can introduce timing variance).
|
||||
- **Fixed** `width`, `height`, `margin`, `viewBox`.
|
||||
- Use **explicit tick counts** only when needed; otherwise rely on D3 defaults but keep domains fixed.
|
||||
- Avoid layout algorithms with non-deterministic iteration unless you control seeds/iterations (e.g., force simulation). If a force layout is required:
|
||||
- fix the tick count,
|
||||
- fix initial positions deterministically (e.g., sorted nodes placed on a grid),
|
||||
- run exactly N ticks and stop.
|
||||
|
||||
### Offline + dependency determinism
|
||||
- Do **not** load D3 from a CDN.
|
||||
- Pin D3 to a specific version (default: **d3@7.9.0**).
|
||||
- Prefer vendoring a minified D3 bundle (e.g., `vendor/d3.v7.9.0.min.js`) or bundling with a lockfile.
|
||||
|
||||
### File determinism
|
||||
- Stable SVG output:
|
||||
- Avoid auto-generated IDs that may change.
|
||||
- If you must use IDs (clipPath, gradients), derive them from stable strings (e.g., `"clip-plot"`).
|
||||
- Use LF line endings.
|
||||
- Keep numeric precision consistent (e.g., round to 2–4 decimals if needed).
|
||||
|
||||
---
|
||||
|
||||
## Recommended project layout
|
||||
|
||||
If the task doesn't specify an existing structure, use:
|
||||
|
||||
```
|
||||
dist/
|
||||
chart.html # standalone HTML with inline or linked JS/CSS
|
||||
chart.svg # exported SVG (optional but nice)
|
||||
chart.png # rasterized (optional)
|
||||
vendor/
|
||||
d3.v7.9.0.min.js # pinned D3 library
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interactive features (tooltips, click handlers, hover effects)
|
||||
|
||||
When the task requires interactivity (e.g., tooltips on hover, click to highlight):
|
||||
|
||||
### Tooltip pattern (recommended)
|
||||
|
||||
1. **Create a tooltip element** in HTML:
|
||||
```html
|
||||
<div id="tooltip" class="tooltip"></div>
|
||||
```
|
||||
|
||||
2. **Style with CSS** using `.visible` class for show/hide:
|
||||
```css
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
pointer-events: none; /* Prevent mouse interference */
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.tooltip.visible {
|
||||
opacity: 1; /* Show when .visible class is added */
|
||||
}
|
||||
```
|
||||
|
||||
3. **Add event handlers** to SVG elements:
|
||||
```javascript
|
||||
svg.selectAll('circle')
|
||||
.on('mouseover', function(event, d) {
|
||||
d3.select('#tooltip')
|
||||
.classed('visible', true) // Add .visible class
|
||||
.html(`<strong>${d.name}</strong><br/>${d.value}`)
|
||||
.style('left', (event.pageX + 10) + 'px')
|
||||
.style('top', (event.pageY - 10) + 'px');
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
d3.select('#tooltip').classed('visible', false); // Remove .visible class
|
||||
});
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- Use `opacity: 0` by default (not `display: none`) for smooth transitions
|
||||
- Use `.classed('visible', true/false)` to toggle visibility
|
||||
- `pointer-events: none` prevents tooltip from blocking mouse events
|
||||
- Position tooltip relative to mouse with `event.pageX/pageY`
|
||||
|
||||
### Click handlers for selection/highlighting
|
||||
|
||||
```javascript
|
||||
// Add 'selected' class on click
|
||||
svg.selectAll('.bar')
|
||||
.on('click', function(event, d) {
|
||||
// Remove previous selection
|
||||
d3.selectAll('.bar').classed('selected', false);
|
||||
// Add to clicked element
|
||||
d3.select(this).classed('selected', true);
|
||||
});
|
||||
```
|
||||
|
||||
CSS for highlighting:
|
||||
```css
|
||||
.bar.selected {
|
||||
stroke: #000;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
```
|
||||
|
||||
### Conditional interactivity
|
||||
|
||||
Sometimes only certain elements should be interactive:
|
||||
```javascript
|
||||
.on('mouseover', function(event, d) {
|
||||
// Example: Don't show tooltip for certain categories
|
||||
if (d.category === 'excluded') {
|
||||
return; // Exit early, no tooltip
|
||||
}
|
||||
// Show tooltip for others
|
||||
showTooltip(event, d);
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user