claude-d3js-skill

安装量: 102
排名: #8176

安装

npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill claude-d3js-skill

D3.js Visualisation Overview This skill provides guidance for creating sophisticated, interactive data visualisations using d3.js. D3.js (Data-Driven Documents) excels at binding data to DOM elements and applying data-driven transformations to create custom, publication-quality visualisations with precise control over every visual element. The techniques work across any JavaScript environment, including vanilla JavaScript, React, Vue, Svelte, and other frameworks. When to use d3.js Use d3.js for: Custom visualisations requiring unique visual encodings or layouts Interactive explorations with complex pan, zoom, or brush behaviours Network/graph visualisations (force-directed layouts, tree diagrams, hierarchies, chord diagrams) Geographic visualisations with custom projections Visualisations requiring smooth, choreographed transitions Publication-quality graphics with fine-grained styling control Novel chart types not available in standard libraries Consider alternatives for: 3D visualisations - use Three.js instead Core workflow 1. Set up d3.js Import d3 at the top of your script: import * as d3 from 'd3' ; Or use the CDN version (7.x): < script src = " https://d3js.org/d3.v7.min.js "

</ script

All modules (scales, axes, shapes, transitions, etc.) are accessible through the d3 namespace. 2. Choose the integration pattern Pattern A: Direct DOM manipulation (recommended for most cases) Use d3 to select DOM elements and manipulate them imperatively. This works in any JavaScript environment: function drawChart ( data ) { if ( ! data || data . length === 0 ) return ; const svg = d3 . select ( '#chart' ) ; // Select by ID, class, or DOM element // Clear previous content svg . selectAll ( "" ) . remove ( ) ; // Set up dimensions const width = 800 ; const height = 400 ; const margin = { top : 20 , right : 30 , bottom : 40 , left : 50 } ; // Create scales, axes, and draw visualisation // ... d3 code here ... } // Call when data changes drawChart ( myData ) ; Pattern B: Declarative rendering (for frameworks with templating) Use d3 for data calculations (scales, layouts) but render elements via your framework: function getChartElements ( data ) { const xScale = d3 . scaleLinear ( ) . domain ( [ 0 , d3 . max ( data , d => d . value ) ] ) . range ( [ 0 , 400 ] ) ; return data . map ( ( d , i ) => ( { x : 50 , y : i * 30 , width : xScale ( d . value ) , height : 25 } ) ) ; } // In React: {getChartElements(data).map((d, i) => )} // In Vue: v-for directive over the returned array // In vanilla JS: Create elements manually from the returned data Use Pattern A for complex visualisations with transitions, interactions, or when leveraging d3's full capabilities. Use Pattern B for simpler visualisations or when your framework prefers declarative rendering. 3. Structure the visualisation code Follow this standard structure in your drawing function: function drawVisualization ( data ) { if ( ! data || data . length === 0 ) return ; const svg = d3 . select ( '#chart' ) ; // Or pass a selector/element svg . selectAll ( "" ) . remove ( ) ; // Clear previous render // 1. Define dimensions const width = 800 ; const height = 400 ; const margin = { top : 20 , right : 30 , bottom : 40 , left : 50 } ; const innerWidth = width - margin . left - margin . right ; const innerHeight = height - margin . top - margin . bottom ; // 2. Create main group with margins const g = svg . append ( "g" ) . attr ( "transform" , translate( ${ margin . left } , ${ margin . top } ) ) ; // 3. Create scales const xScale = d3 . scaleLinear ( ) . domain ( [ 0 , d3 . max ( data , d => d . x ) ] ) . range ( [ 0 , innerWidth ] ) ; const yScale = d3 . scaleLinear ( ) . domain ( [ 0 , d3 . max ( data , d => d . y ) ] ) . range ( [ innerHeight , 0 ] ) ; // Note: inverted for SVG coordinates // 4. Create and append axes const xAxis = d3 . axisBottom ( xScale ) ; const yAxis = d3 . axisLeft ( yScale ) ; g . append ( "g" ) . attr ( "transform" , translate(0, ${ innerHeight } ) ) . call ( xAxis ) ; g . append ( "g" ) . call ( yAxis ) ; // 5. Bind data and create visual elements g . selectAll ( "circle" ) . data ( data ) . join ( "circle" ) . attr ( "cx" , d => xScale ( d . x ) ) . attr ( "cy" , d => yScale ( d . y ) ) . attr ( "r" , 5 ) . attr ( "fill" , "steelblue" ) ; } // Call when data changes drawVisualization ( myData ) ; 4. Implement responsive sizing Make visualisations responsive to container size: function setupResponsiveChart ( containerId , data ) { const container = document . getElementById ( containerId ) ; const svg = d3 . select ( `

${
containerId
}
`
)
.
append
(
'svg'
)
;
function
updateChart
(
)
{
const
{
width
,
height
}
=
container
.
getBoundingClientRect
(
)
;
svg
.
attr
(
'width'
,
width
)
.
attr
(
'height'
,
height
)
;
// Redraw visualisation with new dimensions
drawChart
(
data
,
svg
,
width
,
height
)
;
}
// Update on initial load
updateChart
(
)
;
// Update on window resize
window
.
addEventListener
(
'resize'
,
updateChart
)
;
// Return cleanup function
return
(
)
=>
window
.
removeEventListener
(
'resize'
,
updateChart
)
;
}
// Usage:
// const cleanup = setupResponsiveChart('chart-container', myData);
// cleanup(); // Call when component unmounts or element removed
Or use ResizeObserver for more direct container monitoring:
function
setupResponsiveChartWithObserver
(
svgElement
,
data
)
{
const
observer
=
new
ResizeObserver
(
(
)
=>
{
const
{
width
,
height
}
=
svgElement
.
getBoundingClientRect
(
)
;
d3
.
select
(
svgElement
)
.
attr
(
'width'
,
width
)
.
attr
(
'height'
,
height
)
;
// Redraw visualisation
drawChart
(
data
,
d3
.
select
(
svgElement
)
,
width
,
height
)
;
}
)
;
observer
.
observe
(
svgElement
.
parentElement
)
;
return
(
)
=>
observer
.
disconnect
(
)
;
}
Common visualisation patterns
Bar chart
function
drawBarChart
(
data
,
svgElement
)
{
if
(
!
data
||
data
.
length
===
0
)
return
;
const
svg
=
d3
.
select
(
svgElement
)
;
svg
.
selectAll
(
"*"
)
.
remove
(
)
;
const
width
=
800
;
const
height
=
400
;
const
margin
=
{
top
:
20
,
right
:
30
,
bottom
:
40
,
left
:
50
}
;
const
innerWidth
=
width
-
margin
.
left
-
margin
.
right
;
const
innerHeight
=
height
-
margin
.
top
-
margin
.
bottom
;
const
g
=
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
margin
.
left
}
,
${
margin
.
top
}
)
`
)
;
const
xScale
=
d3
.
scaleBand
(
)
.
domain
(
data
.
map
(
d
=>
d
.
category
)
)
.
range
(
[
0
,
innerWidth
]
)
.
padding
(
0.1
)
;
const
yScale
=
d3
.
scaleLinear
(
)
.
domain
(
[
0
,
d3
.
max
(
data
,
d
=>
d
.
value
)
]
)
.
range
(
[
innerHeight
,
0
]
)
;
g
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(0,
${
innerHeight
}
)
`
)
.
call
(
d3
.
axisBottom
(
xScale
)
)
;
g
.
append
(
"g"
)
.
call
(
d3
.
axisLeft
(
yScale
)
)
;
g
.
selectAll
(
"rect"
)
.
data
(
data
)
.
join
(
"rect"
)
.
attr
(
"x"
,
d
=>
xScale
(
d
.
category
)
)
.
attr
(
"y"
,
d
=>
yScale
(
d
.
value
)
)
.
attr
(
"width"
,
xScale
.
bandwidth
(
)
)
.
attr
(
"height"
,
d
=>
innerHeight
-
yScale
(
d
.
value
)
)
.
attr
(
"fill"
,
"steelblue"
)
;
}
// Usage:
// drawBarChart(myData, document.getElementById('chart'));
Line chart
const
line
=
d3
.
line
(
)
.
x
(
d
=>
xScale
(
d
.
date
)
)
.
y
(
d
=>
yScale
(
d
.
value
)
)
.
curve
(
d3
.
curveMonotoneX
)
;
// Smooth curve
g
.
append
(
"path"
)
.
datum
(
data
)
.
attr
(
"fill"
,
"none"
)
.
attr
(
"stroke"
,
"steelblue"
)
.
attr
(
"stroke-width"
,
2
)
.
attr
(
"d"
,
line
)
;
Scatter plot
g
.
selectAll
(
"circle"
)
.
data
(
data
)
.
join
(
"circle"
)
.
attr
(
"cx"
,
d
=>
xScale
(
d
.
x
)
)
.
attr
(
"cy"
,
d
=>
yScale
(
d
.
y
)
)
.
attr
(
"r"
,
d
=>
sizeScale
(
d
.
size
)
)
// Optional: size encoding
.
attr
(
"fill"
,
d
=>
colourScale
(
d
.
category
)
)
// Optional: colour encoding
.
attr
(
"opacity"
,
0.7
)
;
Chord diagram
A chord diagram shows relationships between entities in a circular layout, with ribbons representing flows between them:
function
drawChordDiagram
(
data
)
{
// data format: array of objects with source, target, and value
// Example: [{ source: 'A', target: 'B', value: 10 }, ...]
if
(
!
data
||
data
.
length
===
0
)
return
;
const
svg
=
d3
.
select
(
'#chart'
)
;
svg
.
selectAll
(
"*"
)
.
remove
(
)
;
const
width
=
600
;
const
height
=
600
;
const
innerRadius
=
Math
.
min
(
width
,
height
)
*
0.3
;
const
outerRadius
=
innerRadius
+
30
;
// Create matrix from data
const
nodes
=
Array
.
from
(
new
Set
(
data
.
flatMap
(
d
=>
[
d
.
source
,
d
.
target
]
)
)
)
;
const
matrix
=
Array
.
from
(
{
length
:
nodes
.
length
}
,
(
)
=>
Array
(
nodes
.
length
)
.
fill
(
0
)
)
;
data
.
forEach
(
d
=>
{
const
i
=
nodes
.
indexOf
(
d
.
source
)
;
const
j
=
nodes
.
indexOf
(
d
.
target
)
;
matrix
[
i
]
[
j
]
+=
d
.
value
;
matrix
[
j
]
[
i
]
+=
d
.
value
;
}
)
;
// Create chord layout
const
chord
=
d3
.
chord
(
)
.
padAngle
(
0.05
)
.
sortSubgroups
(
d3
.
descending
)
;
const
arc
=
d3
.
arc
(
)
.
innerRadius
(
innerRadius
)
.
outerRadius
(
outerRadius
)
;
const
ribbon
=
d3
.
ribbon
(
)
.
source
(
d
=>
d
.
source
)
.
target
(
d
=>
d
.
target
)
;
const
colourScale
=
d3
.
scaleOrdinal
(
d3
.
schemeCategory10
)
.
domain
(
nodes
)
;
const
g
=
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
width
/
2
}
,
${
height
/
2
}
)
`
)
;
const
chords
=
chord
(
matrix
)
;
// Draw ribbons
g
.
append
(
"g"
)
.
attr
(
"fill-opacity"
,
0.67
)
.
selectAll
(
"path"
)
.
data
(
chords
)
.
join
(
"path"
)
.
attr
(
"d"
,
ribbon
)
.
attr
(
"fill"
,
d
=>
colourScale
(
nodes
[
d
.
source
.
index
]
)
)
.
attr
(
"stroke"
,
d
=>
d3
.
rgb
(
colourScale
(
nodes
[
d
.
source
.
index
]
)
)
.
darker
(
)
)
;
// Draw groups (arcs)
const
group
=
g
.
append
(
"g"
)
.
selectAll
(
"g"
)
.
data
(
chords
.
groups
)
.
join
(
"g"
)
;
group
.
append
(
"path"
)
.
attr
(
"d"
,
arc
)
.
attr
(
"fill"
,
d
=>
colourScale
(
nodes
[
d
.
index
]
)
)
.
attr
(
"stroke"
,
d
=>
d3
.
rgb
(
colourScale
(
nodes
[
d
.
index
]
)
)
.
darker
(
)
)
;
// Add labels
group
.
append
(
"text"
)
.
each
(
d
=>
{
d
.
angle
=
(
d
.
startAngle
+
d
.
endAngle
)
/
2
;
}
)
.
attr
(
"dy"
,
"0.31em"
)
.
attr
(
"transform"
,
d
=>
`
rotate(
${
(
d
.
angle
*
180
/
Math
.
PI
)
-
90
}
)translate(
${
outerRadius
+
30
}
)
${
d
.
angle
>
Math
.
PI
?
"rotate(180)"
:
""
}
`
)
.
attr
(
"text-anchor"
,
d
=>
d
.
angle
>
Math
.
PI
?
"end"
:
null
)
.
text
(
(
d
,
i
)
=>
nodes
[
i
]
)
.
style
(
"font-size"
,
"12px"
)
;
}
Heatmap
A heatmap uses colour to encode values in a two-dimensional grid, useful for showing patterns across categories:
function
drawHeatmap
(
data
)
{
// data format: array of objects with row, column, and value
// Example: [{ row: 'A', column: 'X', value: 10 }, ...]
if
(
!
data
||
data
.
length
===
0
)
return
;
const
svg
=
d3
.
select
(
'#chart'
)
;
svg
.
selectAll
(
"*"
)
.
remove
(
)
;
const
width
=
800
;
const
height
=
600
;
const
margin
=
{
top
:
100
,
right
:
30
,
bottom
:
30
,
left
:
100
}
;
const
innerWidth
=
width
-
margin
.
left
-
margin
.
right
;
const
innerHeight
=
height
-
margin
.
top
-
margin
.
bottom
;
// Get unique rows and columns
const
rows
=
Array
.
from
(
new
Set
(
data
.
map
(
d
=>
d
.
row
)
)
)
;
const
columns
=
Array
.
from
(
new
Set
(
data
.
map
(
d
=>
d
.
column
)
)
)
;
const
g
=
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
margin
.
left
}
,
${
margin
.
top
}
)
`
)
;
// Create scales
const
xScale
=
d3
.
scaleBand
(
)
.
domain
(
columns
)
.
range
(
[
0
,
innerWidth
]
)
.
padding
(
0.01
)
;
const
yScale
=
d3
.
scaleBand
(
)
.
domain
(
rows
)
.
range
(
[
0
,
innerHeight
]
)
.
padding
(
0.01
)
;
// Colour scale for values
const
colourScale
=
d3
.
scaleSequential
(
d3
.
interpolateYlOrRd
)
.
domain
(
[
0
,
d3
.
max
(
data
,
d
=>
d
.
value
)
]
)
;
// Draw rectangles
g
.
selectAll
(
"rect"
)
.
data
(
data
)
.
join
(
"rect"
)
.
attr
(
"x"
,
d
=>
xScale
(
d
.
column
)
)
.
attr
(
"y"
,
d
=>
yScale
(
d
.
row
)
)
.
attr
(
"width"
,
xScale
.
bandwidth
(
)
)
.
attr
(
"height"
,
yScale
.
bandwidth
(
)
)
.
attr
(
"fill"
,
d
=>
colourScale
(
d
.
value
)
)
;
// Add x-axis labels
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
margin
.
left
}
,
${
margin
.
top
}
)
`
)
.
selectAll
(
"text"
)
.
data
(
columns
)
.
join
(
"text"
)
.
attr
(
"x"
,
d
=>
xScale
(
d
)
+
xScale
.
bandwidth
(
)
/
2
)
.
attr
(
"y"
,
-
10
)
.
attr
(
"text-anchor"
,
"middle"
)
.
text
(
d
=>
d
)
.
style
(
"font-size"
,
"12px"
)
;
// Add y-axis labels
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
margin
.
left
}
,
${
margin
.
top
}
)
`
)
.
selectAll
(
"text"
)
.
data
(
rows
)
.
join
(
"text"
)
.
attr
(
"x"
,
-
10
)
.
attr
(
"y"
,
d
=>
yScale
(
d
)
+
yScale
.
bandwidth
(
)
/
2
)
.
attr
(
"dy"
,
"0.35em"
)
.
attr
(
"text-anchor"
,
"end"
)
.
text
(
d
=>
d
)
.
style
(
"font-size"
,
"12px"
)
;
// Add colour legend
const
legendWidth
=
20
;
const
legendHeight
=
200
;
const
legend
=
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
width
-
60
}
,
${
margin
.
top
}
)
`
)
;
const
legendScale
=
d3
.
scaleLinear
(
)
.
domain
(
colourScale
.
domain
(
)
)
.
range
(
[
legendHeight
,
0
]
)
;
const
legendAxis
=
d3
.
axisRight
(
legendScale
)
.
ticks
(
5
)
;
// Draw colour gradient in legend
for
(
let
i
=
0
;
i
<
legendHeight
;
i
++
)
{
legend
.
append
(
"rect"
)
.
attr
(
"y"
,
i
)
.
attr
(
"width"
,
legendWidth
)
.
attr
(
"height"
,
1
)
.
attr
(
"fill"
,
colourScale
(
legendScale
.
invert
(
i
)
)
)
;
}
legend
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
legendWidth
}
,0)
`
)
.
call
(
legendAxis
)
;
}
Pie chart
const
pie
=
d3
.
pie
(
)
.
value
(
d
=>
d
.
value
)
.
sort
(
null
)
;
const
arc
=
d3
.
arc
(
)
.
innerRadius
(
0
)
.
outerRadius
(
Math
.
min
(
width
,
height
)
/
2
-
20
)
;
const
colourScale
=
d3
.
scaleOrdinal
(
d3
.
schemeCategory10
)
;
const
g
=
svg
.
append
(
"g"
)
.
attr
(
"transform"
,
`
translate(
${
width
/
2
}
,
${
height
/
2
}
)
`
)
;
g
.
selectAll
(
"path"
)
.
data
(
pie
(
data
)
)
.
join
(
"path"
)
.
attr
(
"d"
,
arc
)
.
attr
(
"fill"
,
(
d
,
i
)
=>
colourScale
(
i
)
)
.
attr
(
"stroke"
,
"white"
)
.
attr
(
"stroke-width"
,
2
)
;
Force-directed network
const
simulation
=
d3
.
forceSimulation
(
nodes
)
.
force
(
"link"
,
d3
.
forceLink
(
links
)
.
id
(
d
=>
d
.
id
)
.
distance
(
100
)
)
.
force
(
"charge"
,
d3
.
forceManyBody
(
)
.
strength
(
-
300
)
)
.
force
(
"center"
,
d3
.
forceCenter
(
width
/
2
,
height
/
2
)
)
;
const
link
=
g
.
selectAll
(
"line"
)
.
data
(
links
)
.
join
(
"line"
)
.
attr
(
"stroke"
,
"#999"
)
.
attr
(
"stroke-width"
,
1
)
;
const
node
=
g
.
selectAll
(
"circle"
)
.
data
(
nodes
)
.
join
(
"circle"
)
.
attr
(
"r"
,
8
)
.
attr
(
"fill"
,
"steelblue"
)
.
call
(
d3
.
drag
(
)
.
on
(
"start"
,
dragstarted
)
.
on
(
"drag"
,
dragged
)
.
on
(
"end"
,
dragended
)
)
;
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
)
;
}
)
;
function
dragstarted
(
event
)
{
if
(
!
event
.
active
)
simulation
.
alphaTarget
(
0.3
)
.
restart
(
)
;
event
.
subject
.
fx
=
event
.
subject
.
x
;
event
.
subject
.
fy
=
event
.
subject
.
y
;
}
function
dragged
(
event
)
{
event
.
subject
.
fx
=
event
.
x
;
event
.
subject
.
fy
=
event
.
y
;
}
function
dragended
(
event
)
{
if
(
!
event
.
active
)
simulation
.
alphaTarget
(
0
)
;
event
.
subject
.
fx
=
null
;
event
.
subject
.
fy
=
null
;
}
Adding interactivity
Tooltips
// Create tooltip div (outside SVG)
const
tooltip
=
d3
.
select
(
"body"
)
.
append
(
"div"
)
.
attr
(
"class"
,
"tooltip"
)
.
style
(
"position"
,
"absolute"
)
.
style
(
"visibility"
,
"hidden"
)
.
style
(
"background-color"
,
"white"
)
.
style
(
"border"
,
"1px solid #ddd"
)
.
style
(
"padding"
,
"10px"
)
.
style
(
"border-radius"
,
"4px"
)
.
style
(
"pointer-events"
,
"none"
)
;
// Add to elements
circles
.
on
(
"mouseover"
,
function
(
event
,
d
)
{
d3
.
select
(
this
)
.
attr
(
"opacity"
,
1
)
;
tooltip
.
style
(
"visibility"
,
"visible"
)
.
html
(
`
${
d
.
label
}

Value:
${
d
.
value
}
`
)
;
}
)
.
on
(
"mousemove"
,
function
(
event
)
{
tooltip
.
style
(
"top"
,
(
event
.
pageY
-
10
)
+
"px"
)
.
style
(
"left"
,
(
event
.
pageX
+
10
)
+
"px"
)
;
}
)
.
on
(
"mouseout"
,
function
(
)
{
d3
.
select
(
this
)
.
attr
(
"opacity"
,
0.7
)
;
tooltip
.
style
(
"visibility"
,
"hidden"
)
;
}
)
;
Zoom and pan
const
zoom
=
d3
.
zoom
(
)
.
scaleExtent
(
[
0.5
,
10
]
)
.
on
(
"zoom"
,
(
event
)
=>
{
g
.
attr
(
"transform"
,
event
.
transform
)
;
}
)
;
svg
.
call
(
zoom
)
;
Click interactions
circles
.
on
(
"click"
,
function
(
event
,
d
)
{
// Handle click (dispatch event, update app state, etc.)
console
.
log
(
"Clicked:"
,
d
)
;
// Visual feedback
d3
.
selectAll
(
"circle"
)
.
attr
(
"fill"
,
"steelblue"
)
;
d3
.
select
(
this
)
.
attr
(
"fill"
,
"orange"
)
;
// Optional: dispatch custom event for your framework/app to listen to
// window.dispatchEvent(new CustomEvent('chartClick', { detail: d }));
}
)
;
Transitions and animations
Add smooth transitions to visual changes:
// Basic transition
circles
.
transition
(
)
.
duration
(
750
)
.
attr
(
"r"
,
10
)
;
// Chained transitions
circles
.
transition
(
)
.
duration
(
500
)
.
attr
(
"fill"
,
"orange"
)
.
transition
(
)
.
duration
(
500
)
.
attr
(
"r"
,
15
)
;
// Staggered transitions
circles
.
transition
(
)
.
delay
(
(
d
,
i
)
=>
i
*
50
)
.
duration
(
500
)
.
attr
(
"cy"
,
d
=>
yScale
(
d
.
value
)
)
;
// Custom easing
circles
.
transition
(
)
.
duration
(
1000
)
.
ease
(
d3
.
easeBounceOut
)
.
attr
(
"r"
,
10
)
;
Scales reference
Quantitative scales
// Linear scale
const
xScale
=
d3
.
scaleLinear
(
)
.
domain
(
[
0
,
100
]
)
.
range
(
[
0
,
500
]
)
;
// Log scale (for exponential data)
const
logScale
=
d3
.
scaleLog
(
)
.
domain
(
[
1
,
1000
]
)
.
range
(
[
0
,
500
]
)
;
// Power scale
const
powScale
=
d3
.
scalePow
(
)
.
exponent
(
2
)
.
domain
(
[
0
,
100
]
)
.
range
(
[
0
,
500
]
)
;
// Time scale
const
timeScale
=
d3
.
scaleTime
(
)
.
domain
(
[
new
Date
(
2020
,
0
,
1
)
,
new
Date
(
2024
,
0
,
1
)
]
)
.
range
(
[
0
,
500
]
)
;
Ordinal scales
// Band scale (for bar charts)
const
bandScale
=
d3
.
scaleBand
(
)
.
domain
(
[
'A'
,
'B'
,
'C'
,
'D'
]
)
.
range
(
[
0
,
400
]
)
.
padding
(
0.1
)
;
// Point scale (for line/scatter categories)
const
pointScale
=
d3
.
scalePoint
(
)
.
domain
(
[
'A'
,
'B'
,
'C'
,
'D'
]
)
.
range
(
[
0
,
400
]
)
;
// Ordinal scale (for colours)
const
colourScale
=
d3
.
scaleOrdinal
(
d3
.
schemeCategory10
)
;
Sequential scales
// Sequential colour scale
const
colourScale
=
d3
.
scaleSequential
(
d3
.
interpolateBlues
)
.
domain
(
[
0
,
100
]
)
;
// Diverging colour scale
const
divScale
=
d3
.
scaleDiverging
(
d3
.
interpolateRdBu
)
.
domain
(
[
-
10
,
0
,
10
]
)
;
Best practices
Data preparation
Always validate and prepare data before visualisation:
// Filter invalid values
const
cleanData
=
data
.
filter
(
d
=>
d
.
value
!=
null
&&
!
isNaN
(
d
.
value
)
)
;
// Sort data if order matters
const
sortedData
=
[
...
data
]
.
sort
(
(
a
,
b
)
=>
b
.
value
-
a
.
value
)
;
// Parse dates
const
parsedData
=
data
.
map
(
d
=>
(
{
...
d
,
date
:
d3
.
timeParse
(
"%Y-%m-%d"
)
(
d
.
date
)
}
)
)
;
Performance optimisation
For large datasets (>1000 elements):
// Use canvas instead of SVG for many elements
// Use quadtree for collision detection
// Simplify paths with d3.line().curve(d3.curveStep)
// Implement virtual scrolling for large lists
// Use requestAnimationFrame for custom animations
Accessibility
Make visualisations accessible:
// Add ARIA labels
svg
.
attr
(
"role"
,
"img"
)
.
attr
(
"aria-label"
,
"Bar chart showing quarterly revenue"
)
;
// Add title and description
svg
.
append
(
"title"
)
.
text
(
"Quarterly Revenue 2024"
)
;
svg
.
append
(
"desc"
)
.
text
(
"Bar chart showing revenue growth across four quarters"
)
;
// Ensure sufficient colour contrast
// Provide keyboard navigation for interactive elements
// Include data table alternative
Styling
Use consistent, professional styling:
// Define colour palettes upfront
const
colours
=
{
primary
:
'#4A90E2'
,
secondary
:
'#7B68EE'
,
background
:
'#F5F7FA'
,
text
:
'#333333'
,
gridLines
:
'#E0E0E0'
}
;
// Apply consistent typography
svg
.
selectAll
(
"text"
)
.
style
(
"font-family"
,
"Inter, sans-serif"
)
.
style
(
"font-size"
,
"12px"
)
;
// Use subtle grid lines
g
.
selectAll
(
".tick line"
)
.
attr
(
"stroke"
,
colours
.
gridLines
)
.
attr
(
"stroke-dasharray"
,
"2,2"
)
;
Common issues and solutions
Issue
Axes not appearing
Ensure scales have valid domains (check for NaN values)
Verify axis is appended to correct group
Check transform translations are correct
Issue
Transitions not working
Call
.transition()
before attribute changes
Ensure elements have unique keys for proper data binding
Check that useEffect dependencies include all changing data
Issue
Responsive sizing not working
Use ResizeObserver or window resize listener
Update dimensions in state to trigger re-render
Ensure SVG has width/height attributes or viewBox
Issue
Performance problems Limit number of DOM elements (consider canvas for >1000 items) Debounce resize handlers Use .join() instead of separate enter/update/exit selections Avoid unnecessary re-renders by checking dependencies Resources references/ Contains detailed reference materials: d3-patterns.md - Comprehensive collection of visualisation patterns and code examples scale-reference.md - Complete guide to d3 scales with examples colour-schemes.md - D3 colour schemes and palette recommendations assets/ Contains boilerplate templates: chart-template.js - Starter template for basic chart interactive-template.js - Template with tooltips, zoom, and interactions sample-data.json - Example datasets for testing These templates work with vanilla JavaScript, React, Vue, Svelte, or any other JavaScript environment. Adapt them as needed for your specific framework. To use these resources, read the relevant files when detailed guidance is needed for specific visualisation types or patterns.
返回排行榜