Initial commit
This commit is contained in:
221
skills/d3-visualization/resources/common-patterns.md
Normal file
221
skills/d3-visualization/resources/common-patterns.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# Common D3 Patterns - Code Templates
|
||||
|
||||
## Bar Chart Template
|
||||
|
||||
```javascript
|
||||
const data = [{label: 'A', value: 30}, {label: 'B', value: 80}, {label: 'C', value: 45}];
|
||||
|
||||
const xScale = d3.scaleBand()
|
||||
.domain(data.map(d => d.label))
|
||||
.range([0, width])
|
||||
.padding(0.1);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data, d => d.value)])
|
||||
.range([height, 0]);
|
||||
|
||||
svg.selectAll('rect')
|
||||
.data(data)
|
||||
.join('rect')
|
||||
.attr('x', d => xScale(d.label))
|
||||
.attr('y', d => yScale(d.value))
|
||||
.attr('width', xScale.bandwidth())
|
||||
.attr('height', d => height - yScale(d.value))
|
||||
.attr('fill', 'steelblue');
|
||||
|
||||
svg.append('g').attr('transform', `translate(0, ${height})`).call(d3.axisBottom(xScale));
|
||||
svg.append('g').call(d3.axisLeft(yScale));
|
||||
```
|
||||
|
||||
## Line Chart Template
|
||||
|
||||
```javascript
|
||||
const parseDate = d3.timeParse('%Y-%m-%d');
|
||||
data.forEach(d => { d.date = parseDate(d.date); });
|
||||
|
||||
const xScale = d3.scaleTime()
|
||||
.domain(d3.extent(data, d => d.date))
|
||||
.range([0, width]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(data, d => d.value)])
|
||||
.range([height, 0]);
|
||||
|
||||
const line = d3.line()
|
||||
.x(d => xScale(d.date))
|
||||
.y(d => yScale(d.value));
|
||||
|
||||
svg.append('path')
|
||||
.datum(data)
|
||||
.attr('d', line)
|
||||
.attr('fill', 'none')
|
||||
.attr('stroke', 'steelblue')
|
||||
.attr('stroke-width', 2);
|
||||
|
||||
svg.append('g').attr('transform', `translate(0, ${height})`).call(d3.axisBottom(xScale));
|
||||
svg.append('g').call(d3.axisLeft(yScale));
|
||||
```
|
||||
|
||||
## Scatter Plot Template
|
||||
|
||||
```javascript
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain(d3.extent(data, d => d.x))
|
||||
.range([0, width]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain(d3.extent(data, d => d.y))
|
||||
.range([height, 0]);
|
||||
|
||||
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
|
||||
|
||||
svg.selectAll('circle')
|
||||
.data(data)
|
||||
.join('circle')
|
||||
.attr('cx', d => xScale(d.x))
|
||||
.attr('cy', d => yScale(d.y))
|
||||
.attr('r', 5)
|
||||
.attr('fill', d => colorScale(d.category))
|
||||
.attr('opacity', 0.7);
|
||||
```
|
||||
|
||||
## Network Graph Template
|
||||
|
||||
```javascript
|
||||
const simulation = d3.forceSimulation(nodes)
|
||||
.force('link', d3.forceLink(links).id(d => d.id))
|
||||
.force('charge', d3.forceManyBody().strength(-100))
|
||||
.force('center', d3.forceCenter(width / 2, height / 2));
|
||||
|
||||
const link = svg.selectAll('line')
|
||||
.data(links)
|
||||
.join('line')
|
||||
.attr('stroke', '#999');
|
||||
|
||||
const node = svg.selectAll('circle')
|
||||
.data(nodes)
|
||||
.join('circle')
|
||||
.attr('r', 10)
|
||||
.attr('fill', d => d3.schemeCategory10[d.group]);
|
||||
|
||||
simulation.on('tick', () => {
|
||||
link.attr('x1', d => d.source.x).attr('y1', d => d.source.y)
|
||||
.attr('x2', d => d.target.x).attr('y2', d => d.target.y);
|
||||
node.attr('cx', d => d.x).attr('cy', d => d.y);
|
||||
});
|
||||
```
|
||||
|
||||
## Treemap Template
|
||||
|
||||
```javascript
|
||||
const root = d3.hierarchy(data)
|
||||
.sum(d => d.value)
|
||||
.sort((a, b) => b.value - a.value);
|
||||
|
||||
const treemap = d3.treemap().size([width, height]).padding(1);
|
||||
treemap(root);
|
||||
|
||||
svg.selectAll('rect')
|
||||
.data(root.leaves())
|
||||
.join('rect')
|
||||
.attr('x', d => d.x0)
|
||||
.attr('y', d => d.y0)
|
||||
.attr('width', d => d.x1 - d.x0)
|
||||
.attr('height', d => d.y1 - d.y0)
|
||||
.attr('fill', d => d3.interpolateBlues(d.value / root.value));
|
||||
|
||||
svg.selectAll('text')
|
||||
.data(root.leaves())
|
||||
.join('text')
|
||||
.attr('x', d => d.x0 + 5)
|
||||
.attr('y', d => d.y0 + 15)
|
||||
.text(d => d.data.name);
|
||||
```
|
||||
|
||||
## Geographic Map Template
|
||||
|
||||
```javascript
|
||||
d3.json('world.geojson').then(geojson => {
|
||||
const projection = d3.geoMercator()
|
||||
.fitExtent([[0, 0], [width, height]], geojson);
|
||||
|
||||
const path = d3.geoPath().projection(projection);
|
||||
|
||||
svg.selectAll('path')
|
||||
.data(geojson.features)
|
||||
.join('path')
|
||||
.attr('d', path)
|
||||
.attr('fill', '#ccc')
|
||||
.attr('stroke', '#fff');
|
||||
});
|
||||
```
|
||||
|
||||
## Zoom and Pan Pattern
|
||||
|
||||
```javascript
|
||||
const zoom = d3.zoom()
|
||||
.scaleExtent([0.5, 5])
|
||||
.on('zoom', (event) => g.attr('transform', event.transform));
|
||||
|
||||
svg.call(zoom);
|
||||
|
||||
const g = svg.append('g');
|
||||
g.selectAll('circle').data(data).join('circle')...
|
||||
```
|
||||
|
||||
## Brush Selection Pattern
|
||||
|
||||
```javascript
|
||||
const brush = d3.brush()
|
||||
.extent([[0, 0], [width, height]])
|
||||
.on('end', (event) => {
|
||||
if (!event.selection) return;
|
||||
const [[x0, y0], [x1, y1]] = event.selection;
|
||||
const selected = data.filter(d => {
|
||||
const x = xScale(d.x), y = yScale(d.y);
|
||||
return x >= x0 && x <= x1 && y >= y0 && y <= y1;
|
||||
});
|
||||
updateChart(selected);
|
||||
});
|
||||
|
||||
svg.append('g').attr('class', 'brush').call(brush);
|
||||
```
|
||||
|
||||
## Transition Pattern
|
||||
|
||||
```javascript
|
||||
function update(newData) {
|
||||
yScale.domain([0, d3.max(newData, d => d.value)]);
|
||||
|
||||
svg.selectAll('rect')
|
||||
.data(newData)
|
||||
.join('rect')
|
||||
.transition().duration(750).ease(d3.easeCubicOut)
|
||||
.attr('y', d => yScale(d.value))
|
||||
.attr('height', d => height - yScale(d.value));
|
||||
|
||||
svg.select('.y-axis').transition().duration(750).call(d3.axisLeft(yScale));
|
||||
}
|
||||
```
|
||||
|
||||
## Tooltip Pattern
|
||||
|
||||
```javascript
|
||||
const tooltip = d3.select('body').append('div')
|
||||
.attr('class', 'tooltip')
|
||||
.style('position', 'absolute')
|
||||
.style('visibility', 'hidden');
|
||||
|
||||
svg.selectAll('circle')
|
||||
.data(data)
|
||||
.join('circle')
|
||||
.attr('r', 5)
|
||||
.on('mouseover', (event, d) => {
|
||||
tooltip.style('visibility', 'visible').html(`Value: ${d.value}`);
|
||||
})
|
||||
.on('mousemove', (event) => {
|
||||
tooltip.style('top', (event.pageY - 10) + 'px')
|
||||
.style('left', (event.pageX + 10) + 'px');
|
||||
})
|
||||
.on('mouseout', () => tooltip.style('visibility', 'hidden'));
|
||||
```
|
||||
Reference in New Issue
Block a user