Skip to content
Snippets Groups Projects
calorieVisual.js 7 KiB
Newer Older
=AZIZI Anis's avatar
=AZIZI Anis committed
export function renderCaloriesVisualization() {
    fetch("../static/js/final_combined_with_all_data.json")
      .then((response) => response.json())
      .then((data) => {
        const parseDate = d3.timeParse("%Y-%m-%d");
        const formatYear = d3.timeFormat("%Y");
        const formatMonth = d3.timeFormat("%Y-%m");
        const members = ["Corentin", "Maya", "Anis", "Amira"];
  
        data.forEach((d) => (d.date = parseDate(d.date)));
  
        const margin = { top: 50, right: 230, bottom: 150, left: 70 };
        const width = 800 - margin.left - margin.right;
        const height = 500 - margin.top - margin.bottom;
  
        const svg = d3
          .select("#calories-visualization")
          .append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
          .append("g")
          .attr("transform", `translate(${margin.left},${margin.top})`);
  
        const years = [2022, 2023, 2024];
        const prevYearBtn = document.getElementById("caloriesPrevYear");
        const nextYearBtn = document.getElementById("caloriesNextYear");
        const currentYearDisplay = document.getElementById("caloriesCurrentYear");
  
        // Gestion des événements des boutons
        prevYearBtn.addEventListener("click", () => {
          const currentYearIndex = years.indexOf(
            parseInt(currentYearDisplay.textContent)
          );
          if (currentYearIndex > 0) {
            const newYear = years[currentYearIndex - 1];
            currentYearDisplay.textContent = newYear;
            updateVisualization(newYear);
            updateAnalysis("calories", newYear);
            // Activer/désactiver les boutons
            nextYearBtn.disabled = false;
            if (currentYearIndex - 1 === 0) {
              prevYearBtn.disabled = true;
            }
          }
        });
  
        nextYearBtn.addEventListener("click", () => {
          const currentYearIndex = years.indexOf(
            parseInt(currentYearDisplay.textContent)
          );
          if (currentYearIndex < years.length - 1) {
            const newYear = years[currentYearIndex + 1];
            currentYearDisplay.textContent = newYear;
            updateVisualization(newYear);
            updateAnalysis("calories", newYear);
  
            // Activer/désactiver les boutons
            prevYearBtn.disabled = false;
            if (currentYearIndex + 1 === years.length - 1) {
              nextYearBtn.disabled = true;
            }
          }
        });
  
        // Initialisation des boutons
        prevYearBtn.disabled =
          years.indexOf(parseInt(currentYearDisplay.textContent)) === 0;
        nextYearBtn.disabled =
          years.indexOf(parseInt(currentYearDisplay.textContent)) ===
          years.length - 1;
  
        updateVisualization(2024);
  
        function updateVisualization(selectedYear) {
          const filteredData = data.filter(
            (d) => formatYear(d.date) === selectedYear.toString()
          );
  
          if (filteredData.length === 0) {
            console.log(`Aucune donnée pour l'année ${selectedYear}`);
            return;
          }
  
          const groupedData = d3.groups(filteredData, (d) => formatMonth(d.date));
  
          const aggregatedData = groupedData.map(([month, records]) => {
            const aggregated = { month };
            members.forEach((member) => {
              aggregated[`Calories_${member}`] = d3.mean(
                records,
                (d) => d[`Calories_${member}`] || 0
              );
            });
            return aggregated;
          });
  
          svg.selectAll("*").remove();
  
          svg
            .append("text")
            .attr("x", width / 2)
            .attr("y", margin.top - 60)
            .attr("text-anchor", "middle")
            .style("font-size", "16px")
            .style("font-weight", "bold")
            .text("Analyse des calories brûlées par mois");
  
          const xScale = d3
            .scaleBand()
            .domain(aggregatedData.map((d) => d.month))
            .range([0, width])
            .padding(0.2);
  
          const yScale = d3
            .scaleLinear()
            .domain([
              0,
              d3.max(aggregatedData, (d) =>
                Math.max(...members.map((member) => d[`Calories_${member}`]))
              ),
            ])
            .nice()
            .range([height, 0]);
  
          const colorScale = d3
            .scaleOrdinal()
            .domain(members)
            .range(["#1d38e3", "#0f7e06", "#d6bff4", "#7e09bd"]);
  
          svg
            .append("g")
            .attr("transform", `translate(0, ${height})`)
            .call(d3.axisBottom(xScale))
            .selectAll("text")
            .attr("transform", "rotate(-45)")
            .style("text-anchor", "end");
  
          svg
            .append("text")
            .attr("x", width / 2)
            .attr("y", height + 70)
            .attr("text-anchor", "middle")
            .style("font-size", "14px")
            .text("Mois");
  
          svg.append("g").call(d3.axisLeft(yScale));
  
          svg
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("x", -height / 2)
            .attr("y", -50)
            .attr("text-anchor", "middle")
            .style("font-size", "14px")
            .text("Calories brûlées");
          // Ajout de la légende
          const legend = svg
            .append("g")
            .attr(
              "transform",
              `translate(${width / 2 - (members.length * 120) / 2}, ${
                height + 100
              })`
            ); // Positionnement
  
          members.forEach((member, i) => {
            const legendGroup = legend
              .append("g")
              .attr("transform", `translate(${i * 120}, 0)`); // Espacement horizontal
  
            // Rectangle coloré
            legendGroup
              .append("rect")
              .attr("width", 15)
              .attr("height", 15)
              .attr("fill", colorScale(member))
              .style("opacity", 0.8);
  
            // Texte descriptif
            legendGroup
              .append("text")
              .attr("x", 20) // Position par rapport au rectangle
              .attr("y", 12) // Alignement vertical
              .style("font-size", "12px")
              .text(member);
          });
  
          members.forEach((member) => {
            const lineData = aggregatedData.map((d) => ({
              month: d.month,
              calories: d[`Calories_${member}`] || 0,
            }));
  
            const line = d3.line()
              .x((d) => xScale(d.month) + xScale.bandwidth() / 2)
              .y((d) => yScale(d.calories));
  
  
            svg
              .append("path")
              .data([lineData])
              .attr("fill", "none")
              .attr("stroke", colorScale(member)) // Couleur de la ligne
              .attr("stroke-width", 2) // Épaisseur de la ligne
              .attr("d", line);
          });
        }
      });
  }