基于Chart.js实现调查结果折线图可视化的技术咨询
Got it, let's break down how to build those three line charts with Chart.js for your team lead—each tied to a questionId, showing dates, team members, and their scores. Here's a practical, step-by-step approach tailored to your data structure:
Step 1: Restructure Raw Data for Chart.js
First off, the raw data from getHistoricalData() is nested, so we need to reshape it into a format Chart.js understands. Each chart (per question) needs:
- X-axis: Unique dates sorted chronologically
- Y-axis: Score values (I’m assuming 1-5 based on your sample data)
- Datasets: One line per team member, mapping their score to each date
Here's a helper function to transform the data:
function transformData(rawData) { // Create a map to group data by questionId const questionDataMap = {}; rawData.forEach(entry => { const date = new Date(entry.date).toLocaleDateString(); // Format date for readability entry.results.forEach(member => { member.questions.forEach(question => { const { questionId, value } = question; const memberId = member.teamMemberId; // Initialize question entry if it doesn't exist if (!questionDataMap[questionId]) { questionDataMap[questionId] = { dates: new Set(), members: {} }; } // Add date to the question's date set questionDataMap[questionId].dates.add(date); // Initialize member's score array if needed if (!questionDataMap[questionId].members[memberId]) { questionDataMap[questionId].members[memberId] = []; } // Store the score with its corresponding date questionDataMap[questionId].members[memberId].push({ date, value }); }); }); }); // Convert sets to sorted arrays and structure final data Object.keys(questionDataMap).forEach(questionId => { const data = questionDataMap[questionId]; // Sort dates chronologically data.sortedDates = Array.from(data.dates).sort((a, b) => new Date(a) - new Date(b)); // Build datasets for each member, filling in missing dates with null (so lines don't break) data.datasets = Object.keys(data.members).map(memberId => { const memberScores = data.members[memberId]; const dataPoints = data.sortedDates.map(date => { const scoreEntry = memberScores.find(s => s.date === date); return scoreEntry ? scoreEntry.value : null; }); return { label: memberId, data: dataPoints, borderColor: getRandomColor(), // Helper to generate unique colors fill: false, tension: 0.1 }; }); }); return questionDataMap; } // Helper to generate random distinct colors for each team member function getRandomColor() { const letters = '0123456789ABCDEF'; let color = '#'; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; }
Step 2: Set Up HTML Canvas Elements
You'll need one canvas per question to render each chart. Add these to your page:
<div class="chart-container"> <h3>Question 1: [Replace with actual question text]</h3> <canvas id="chart-1"></canvas> </div> <div class="chart-container"> <h3>Question 2: [Replace with actual question text]</h3> <canvas id="chart-2"></canvas> </div> <div class="chart-container"> <h3>Question 3: [Replace with actual question text]</h3> <canvas id="chart-3"></canvas> </div> <!-- Add Chart.js CDN --> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
Step 3: Initialize Charts with Processed Data
Now fetch your data, transform it, and render each chart:
// Fetch historical data (replace with your actual API call if needed) const rawHistoricalData = getHistoricalData(); const processedData = transformData(rawHistoricalData); // Loop through each questionId and render the chart Object.keys(processedData).forEach(questionId => { const chartConfig = { type: 'line', data: { labels: processedData[questionId].sortedDates, datasets: processedData[questionId].datasets }, options: { responsive: true, scales: { y: { beginAtZero: false, min: 1, // Assuming scores start at 1 max: 5, // Assuming max score is 5 title: { display: true, text: 'Score' } }, x: { title: { display: true, text: 'Date' } } }, plugins: { legend: { position: 'top', title: { display: true, text: 'Team Members' } }, tooltip: { mode: 'index', intersect: false, callbacks: { label: function(context) { return `${context.dataset.label}: ${context.raw}`; } } } } } }; // Initialize the chart new Chart(document.getElementById(`chart-${questionId}`), chartConfig); });
Key Notes for Your Team Lead Audience
- Readability: The charts show each team member's trend over time, making it easy to spot improvements or drops in scores at a glance.
- Missing Data: If a member didn’t submit a score on a date, we use
nullto keep the line intact without filling in false values. - Customization: You can tweak colors, labels, or scale ranges to match your team’s branding or specific score ranges.
内容的提问来源于stack exchange,提问作者krmnow
相关产品推荐
相关产品推荐

