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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:24:56