Data Visualization

Démos D3.js interactives

Trois visualisations codées from scratch avec D3.js v7 — données fictives réalistes, animations soignées, responsive.

01 / 03

Dashboard Analytics

Barres animées + courbe de conversion + filtres temporels + tooltip hover

D3.js · scaleBand · scaleLinear · area
Chargement…
// Données fictives réalistes
const data: MonthData[] = [
  { month: 'Oct 25', visits: 2100, conversions: 78 },
  { month: 'Nov 25', visits: 2340, conversions: 91 },
  // ...12 mois de données
];

// Bar chart D3 avec animation entrée depuis le bas
const x = d3.scaleBand().domain(data.map(d => d.month)).padding(0.35);
const y = d3.scaleLinear().domain([0, d3.max(data, d => d.visits)! * 1.1]);

g.selectAll('.bar').data(data).enter().append('rect')
  .attr('y', innerH).attr('height', 0)       // part du bas
  .transition().duration(600)
  .attr('y', d => y(d.visits))
  .attr('height', d => innerH - y(d.visits));

// Line chart — effet dessin stroke-dashoffset
const len = path.node().getTotalLength();
path.attr('stroke-dasharray', len).attr('stroke-dashoffset', len)
  .transition().duration(900).attr('stroke-dashoffset', 0);

// Tooltip : ref DOM direct (pas de useState → pas de re-render → pas de boucle)
const tip = tooltipRef.current!;
bar.on('mouseenter', (event, d) => {
  tip.innerHTML = `<strong>${d.month}</strong><span>${d.visits} visites</span>`;
  tip.style.opacity = '1';
}).on('mouseleave', () => { tip.style.opacity = '0'; });
02 / 03

Visualisation réseau

Réseau de compétences tech — drag & drop, zoom, force simulation, tooltip

D3.js · forceSimulation · drag · zoom
Chargement…
// Force simulation — réseau de 17 nœuds tech
const sim = d3.forceSimulation<Node>(nodes)
  .force('link',    d3.forceLink<Node, Link>(links).id(d => d.id)
                       .distance(d => 80 + (1 - d.strength) * 60))
  .force('charge',  d3.forceManyBody().strength(-280))
  .force('center',  d3.forceCenter(W / 2, H / 2))
  .force('collide', d3.forceCollide<Node>().radius(d => RADIUS[d.level] + 10));

// Drag behavior
const drag = d3.drag<SVGGElement, Node>()
  .on('start', (e, d) => { d.fx = d.x; d.fy = d.y; sim.alphaTarget(0.3).restart(); })
  .on('drag',  (e, d) => { d.fx = e.x; d.fy = e.y; })
  .on('end',   (e, d) => { d.fx = null; d.fy = null; sim.alphaTarget(0); });

// Zoom behavior
const zoom = d3.zoom<SVGSVGElement, unknown>()
  .scaleExtent([0.4, 3])
  .on('zoom', e => zoomG.attr('transform', e.transform));

// Tick loop : repositionner liens et nœuds à chaque frame
sim.on('tick', () => {
  linkEl.attr('x1', d => d.source.x!).attr('y1', d => d.source.y!)
        .attr('x2', d => d.target.x!).attr('y2', d => d.target.y!);
  nodeG.attr('transform', d => `translate(${d.x},${d.y})`);
});
03 / 03

Carte choroplèthe France

Missions freelance tech par région — projection conique, tooltip, animation décalée

D3.js · geoPath · scaleSequential
Chargement…
// Projection conique conforme centrée sur la France
const projection = d3.geoConicConformal()
  .center([2.454071, 46.279229])
  .parallels([44, 49])
  .scale(W * 4.2)
  .translate([W / 2, H / 2]);

const path = d3.geoPath().projection(projection);

// Échelle couleur séquentielle violet → opaque
const colorScale = d3.scaleSequential()
  .domain([vMin, vMax])
  .interpolator(d3.interpolate(
    'rgba(139,92,246,0.08)',
    'rgba(139,92,246,0.95)'
  ));

// Fetch GeoJSON + rendu
d3.json(GEOJSON_URL).then(geojson => {
  svg.selectAll('path')
    .data(geojson.features)
    .enter().append('path')
    .attr('d', path)
    .attr('fill', f => colorScale(REGION_DATA[f.properties.nom]))
    // Animation décalée : chaque région apparaît à +40ms
    .attr('opacity', 0)
    .transition().duration(500).delay((_, i) => i * 40)
    .attr('opacity', 1);
});