Chart.js+Django REST Framework下拉框切换图表数据报错求助
问题分析
你遇到的Uncaught TypeError: Cannot read property 'pop' of undefined错误,根源有两个:
- 下拉框的
onchange事件调用change()时没有传递任何参数,导致函数里的data变量是undefined - 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
相关产品推荐
相关产品推荐

