You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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 null to 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:26:44