pie_chart.tsx 6,82 ko
Newer Older
Thibault Fouchet's avatar
Thibault Fouchet a validé
import React, { useState, useEffect, useRef } from "react";
Thibault Fouchet's avatar
Thibault Fouchet a validé
import * as d3 from "d3";

Thibault Fouchet's avatar
Thibault Fouchet a validé
interface ChartData {
  departement: string;
  value: number;
}

const Pie_Chart = () => {
  const originalData: ChartData[] = [
Thibault Fouchet's avatar
Thibault Fouchet a validé
    { departement: "01", value: 21050 },
    { departement: "02", value: 45954 },
    { departement: "03", value: 21584 },
    { departement: "04", value: 53486 },
    { departement: "05", value: 87965 },
    { departement: "06", value: 34864 },
    { departement: "07", value: 48453 },
    { departement: "08", value: 87652 },
    { departement: "09", value: 12346 },
    { departement: "10", value: 78654 },
    { departement: "11", value: 48453 },
    { departement: "12", value: 78654 },
    { departement: "13", value: 28203 },
    { departement: "14", value: 21050 },
    { departement: "15", value: 45211 },
    { departement: "16", value: 87945 },
    { departement: "17", value: 47853 },
    { departement: "18", value: 75213 },
    { departement: "19", value: 21050 },
    { departement: "20", value: 78542 },
    { departement: "21", value: 21050 },
    { departement: "22", value: 78432 },
    { departement: "23", value: 21050 },
    { departement: "24", value: 21050 },
    { departement: "25", value: 27420 },
    { departement: "26", value: 27420 },
    { departement: "27", value: 27420 },
    { departement: "28", value: 27420 },
    { departement: "29", value: 75423 },
    { departement: "30", value: 21050 },
    { departement: "31", value: 78543 },
    { departement: "32", value: 21050 },
    { departement: "33", value: 100 },
    { departement: "34", value: 21050 },
    { departement: "35", value: 21050 },
    { departement: "36", value: 500 },
    { departement: "37", value: 24128 },
    { departement: "38", value: 24128 },
    { departement: "39", value: 2400 },
    { departement: "40", value: 24128 },
    { departement: "41", value: 7856 },
    { departement: "42", value: 2014 },
    { departement: "43", value: 3500 },
    { departement: "44", value: 24128 },
    { departement: "45", value: 2035 },
    { departement: "46", value: 150 },
    { departement: "47", value: 980 },
    { departement: "48", value: 748 },
    { departement: "49", value: 38806 },
    { departement: "50", value: 38806 },
    { departement: "51", value: 78543 },
    { departement: "52", value: 12999 },
    { departement: "53", value: 7865 },
    { departement: "54", value: 12999 },
    { departement: "55", value: 7854 },
    { departement: "56", value: 3698 },
    { departement: "57", value: 7412 },
    { departement: "58", value: 1236 },
    { departement: "59", value: 4789 },
    { departement: "60", value: 8963 },
    { departement: "61", value: 6321 },
    { departement: "62", value: 2145 },
    { departement: "63", value: 3256 },
    { departement: "64", value: 6589 },
    { departement: "65", value: 8965 },
    { departement: "66", value: 4587 },
    { departement: "67", value: 5697 },
    { departement: "68", value: 5413 },
    { departement: "69", value: 9713 },
    { departement: "70", value: 5418 },
    { departement: "71", value: 12999 },
    { departement: "72", value: 8642 },
    { departement: "73", value: 12999 },
    { departement: "74", value: 7319 },
    { departement: "75", value: 8246 },
    { departement: "76", value: 7853 },
    { departement: "77", value: 4687 },
    { departement: "78", value: 2480 },
    { departement: "79", value: 4283 },
    { departement: "80", value: 7352 },
    { departement: "81", value: 2052 },
    { departement: "82", value: 4052 },
    { departement: "83", value: 3058 },
    { departement: "84", value: 5602 },
    { departement: "85", value: 4206 },
    { departement: "86", value: 7069 },
    { departement: "87", value: 7605 },
    { departement: "88", value: 100 },
    { departement: "89", value: 200 },
    { departement: "90", value: 300 },
    { departement: "91", value: 400 },
    { departement: "92", value: 500 },
    { departement: "93", value: 600 },
    { departement: "94", value: 700 },
    { departement: "95", value: 800 },
    { departement: "971", value: 900 },
    { departement: "972", value: 1000 },
    { departement: "973", value: 1000 },
    { departement: "974", value: 1200 },
    { departement: "975", value: 1300 },
  ];

Thibault Fouchet's avatar
Thibault Fouchet a validé
  const chartRef = useRef<SVGSVGElement | null>(null);
  const [numResults, setNumResults] = useState(10);
Thibault Fouchet's avatar
Thibault Fouchet a validé

  useEffect(() => {
    const svg = d3.select(chartRef.current);
    svg.selectAll("*").remove();

Thibault Fouchet's avatar
Thibault Fouchet a validé
    const margin = { top: 100, right: 10, bottom: 10, left: 10 };
Thibault Fouchet's avatar
Thibault Fouchet a validé
    const width = 400 - margin.left - margin.right;
    const height = 400 - margin.top - margin.bottom;
    const radius = Math.min(width, height) / 2;

Thibault Fouchet's avatar
Thibault Fouchet a validé
    const sortedData = [...originalData].sort((a, b) => b.value - a.value);

    const displayedData = sortedData.slice(0, numResults);
Thibault Fouchet's avatar
Thibault Fouchet a validé

Thibault Fouchet's avatar
Thibault Fouchet a validé
    const totalSales = d3.sum(sortedData, (d) => d.value);

    const otherData = {
      departement: "Autres",
      value: totalSales - d3.sum(displayedData, (d) => d.value),
    };
Thibault Fouchet's avatar
Thibault Fouchet a validé

    const pie = d3.pie()
      .value((d) => d.value);

    const arc = d3.arc()
      .outerRadius(radius)
Thibault Fouchet's avatar
Thibault Fouchet a validé
      .innerRadius(radius / 2);
Thibault Fouchet's avatar
Thibault Fouchet a validé

Thibault Fouchet's avatar
Thibault Fouchet a validé
    const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
    const g = svg.append("g")
      .attr("transform", `translate(${width / 2},${height / 2})`);
Thibault Fouchet's avatar
Thibault Fouchet a validé

Thibault Fouchet's avatar
Thibault Fouchet a validé
    const arcs = g.selectAll("arc")
      .data(pie([...displayedData, otherData]))
Thibault Fouchet's avatar
Thibault Fouchet a validé
      .enter().append("g")
Thibault Fouchet's avatar
Thibault Fouchet a validé
      .attr("class", "arc");

    arcs.append("path")
      .attr("d", arc)
      .attr("fill", (d) => (d.data.departement === "Autres" ? "gray" : colorScale(d.data.departement)));


    const outerArc = d3.arc()
      .innerRadius(radius * 0.9)
      .outerRadius(radius * 0.9);

    arcs.append("polyline")
      .attr("stroke", "black")
      .attr("stroke-width", 1)
      .attr("fill", "none")
      .attr("points", (d) => {
        const posA = arc.centroid(d);
        const posB = outerArc.centroid(d);
        const posC = outerArc.centroid(d);
        const midangle = d.startAngle + (d.endAngle - d.startAngle) / 2;
        posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1);
        return [posA, posB, posC];
      });

    arcs.append("text")
      .attr("transform", (d) => `translate(${outerArc.centroid(d)})`)
Thibault Fouchet's avatar
Thibault Fouchet a validé
      .attr("dy", ".35em")
Thibault Fouchet's avatar
Thibault Fouchet a validé
      .style("text-anchor", "middle")
      .text((d) => {
        const percentage = (d.data.value / totalSales) * 100;
        return `${d.data.departement}: ${percentage.toFixed(2)}%`;
      });
Thibault Fouchet's avatar
Thibault Fouchet a validé

Thibault Fouchet's avatar
Thibault Fouchet a validé
  }, [numResults]);
Thibault Fouchet's avatar
Thibault Fouchet a validé

  return (
Thibault Fouchet's avatar
Thibault Fouchet a validé
    <div>
      <label>
        Nombre de résultats à afficher :
        <input
          type="number"
          value={numResults}
          onChange={(e) => setNumResults(parseInt(e.target.value, 10))}
        />
      </label>
      <div style={{textAlign: "center"}}>
        <svg id="donut-chart" width={400} height={400} ref={chartRef}
             style={{display: "block", margin: "0 auto"}}></svg>
      </div>

    </div>
Thibault Fouchet's avatar
Thibault Fouchet a validé

export default Pie_Chart;