簡體   English   中英

銷毀 chart.js 條形圖以重繪相同的其他圖形<canvas></canvas>

[英]Destroy chart.js bar graph to redraw other graph in same <canvas>

我正在使用Chart.js庫繪制條形圖,它工作正常,但現在我想破壞條形圖並在同一個canvas中制作折線圖 我試過這兩種方法來清除canvas:

var grapharea = document.getElementById("barChart").getContext("2d");

grapharea.destroy();

var myNewChart = new Chart(grapharea, { type: 'radar', data: barData, options: barOptions });

第二種方式:

var grapharea = document.getElementById("barChart").getContext("2d");

grapharea.clear();

var myNewChart = new Chart(grapharea, { type: 'radar', data: barData, options: barOptions });

我說得對嗎? OnButtonClick 我稱之為 function,它使用相同的 canvas。

為了能夠在同一畫布上繪制另一個圖表,正確的使用方法是.destroy() 您必須在先前創建的圖表對象上調用它。 您也可以對兩個圖表使用相同的變量。

var grapharea = document.getElementById("barChart").getContext("2d");

var myChart = new Chart(grapharea, { type: 'bar', data: barData, options: barOptions });

myChart.destroy();

myChart = new Chart(grapharea, { type: 'radar', data: barData, options: barOptions });

直接來自 文檔(在原型方法下)

.銷毀()

使用它來銷毀任何創建的圖表實例。 這將清除 Chart.js 中存儲到圖表對象的所有引用,以及 Chart.js 附加的任何關聯事件偵聽器。 這必須在畫布重新用於新圖表之前調用。

// Example from the docs
var myLineChart = new Chart(ctx, config);
// Destroys a specific chart instance
myLineChart.destroy();

它明確指出必須先調用此方法,然后才能將畫布重新用於新圖表。

.clear()也在后面與“將清除圖表畫布的函數相同的部分中提到。在動畫幀之間廣泛使用,但您可能會發現它很有用。” 調用此方法后,圖表將保持良好狀態,因此如果您想將畫布重用於全新的圖表,則不應調用此方法。

不過,老實說,在像您這樣的情況下,我經常使用容器div來包裝我的canvas並且每當我需要創建新圖表時,我都會在這個div放置一個新的canvas元素。 然后我將這個新創建的canvas用於新圖表。 如果您遇到過奇怪的行為,可能與圖表在當前圖表之前占據畫布有關,也請記住這種方法。

每次圖表調用后刪除畫布,這對我有用

$("canvas#chartreport").remove();
$("div.chartreport").append('<canvas id="chartreport" class="animated fadeIn" height="150"></canvas>');
var ctx = document.getElementById("chartreport").getContext("2d");
chartreport= new Chart(ctx, { .... });

對於ChartJS v2.x,您可以使用update()來更新圖表數據,而無需顯式銷毀和創建畫布。

var chart_ctx = document.getElementById("chart").getContext("2d");

var chart = new Chart(chart_ctx, {
    type: "pie",
    data: {},
    options: {}
});

$.ajax({
    ...
}).done(function (response) {
    chart.data = response;
    chart.update();
});

也許有更好的方法,但沒有適合我的答案。

document.querySelector("#chartReport").innerHTML = '<canvas id="myChart"></canvas>';

我的 HTML 部分是

<div class="col-md-6 col-md-offset-3">
     <div id="chartReport">
         <canvas id="myChart"></canvas>
     </div>
</div>

2020 年的簡單編輯:

這對我有用。 通過使其擁有窗口來將圖表更改為全局(將聲明從var myChart更改為window myChart

檢查chart變量是否已經初始化為Chart,如果是,銷毀它並創建一個新的,即使你可以創建另一個同名的。 下面是代碼:

if(window.myChart instanceof Chart)
{
    window.myChart.destroy();
}
var ctx = document.getElementById('myChart').getContext("2d");

希望它有效!

我現在使用的是 Chart.js 2.7.2。 在我的應用程序中,我正在創建多個圖表,需要一種方法來訪問它們以正確“替換”它們的數據並修復懸停時顯示的“舊圖表”。 我試過的所有答案都沒有奏效。

這是一種使用一個或多個圖表進行管理的方法:

在全球存儲圖表

var charts=[]; // global

創建圖表的功能

function createChart(id, type, labels, data)
{
    // for multiple datasets
    var datasets=[];
    data.forEach(function(set) {
        datasets.push({
            label: set.label,
            data: set.data
        });
    });  

    var config = {
        type: type,
        data: {
            labels: labels,
            datasets: datasets
        }
    };

    if(typeof charts[id] == "undefined") // see if passed id exists
    {   
        // doesn't, so create it
        charts[id]= new (function(){
            this.ctx=$(id); // canvas el
            this.chart=new Chart(this.ctx, config);
        })();     
        console.log('created chart '+charts[id].chart.canvas.id);     
    }
    else
    {
        charts[id].chart.destroy(); // "destroy" the "old chart"
        charts[id].chart=new Chart(charts[id].ctx, config); // create the chart with same id and el
        console.log('replaced chart '+charts[id].chart.canvas.id);        
    }
    // just to see all instances
    Chart.helpers.each(Chart.instances, function(instance){
        console.log('found instance '+instance.chart.canvas.id)
    })

}

對於每個畫布元素,例如:

<canvas id="thiscanvasid"></canvas>

使用函數創建/替換圖表

createChart('#thiscanvasid', 'bar', json.labels, json.datasets);

你可以測試這個

 $('#canvas').replaceWith($('<canvas id="canvas" height="320px"></canvas>'));

;)

這是我在為給定的畫布 ID 創建新圖表之前銷毀 ChartJS 圖表的策略。 這有點蠻力,但可以完成工作。

我創建了一個對象來跟蹤從畫布 id 到關聯的 ChartJS 對象的映射,我將在創建新對象之前檢查該對象是否有任何現有的 ChartJS 對象要銷毀。

看看這里:


// Helper object and functions

const chartsByCanvasId = {};

const destroyChartIfNecessary = (canvasId) => {
    if (chartsByCanvasId[canvasId]) {
        chartsByCanvasId[canvasId].destroy();
    }
}

const registerNewChart = (canvasId, chart) => {
    chartsByCanvasId[canvasId] = chart;
}

然后,如果圖表存在,這就是如何銷毀圖表

destroyChartIfNecessary(canvasId);
const myChart = new Chart(ctx, config);
registerNewChart(canvasId, myChart);

請注意,在創建圖表后,我們立即使用registerNewChart()對其進行“注冊”。 這個注冊步驟很重要,因為這就是destroyChartIfNecessary()知道給定畫布 id 的 ChartJS 對象已經存在的方式。

這個策略的好處是,即使頁面上有很多圖表,它也能工作,因為它通過畫布 ID 跟蹤 ChartJS 對象。

我總是只使用 1 個圖/頁。 Destroy() 解決了這些問題。

 if (
        window.myLine !== undefined
        &&
        window.myLine !== null
    ) {
        window.myLine.destroy();
    }

    window.myLine = new Chart(graphCanvasCtx, config);

ChartJs 的getChart(key) - 如果圖表已經創建,則從給定的鍵中查找圖表實例。

  • 如果鍵是字符串,則將其解釋為圖表的 Canvas 元素的 ID。
  • 鍵也可以是 CanvasRenderingContext2D 或 HTMLDOMElement。

注意:如果沒有找到圖表,這將返回undefined 如果找到圖表的實例,則表示該圖表必須先前已創建。

 // JS - Destroy exiting Chart Instance to reuse <canvas> element let chartStatus = Chart.getChart("myChart"); // <canvas> id if (chartStatus != undefined) { chartStatus.destroy(); } //-- End of chart destroy var chartCanvas = $('#myChart'); //<canvas> id chartInstance = new Chart(chartCanvas, { type: 'line', data: data });
 <!-- HTML -Line Graph - Chart.js --> <div class="container-fluid" id="chartContainer"> <canvas id="myChart" width="400" height="150"> </canvas> </div>

這種方法將使您免於從 JS 內部刪除 - 創建 - 將 Canvas 元素附加到 DIV 中。

為了解決這個問題,我使用了 jQuery 的add()remove()方法來清除畫布。 我正在刪除組件,在再次繪制它之前,我使用 jQuery 的append()方法再次使用相同的 id 附加畫布。

redraw(){

 $("#myChart").remove();// removing previous canvas element
 //change the data values or add new values for new graph
 $("#chart_box").after("<canvas id='myChart'></canvas>");
 // again adding a new canvas element with same id
 generateGraph();// calling the main graph generating function 

}

創建一個全局對象:

window['chart-' + chartId] = new Chart(...);

訪問和銷毀以進行重繪:

if ( window['chart-' + chartId] != undefined ) {
    window['chart-' + chartId].destroy();
}

這將解決圖表在多次 ajax 調用中多次更新時變慢的問題:

只需在啟動圖表之前添加此代碼:

    $('.chartjs-size-monitor').each(function(){
      $(this).remove();
    })
    var grapharea = document.getElementById("barChart").getContext("2d");

我遇到了同樣的問題,我刪除了畫布元素並重新創建了畫布元素,然后再次渲染了一些延遲。

var element = document.getElementById("canvasId");

element.parentNode.removeChild(element);

var canv =  document.createElement("canvas");

canv.setAttribute("id","canvasId");

canv.style.height = "20vw"; // give height and width as per the requirement

canv.style.width = "20vw"; 

setTimeout(()=>{
 var grapharea = document.getElementById("canvasId").getContext("2d");
},500)

我設法找到了一個與 destroy 方法一起使用的解決方案,並允許在不刪除和重新創建畫布的情況下重用畫布,同時它是較少的資源消耗者。

首先,聲明var chart為 global 並創建一個布爾值來檢查 js 是否已加載

var chart;
var graphScriptLoaded = false;

下一部分很好,因為它只在需要圖形時加載 js,節省了加載頁面的時間,同時它可以讓您了解它是否是第一次執行

//load graph just when needed and destry existing istances
if (!Boolean(graphScriptLoaded)) {
  loadScript('https://cdn.jsdelivr.net/npm/chart.js@2.8.0', function(){
    graphScriptLoaded = true;
    chart=graphs_init(i_arr, spent_arr);
  });
} else {
  chart.destroy();
  chart=graphs_init(i_arr, spent_arr);
}

然后,在創建圖表的函數中,只需返回圖表 var

var chart = new Chart(ctx, {
[.....]
});
return chart;

函數“loadscript”是基於這個答案定制的: 如何在另一個 JavaScript 文件中包含一個 JavaScript 文件?

這是:

    function loadScript(url, callback){

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
          if (script.readyState == "loaded" || script.readyState == "complete"){
                script.onreadystatechange = null;
                callback();
          }
        };
    } else {  //Others
        script.onload = function(){
          callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

它就像一個魅力。

對我來說,它似乎與核心 javascript 類似如下(假設圖表 min js 已經加載):

const data = {
    labels : graphDataLabels,
        datasets: [{
            label: 'Sentiment Intensity Distribution',
            data: dataValues, //[300, 50, 100],
            backgroundColor: [
                "#0D5265",
                "#32DAC8",
                "#FF8300"
            ],
            hoverOffset: 4
        }]
    };
    const config = {
        type: 'pie',
        data: data
    };
    var ctx = document.getElementById('pieChart').getContext('2d');
    if(ctx.pieChart){
        pieChart = null;
    }else{
        pieChart = new Chart(ctx, config);
    }

如果您在一頁上有許多圖表,那么構建數據結構來保存現有圖表的列表是很復雜的。 在 chart.js 3.5.0 中更容易測試圖表畫布是否已被使用。 不需要單獨的數據結構:

// Chart may previously have been shown or not, so the chart may need creating or updating. 
// Vue messes with the DOM, so you can't just "update" the chart as per the docs.
var canv = this.$refs['canvas'];
const oldChart = Chart.getChart(canv);
if (typeof oldChart !== 'undefined') {
    oldChart.destroy();
}
new Chart(canv.getContext('2d'), this.config);

我不知道我花了多少小時來處理這個問題。

讓我們假設您的 html 包含

<div id="soner" class="card-body customerDonutChart">
<canvas id="customerDonutChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas> 
</div>

注意解決問題所必需的<div id="soner"部分。

function myChartJsCaller()
{
   document.getElementById("soner").innerHTML = '<canvas id="customerDonutChart" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>';

  // here is important, your ctx = blabla must be below after changing innerHTML
  let ctx = document.getElementById(selector);
  .
  .
}

從...更改新圖表變量

var yourChart= new Chart(ctx1).Line(barChartData1, {animation: false});

window.yourChart= new Chart(ctx1).Line(barChartData1, {animation: false});

然后

if(window.yourChart!= null)
{
 window.yourChart.destroy();
}

var doc1 = document.getElementById("stockPrice");
var ctx1 = doc1.getContext("2d");
window.yourChart = new Chart(ctx1).Bar(barChartData1, {animation: false});

改變這個: var myChart = new Chart(ctx, {...

如果(window.myChartAnything != 未定義)

window.Anything.destroy();

window.Anything = new Chart(ctx, {...

這在我的網頁上很震撼。

我對此略有不同。 首先在我的 js 中,我定義了一個 map,如下所示。

var chartContext = new Map();

當我填充這個圖表時,我插入一個鍵值對,就像這個值是圖表 object 它自己和鍵是那個 canvas 的 id。

 chartContext.set(chartid, chartObject);

在此之后,當我需要再次重新填充/重新渲染相同的 canvas 時,我會執行以下操作。

if (chartContext.has(chartid)) {
        tempchartContext = chartContext.get(chartid);
        if (tempchartContext instanceof Chart) {
            tempchartContext.destroy();
        }
    }

通過這種方式,舊的圖表上下文被破壞了。

在制作新圖表后,我調用以下代碼再次更新相同的 canvas

我在此示例中使用 Angular 並發現通過執行以下操作很容易

import Chart, { ChartConfiguration } from 'chart.js/auto';
export class ReportsComponent implements OnInit {
    chart1: Chart;

    ngOnInit(): void {
       this.initGraphs(); // logic for creating your charts
       this.drawGraphs(data) // populate the chart and update graph
    }
    
    initGraphs(){
      this.chart1= new Chart(...)
    }

    drawGraphs(data){ // just an example of how you might populate your chart
      for (const total of Object.values(data.gender)) {
        this.chart1.data.datasets[0].data.push(+total);
      }

      this.chart1.update(); // to override the default empty datasets on the chart config
    }

    onUpdate(){
       const filteredData = {...} // this would be the new data you want to show
       this.chart1.destroy();
       this.initGraphs();
       this.drawGraphs(filteredData);
    }
}

所以是的,您使用.destroy()來銷毀創建的任何圖表實例。 但是您必須再次創建圖表才能將其呈現在您的屏幕上

Mais simples que usar a API do charts.js, aqui foi usando o Jquery, JS puro também vai funcionar:

HTML

<div id="graficoSituacoesPedidos" class="col-12">
    <canvas id="myChart"></canvas>
</div>

JS

$('#myChart').remove();
$('#graficoSituacoesPedidos').append('<canvas id="myChart"></canvas>');

// Abaixo recriar o grafico。 Com JS puro funciona também。

這在角度上對我有用

removeHTML() {

    let chart = <HTMLCanvasElement>document.getElementById("myChart"); 
    let chart2 = <HTMLCanvasElement>document.getElementById("myChart2"); 

    if(chart){
       chart.remove()
    }

    if(chart2){
      chart2.remove()
    }


}


ngOnDestroy(): void {

    this.removeHTML();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM