export function renderStepsVisualization() { fetch("../static/js/final_combined_with_all_data.json") // Chemin à adapter si nécessaire .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 svgContainer = d3 .select("#steps-visualization") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom + 50); // +50 pour la légende // Ajout du titre svgContainer .append("text") .attr("x", (width + margin.left + margin.right) / 2.5) // Centré horizontalement .attr("y", 20) // Positionné en haut .attr("text-anchor", "middle") .style("font-size", "18px") .style("font-weight", "bold") .text("Comparaison des pas des utilisateurs"); const svg = svgContainer .append("g") .attr("transform", `translate(${margin.left},${margin.top})`); const years = [2022, 2023, 2024]; const stepsPrevYearBtn = document.getElementById("stepsPrevYear"); const stepsNextYearBtn = document.getElementById("stepsNextYear"); const stepsCurrentYearDisplay = document.getElementById("stepsCurrentYear"); stepsPrevYearBtn.addEventListener("click", () => { const currentYearIndex = years.indexOf( parseInt(stepsCurrentYearDisplay.textContent) ); if (currentYearIndex > 0) { const newYear = years[currentYearIndex - 1]; stepsCurrentYearDisplay.textContent = newYear; updateVisualization(newYear); updateAnalysis("steps", newYear); stepsNextYearBtn.disabled = false; if (currentYearIndex - 1 === 0) { stepsPrevYearBtn.disabled = true; } } }); stepsNextYearBtn.addEventListener("click", () => { const currentYearIndex = years.indexOf( parseInt(stepsCurrentYearDisplay.textContent) ); if (currentYearIndex < years.length - 1) { const newYear = years[currentYearIndex + 1]; stepsCurrentYearDisplay.textContent = newYear; updateVisualization(newYear); updateAnalysis("steps", newYear); stepsPrevYearBtn.disabled = false; if (currentYearIndex + 1 === years.length - 1) { stepsNextYearBtn.disabled = true; } } }); stepsPrevYearBtn.disabled = years.indexOf(parseInt(stepsCurrentYearDisplay.textContent)) === 0; stepsNextYearBtn.disabled = years.indexOf(parseInt(stepsCurrentYearDisplay.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[`Steps_${member}`] = d3.mean( records, (d) => d[`Steps_${member}`] || 0 ); }); return aggregated; }); svg.selectAll("*").remove(); 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[`Steps_${member}`])) ), ]) .nice() .range([height, 0]); const colorMap = { Maya: "#0f7e06", Corentin: "#1d38e3", Anis: "#d6bff4", Amira: "#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("g").call(d3.axisLeft(yScale)); svg .append("text") .attr("x", width / 2) .attr("y", height + 70) .attr("text-anchor", "middle") .style("font-size", "14px") .text("Mois"); svg .append("text") .attr("transform", "rotate(-90)") .attr("x", -height / 2) .attr("y", -50) .attr("text-anchor", "middle") .style("font-size", "14px") .text("Nombre de pas"); members.forEach((member) => { const lineData = aggregatedData.map((d) => { let steps = d[`Steps_${member}`] === -1.0 ? 0 : d[`Steps_${member}`]; return { month: d.month, steps }; }); const line = d3 .line() .x((d) => xScale(d.month) + xScale.bandwidth() / 2) .y((d) => yScale(d.steps)) .defined((d) => d.steps !== 0); svg .append("path") .data([lineData]) .attr("class", `line-${member}`) .attr("d", line) .attr("fill", "none") .attr("stroke", colorMap[member]) .attr("stroke-width", 2); }); const legend = svg .append("g") .attr("transform", `translate(${width / 20}, ${height + 80})`); members.forEach((member, i) => { const legendGroup = legend .append("g") .attr("transform", `translate(${i * 150}, 0)`); legendGroup .append("rect") .attr("width", 15) .attr("height", 15) .attr("fill", colorMap[member]); legendGroup .append("text") .attr("x", 20) .attr("y", 12) .style("font-size", "12px") .text(member); }); } }); }