Skip to main content 首页 创作者 johnnuwan eva_core d3-js
d3-js D3.js (Data-Driven Documents) : bibliothèque JavaScript de visualisation de données par manipulation directe du DOM — SVG, Canvas, transitions, force layout, géo, hiérarchies, échelles, axes, brush, zoom, drag.
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/JohnNuwan/EVA_CORE --skill d3-js命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... name d3-js description D3.js (Data-Driven Documents) : bibliothèque JavaScript de visualisation de données par manipulation directe du DOM — SVG, Canvas, transitions, force layout, géo, hiérarchies, échelles, axes, brush, zoom, drag. version 1.0.0 author EVA license Privée EVA platforms ["linux","macos","windows"] metadata {"EVA":{"tags":["d3","d3js","data-visualization","svg","javascript","dataviz","interactive-viz","web"],"homepage":"https://d3js.org/","related_skills":["observable","chart-js","plotly","dashboard-design"]}} prerequisites {"commands":["node","npm"],"npm_packages":["d3"]}
Compétence D3.js — Visualisation de Données par Manipulation du DOM
Vue d'ensemble
D3.js (Data-Driven Documents) est la bibliothèque de référence pour les visualisations de données sur le web. Contrairement aux librairies "boîte noire" (Chart.js, Highcharts), D3 opère directement sur le DOM : l'utilisateur manipule des éléments SVG/Canvas en liant des données, ce qui offre un contrôle total sur chaque pixel de la visualisation.
Philosophie D3 : "Penser en données, dessiner en DOM."
Points forts : flexibilité totale, SVG/Canvas/WebGL, animations fluides, écosystème riche (geo, hiérarchies, réseaux, layouts).
Points faibles : courbe d'apprentissage raide, pas de graphiques prêts à l'emploi, verbose pour des charts simples.
Quand l'utiliser
Activez cette compétence lorsque l'utilisateur :
Veut créer une visualisation de données interactive pour le web.
A besoin d'un contrôle pixel-parfait sur l'apparence d'un graphique.
Souhaite des animations de transition entre états de données.
Travaille sur des visualisations géospatiales (carte choroplèthe, projections).
Veut des graphiques en réseau, arbres, treemaps, sunbursts.
A besoin d'interactions avancées : zoom, brush, drag, tooltips personnalisés.
Prérequis
npm install d3
1. Sélections et Liaison de Données (Data Join)
1.1 Le Pattern d'Entrée-Sortie (Enter/Update/Exit)
const data = [10 , 25 , 50 , 75 , 100 ];
const circles = d3.select ("svg" )
.selectAll ("circle" )
.data (data);
circles.enter ()
.append ("circle" )
.attr ("r" , d)
. ( , i * + )
. ( , )
. ( , );
circles. ( , d);
circles. (). ();
d =>
attr
"cx"
(d, i ) =>
100
50
attr
"cy"
100
attr
"fill"
"steelblue"
attr
"r"
d =>
exit
remove
1.2 La Méthode Générale .join() (D3 v7+) svg.selectAll ("circle" )
.data (data)
.join ("circle" )
.attr ("r" , d => d)
.attr ("cx" , (d, i ) => i * 100 + 50 )
.attr ("cy" , 100 )
.attr ("fill" , "steelblue" );
2. Échelles (Scales) Les échelles transforment le domaine des données en plage visuelle.
const xScale = d3.scaleLinear ()
.domain ([0 , 100 ])
.range ([0 , 800 ]);
const timeScale = d3.scaleTime ()
.domain ([new Date ("2024-01-01" ), new Date ("2024-12-31" )])
.range ([0 , 800 ]);
const colorScale = d3.scaleOrdinal ()
.domain (["A" , "B" , "C" ])
.range (d3.schemeCategory10 );
const tempScale = d3.scaleSequential ()
.domain ([20 , 100 ])
.interpolator (d3.interpolateReds );
const logScale = d3.scaleLog ()
.domain ([1 , 1000 ])
.range ([0 , 800 ]);
const thresholdScale = d3.scaleThreshold ()
.domain ([50 , 75 , 90 ])
.range (["#e74c3c" , "#f39c12" , "#2ecc71" , "#27ae60" ]);
3. Axes (Axes) const svg = d3.select ("svg" );
const margin = { top : 20 , right : 30 , bottom : 40 , left : 50 };
const width = 800 - margin.left - margin.right ;
const height = 400 - margin.top - margin.bottom ;
const g = svg.append ("g" )
.attr ("transform" , `translate(${margin.left} ,${margin.top} )` );
const xScale = d3.scaleLinear ().domain ([0 , 100 ]).range ([0 , width]);
const yScale = d3.scaleLinear ().domain ([0 , 100 ]).range ([height, 0 ]);
g.append ("g" )
.attr ("transform" , `translate(0,${height} )` )
.call (d3.axisBottom (xScale))
.selectAll ("text" )
.attr ("transform" , "rotate(-45)" )
.style ("text-anchor" , "end" );
g.append ("g" )
.call (d3.axisLeft (yScale));
g.append ("g" )
.call (d3.axisLeft (yScale)
.ticks (10 )
.tickFormat (d => `${d} %` )
.tickSizeOuter (0 )
);
4. Graphiques Fondamentaux
4.1 Bar Chart const data = [
{ name : "A" , value : 30 },
{ name : "B" , value : 80 },
{ name : "C" , value : 45 },
{ name : "D" , value : 60 },
{ name : "E" , value : 20 },
];
const x = d3.scaleBand ()
.domain (data.map (d => d.name ))
.range ([0 , width])
.padding (0.1 );
const y = d3.scaleLinear ()
.domain ([0 , d3.max (data, d => d.value )])
.range ([height, 0 ]);
g.selectAll ("rect" )
.data (data)
.join ("rect" )
.attr ("x" , d => x (d.name ))
.attr ("y" , d => y (d.value ))
.attr ("width" , x.bandwidth ())
.attr ("height" , d => height - y (d.value ))
.attr ("fill" , "steelblue" );
4.2 Line Chart (Série Temporelle) const line = d3.line ()
.x (d => x (d.date ))
.y (d => y (d.value ))
.curve (d3.curveMonotoneX );
g.append ("path" )
.datum (data)
.attr ("fill" , "none" )
.attr ("stroke" , "steelblue" )
.attr ("stroke-width" , 2 )
.attr ("d" , line);
const area = d3.area ()
.x (d => x (d.date ))
.y0 (y (0 ))
.y1 (d => y (d.value ))
.curve (d3.curveMonotoneX );
g.append ("path" )
.datum (data)
.attr ("fill" , "steelblue" )
.attr ("fill-opacity" , 0.1 )
.attr ("d" , area);
4.3 Scatter Plot g.selectAll ("circle" )
.data (data)
.join ("circle" )
.attr ("cx" , d => x (d.x ))
.attr ("cy" , d => y (d.y ))
.attr ("r" , d => d.r || 5 )
.attr ("fill" , d => colorScale (d.category ))
.attr ("opacity" , 0.7 );
4.4 Pie / Donut Chart const pie = d3.pie ().value (d => d.value );
const arc = d3.arc ().innerRadius (0 ).outerRadius (200 );
const donutArc = d3.arc ().innerRadius (80 ).outerRadius (200 );
const arcs = g.selectAll ("path" )
.data (pie (data))
.join ("path" )
.attr ("d" , donutArc)
.attr ("fill" , d => colorScale (d.data .name ))
.attr ("stroke" , "white" )
.attr ("stroke-width" , 2 );
5. Animations et Transitions
g.selectAll ("rect" )
.data (newData)
.join ("rect" )
.transition ()
.duration (800 )
.delay ((d, i ) => i * 50 )
.ease (d3.easeElasticOut )
.attr ("height" , d => height - y (d.value ))
.attr ("y" , d => y (d.value ));
g.selectAll ("rect" )
.data (data)
.join ("rect" )
.attr ("y" , height)
.attr ("height" , 0 )
.transition ()
.duration (600 )
.delay ((d, i ) => i * 30 )
.ease (d3.easeBounceOut )
.attr ("y" , d => y (d.value ))
.attr ("height" , d => height - y (d.value ));
g.selectAll ("circle" )
.transition ()
.duration (1000 )
.attrTween ("cx" , d => {
const interpolate = d3.interpolate (0 , x (d.x ));
return t => interpolate (t);
});
6. Interactions
6.1 Tooltip const tooltip = d3.select ("body" )
.append ("div" )
.attr ("class" , "tooltip" )
.style ("position" , "absolute" )
.style ("background" , "rgba(0,0,0,0.8)" )
.style ("color" , "white" )
.style ("padding" , "8px 12px" )
.style ("border-radius" , "4px" )
.style ("font-size" , "14px" )
.style ("pointer-events" , "none" )
.style ("opacity" , 0 );
g.selectAll ("circle" )
.on ("mouseenter" , (event, d ) => {
tooltip.transition ().duration (200 ).style ("opacity" , 0.9 );
tooltip.html (`<strong>${d.name} </strong><br>Valeur : ${d.value} ` )
.style ("left" , `${event.pageX + 10 } px` )
.style ("top" , `${event.pageY - 28 } px` );
})
.on ("mouseleave" , () => {
tooltip.transition ().duration (500 ).style ("opacity" , 0 );
});
6.2 Zoom & Pan const zoom = d3.zoom ()
.scaleExtent ([0.5 , 10 ])
.translateExtent ([[0 , 0 ], [width, height]])
.on ("zoom" , (event ) => {
g.attr ("transform" , event.transform );
});
svg.call (zoom);
svg.call (zoom.transform , d3.zoomIdentity .translate (200 , 100 ).scale (2 ));
6.3 Brush (Sélection par Rectangle) 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 =>
x (d.x ) >= x0 && x (d.x ) <= x1 && y (d.y ) >= y0 && y (d.y ) <= y1
);
console .log ("Points sélectionnés :" , selected);
});
g.append ("g" ).call (brush);
6.4 Drag (Déplacement) const drag = d3.drag ()
.on ("start" , (event, d ) => {
d.fx = d.x ; d.fy = d.y ;
})
.on ("drag" , (event, d ) => {
d.fx = event.x ; d.fy = event.y ;
redraw ();
})
.on ("end" , (event, d ) => {
d.fx = null ; d.fy = null ;
});
g.selectAll ("circle" ).call (drag);
7. Layouts Avancés
7.1 Force Layout (Graphes / Réseaux) 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 ))
.force ("collision" , d3.forceCollide (30 ))
.on ("tick" , ticked);
function ticked ( ) {
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 );
}
7.2 Treemap const root = d3.hierarchy (data).sum (d => d.value );
d3.treemap ()
.size ([width, height])
.padding (2 )
.round (true )(root);
const cells = g.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 => colorScale (d.parent .data .name ));
7.3 Sunburst / Partition const root = d3.hierarchy (data).sum (d => d.value );
d3.partition ()
.size ([2 * Math .PI , radius])(root);
const arcs = g.selectAll ("path" )
.data (root.descendants ())
.join ("path" )
.attr ("d" , d3.arc ()
.startAngle (d => d.x0 )
.endAngle (d => d.x1 )
.innerRadius (d => d.y0 )
.outerRadius (d => d.y1 )
)
.attr ("fill" , d => colorScale (d.depth ));
7.4 Sankey (Diagramme de Flux) const sankey = d3.sankey ()
.nodeWidth (20 )
.nodePadding (10 )
.extent ([[0 , 0 ], [width, height]]);
const { nodes, links } = sankey ({
nodes : [...],
links : [...]
});
g.selectAll ("path" )
.data (links)
.join ("path" )
.attr ("d" , d3.sankeyLinkHorizontal ())
.attr ("fill" , "none" )
.attr ("stroke" , d => d.color )
.attr ("stroke-width" , d => d.width )
.attr ("opacity" , 0.4 );
8. Cartographie (Geo)
const projection = d3.geoMercator ()
.fitSize ([width, height], geojson);
const path = d3.geoPath ().projection (projection);
g.selectAll ("path" )
.data (topojson.feature (world, world.objects .countries ).features )
.join ("path" )
.attr ("d" , path)
.attr ("fill" , "#ddd" )
.attr ("stroke" , "#fff" )
.attr ("stroke-width" , 0.5 );
g.selectAll ("path" )
.data (geoData)
.join ("path" )
.attr ("d" , path)
.attr ("fill" , d => colorScale (d.properties .value ))
.attr ("stroke" , "#fff" );
const projections = {
equirectangular : d3.geoEquirectangular (),
albers : d3.geoAlbers (),
conicConformal : d3.geoConicConformal (),
orthographic : d3.geoOrthographic (),
stereographic : d3.geoStereographic (),
naturalEarth : d3.geoNaturalEarth1 (),
};
9. Modulaires (Modules D3 Individuels) D3 est modulaire : importez uniquement ce dont vous avez besoin.
import { select, selectAll } from "d3-selection" ;
import { scaleLinear, scaleOrdinal } from "d3-scale" ;
import { line, area } from "d3-shape" ;
import { axisBottom, axisLeft } from "d3-axis" ;
import { transition } from "d3-transition" ;
import { easeElasticOut } from "d3-ease" ;
import { geoMercator, geoPath } from "d3-geo" ;
import * as d3 from "d3" ;
Module Utilité d3-selectionSélection DOM, data join d3-scaleÉchelles (lin, log, time, ordinal, band) d3-shapeLignes, aires, arcs, symboles d3-axisAxes de graphique d3-transitionAnimations, transitions d3-easeFonctions d'easing d3-arrayStatistiques, tris, groupBy d3-formatFormatage de nombres d3-time-formatFormatage de dates d3-geoProjections cartographiques d3-forceSimulation de forces (graphes) d3-hierarchyTreemap, sunburst, dendrogram d3-sankeyDiagrammes de flux Sankey (module externe) d3-brushSélection rectangulaire d3-zoomZoom/Pan d3-dragGlisser-déposer d3-colorManipulation de couleurs d3-interpolateInterpolation de valeurs d3-timerBoucle d'animation requestAnimationFrame
10. Patterns de Performance
const canvas = document .getElementById ("canvas" );
const ctx = canvas.getContext ("2d" );
const render = ( ) => {
ctx.clearRect (0 , 0 , width, height);
data.forEach (d => {
ctx.beginPath ();
ctx.arc (xScale (d.x ), yScale (d.y ), 3 , 0 , Math .PI * 2 );
ctx.fillStyle = colorScale (d.category );
ctx.fill ();
});
};
svg.selectAll ("circle" )
.data (data, d => d.id )
.join ("circle" )
.attr ("cx" , d => x (d.x ));
const xScale = d3.scaleLinear ().domain (...).range (...);
selection.raise ();
selection.lower ();
Pièges Courants (Pitfalls)
Mutation accidentelle des données dans le data join.
Erreur : D3 stocke les données en place sur l'élément DOM via __data__. Modifier d.x dans un callback modifie l'objet original.
Correction : Faites une copie des données si vous devez les transformer : data.map(d => ({...d})).
Axes tronqués ou illisibles.
Erreur : Les étiquettes d'axes débordent du groupe SVG car le margin n'est pas assez large.
Correction : Toujours définir des margin explicites et traduire le groupe conteneur.
Transitions en conflit (torn tearing).
Erreur : Plusieurs transitions sur le même élément s'interrompent mutuellement.
Correction : Utilisez selection.interrupt() avant une nouvelle transition, ou gérez avec selection.transition().on("end", ...).
Force layout infini.
Erreur : La simulation de forces ne converge pas (nœuds qui s'éloignent à l'infini).
Correction : Équilibrer les forces : forceManyBody().strength(-300) + forceCenter() + forceCollide(). Ajuster alphaDecay.
Carte géo incomplète ou déformée.
Erreur : Le fichier TopoJSON/GeoJSON n'est pas correctement lié à la projection.
Correction : Vérifiez que topojson.feature() est bien appelé, et que la projection utilise .fitSize() ou .fitExtent().
Sélecteurs réutilisés sans vidage préalable.
Erreur : Appeler svg.selectAll("circle").data(nouveauxData) sur un SVG qui contient déjà des cercles — les anciens persistent si mal gérés.
Correction : Utiliser le pattern enter/update/exit complet ou .join().
Oubli de la fonction de clé dans le data join.
Erreur : D3 lie par index (pas par identité), ce qui cause des animations incorrectes lors de réorganisations.
Correction : Toujours fournir une fonction de clé : .data(data, d => d.id).
Ressources
Checklist