Wix Velo中Chart.js发布后刷新失败,提示Canvas已占用
问题描述
我在Wix Velo中使用Chart.js绘制图表,添加了按钮用于切换图表数据,核心切换代码如下:
if (!chart1 ) {chart1 = new ChartJSAPI($w('#CustomElement1'));} chart1.customization = data_chart.customization chart1.data = data_chart.data
预览状态下图表可正常刷新,但发布后出现错误:
hart.js:5552 Uncaught Error: Canvas is already in use. Chart with ID '0' must be destroyed before the canvas with ID 'myChart' can be reused.
完整代码:
import { ChartJSAPI } from 'public/chart-api'; import { chartCustomization } from 'public/chart-customization'; import wixData from 'wix-data'; $w.onReady(async function () { chart(processDataForChart(results2)) }) var results2 = [ { trip_date: { value: "2021-01-01" }, trips_count: 19595 }, { trip_date: { value: "2021-02-01" }, trips_count: 19460 }, { trip_date: { value: "2021-03-01" }, trips_count: 10909 }, { trip_date: { value: "2021-04-01" }, trips_count: 35 } ]; var results3 = [ { trip_date: { value: "2021-01-01" }, trips_count: 1955 }, { trip_date: { value: "2021-02-01" }, trips_count: 1960 }, { trip_date: { value: "2021-03-01" }, trips_count: 1009 }, { trip_date: { value: "2021-04-01" }, trips_count: 3570 } ]; // 确定X轴对应的列 function getColumnName(jsonData) { var columns_counter = 0 var columns = Object.keys(jsonData[0]) for (var i = 0; i < columns.length; i++) { if (jsonData[0][columns[i]].value != undefined) { console.log('getColumnName',columns[i]) return columns[i]; } columns_counter ++ } console.log('getColumnName',columns[0]) columns[0] } function processDataForChart(jsonData) { var columns = Object.keys(jsonData[0]) var dataArray = []; var counter = 0 var labels = []; var columns_counter = 0 var backgroundColor1 = ["rgba(255, 99, 132, 0.2)","rgba(54, 162, 235, 0.2)","rgba(255, 206, 86, 0.2)","rgba(75, 192, 192, 0.2)","rgba(255, 159, 64, 1)"] var borderColor1 = ["rgba(255, 99, 132, 1)", "rgba(54, 162, 235, 1)","rgba(255, 206, 86, 1)","rgba(75, 192, 192, 1)","rgba(153, 102, 255, 1)","rgba(255, 159, 64, 1)"] var backgroundC = [] var borderC = [] var x_axis = getColumnName(jsonData) columns.forEach(function(column) { console.log('column',column ) console.log('x_axis', x_axis ) if(column != x_axis ){ var label = []; var type=[]; var data = []; var backgroundC = []; var borderC = []; var borderWidth = []; backgroundC.push(backgroundColor1[columns_counter]); borderC.push(borderColor1[columns_counter]); type.push("bar") borderWidth.push(1) jsonData.forEach(function(item) { if (counter < 5){ data.push(item[column]); } }); dataArray.push({ label: column, type: type, data: data, backgroundColor: backgroundC, borderColor: borderC, borderWidth: borderWidth }); counter++; } else{ jsonData.forEach(function(item) { labels.push(item[column].value); }) } columns_counter ++ }) var data_charts = { data: { "labels": labels, "datasets": dataArray }, customization: { "borderWidth": 1, } }; return data_charts } var chart1 async function chart(data_chart){ if (!chart1 ) {chart1 = new ChartJSAPI($w('#CustomElement1'));} chart1.customization = data_chart.customization chart1.data = data_chart.data } export function button6_click(event) { chart(processDataForChart(results3)) }
解决方案
这个错误的核心原因是:发布环境中旧的Chart.js实例未被销毁,导致canvas元素被重复占用。预览环境的生命周期逻辑和发布环境不同,所以预览时无问题,发布后触发冲突。
方法1:销毁旧实例后重建
修改你的chart函数,每次更新前先销毁已有实例:
var chart1; async function chart(data_chart){ // 销毁已有图表实例 if (chart1) { await chart1.destroy(); } // 重新创建实例并赋值数据 chart1 = new ChartJSAPI($w('#CustomElement1')); chart1.customization = data_chart.customization; chart1.data = data_chart.data; }
方法2:直接更新数据(如果API支持)
如果ChartJSAPI封装了Chart.js的update方法,可以直接更新数据而不重建实例:
var chart1; async function chart(data_chart){ if (!chart1 ) { chart1 = new ChartJSAPI($w('#CustomElement1')); chart1.customization = data_chart.customization; chart1.data = data_chart.data; } else { // 更新数据后调用update方法刷新 chart1.data = data_chart.data; await chart1.update(); } }
方法3:扩展自定义元素的销毁方法
如果ChartJSAPI没有暴露destroy方法,需要修改自定义元素的代码(对应public/chart-api的前端文件),添加销毁逻辑:
// 自定义元素内部代码示例 class ChartJSCustomElement extends HTMLElement { constructor() { super(); this.chart = null; } // 新增销毁实例的方法 destroy() { if (this.chart) { this.chart.destroy(); this.chart = null; } } // 其他原有方法(如设置data、customization的逻辑)... }
添加后,就可以在Velo代码中正常调用chart1.destroy()来销毁旧实例了。
内容的提问来源于stack exchange,提问作者idan
相关产品推荐
相关产品推荐

