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

Chart.js+Django REST Framework下拉框切换图表数据报错求助

问题分析

你遇到的Uncaught TypeError: Cannot read property 'pop' of undefined错误,根源有两个:

  1. 下拉框的onchange事件调用change()时没有传递任何参数,导致函数里的data变量是undefined
  2. AJAX回调里的sales_rev是局部变量,下拉触发change函数时无法访问到这个数据

另外你当前的change函数只是简单操作数组元素,没有实现根据下拉选项过滤数据并更新图表的核心逻辑。下面是完整的解决方案:

解决方案

1. 全局存储API原始数据

首先把AJAX获取到的图表数据存到全局变量里,这样后续下拉切换时能随时访问:

// 全局变量,用于存储API返回的原始图表数据
let chartRawData = {};

const endpoint = 'api/chart/data';
$.ajax({
    type: "GET",
    url: endpoint,
    success: function(data){
        console.log('API数据返回:', data);
        // 将数据存入全局变量,同时简化二维数组结构(方便后续处理)
        chartRawData = {
            salesTime: data.sales_time_axis.map(item => item[0]),
            salesRev: data.sales_rev.map(item => item[0]),
            conversionLabels: data.conversion_label,
            conversionData: data.conversion_data,
            profitData: data.profit_data_per_project.map(item => item[0])
        };
        // 初始化图表
        createChart(chartRawData);
    },
    error: function(error_data){
        console.error('API请求失败:', error_data);
    }
});

2. 修改下拉框的触发事件

让下拉框触发时传递选中的月份值,这样change函数知道要过滤多久的数据:

<div class="card-body" id="card_body">
    <select class="text_select" id="chart-select" onchange="change(this.value)" name="select">
        <option value="All">All Time</option>
        <option value="3">Last 3 Months</option>
        <option value="6">Last 6 Months</option>
        <option value="12">Last Year</option>
        <option value="24">Last 2 Years</option>
    </select>
    <canvas id="myChart"></canvas>
</div>

3. 重写change函数实现数据过滤与图表更新

这个函数会根据选中的月份过滤数据,然后更新Chart.js图表:

function change(selectedMonths) {
    // 先检查全局数据是否已加载完成
    if (!chartRawData.salesTime) {
        console.warn('图表数据还未加载完成,请稍后重试!');
        return;
    }

    let filteredTime = [];
    let filteredRev = [];

    if (selectedMonths === 'All') {
        // 显示全部数据
        filteredTime = [...chartRawData.salesTime];
        filteredRev = [...chartRawData.salesRev];
    } else {
        // 计算时间截止点:当前日期往前推指定月份
        const cutoffDate = new Date();
        cutoffDate.setMonth(cutoffDate.getMonth() - parseInt(selectedMonths));

        // 遍历原始数据,筛选符合时间条件的记录
        for (let i = 0; i < chartRawData.salesTime.length; i++) {
            const projectDate = new Date(chartRawData.salesTime[i]);
            if (projectDate >= cutoffDate) {
                filteredTime.push(chartRawData.salesTime[i]);
                filteredRev.push(chartRawData.salesRev[i]);
            }
        }
    }

    // 更新图表
    if (window.myChart) {
        // 如果图表实例已存在,直接更新数据
        window.myChart.data.labels = filteredTime;
        window.myChart.data.datasets[0].data = filteredRev;
        window.myChart.update(); // 触发图表重绘
    } else {
        // 如果图表还未初始化,创建新的图表实例
        createChart({
            ...chartRawData,
            salesTime: filteredTime,
            salesRev: filteredRev
        });
    }
}

4. 完善createChart函数,保存图表实例

确保这个函数能接收过滤后的数据,并把图表实例存在全局,方便后续更新:

function createChart(data) {
    const ctx = document.getElementById('myChart').getContext('2d');
    // 把图表实例存到全局,方便后续更新
    window.myChart = new Chart(ctx, {
        type: 'line', // 根据你的需求修改图表类型(比如bar、pie等)
        data: {
            labels: data.salesTime,
            datasets: [{
                label: 'Project Sales Revenue',
                data: data.salesRev,
                borderColor: '#2196F3',
                backgroundColor: 'rgba(33, 150, 243, 0.1)',
                tension: 0.2
            }]
        },
        options: {
            responsive: true,
            scales: {
                y: {
                    beginAtZero: true,
                    title: {
                        display: true,
                        text: 'Revenue'
                    }
                },
                x: {
                    title: {
                        display: true,
                        text: 'Closing Date'
                    }
                }
            }
        }
    });
}
额外注意事项
  • 后端返回的profit_data_per_project是空数组,你需要检查后端的np.array(list(moq_data)) * np.array(list(cost_data_per_unit))计算逻辑,确保moq_data和cost_data_per_unit的长度一致,否则numpy会返回空数组
  • 如果需要切换不同类型的图表(比如从折线图切换到饼图),可以在change函数里根据下拉选项做更复杂的逻辑处理

内容的提问来源于stack exchange,提问作者noobmaster64

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:12:39