Chartjs 条形图在悬停时显示旧数据

Posted

技术标签:

【中文标题】Chartjs 条形图在悬停时显示旧数据【英文标题】:Chartjs Bar Chart showing old data when hovering 【发布时间】:2017-08-04 23:05:20 【问题描述】:

我有一个使用 chart.js 创建的条形图。页面加载时一切正常,但是当我使用 daterangepicker 更改时间范围时,会出现故障。引入了新数据,但是当我将鼠标悬停在它上面时,会显示旧数据。我是javascript的新手,所以我希望能得到一些帮助。看起来我需要合并 .destroy();不知何故,但我不知道如何。我的代码的 sn-p 如下:

function loadFTPRChart(startdate, enddate)
var BCData = 
labels: [],
datasets: [
 
  label: "Pass %",
  backgroundColor: "#536A7F",
  data: [],
  stack: 1
,

  label: "Fail %",
  backgroundColor: "#e6e6e6",
  data: [],
  stack: 1
,

  label: "Auto %",
  backgroundColor: "#286090",
  data: [],
  stack: 2
,

  label: "Manual %",
  backgroundColor: "#f0f0f0",
  data: [],
  stack: 2

 ]
;
  $.getJSON( "content/FTPR_AM_Graph_ajax.php", 
    startdate: startdate,
    enddate: enddate,
    location: "M"
)
.done(function( data ) 
    console.log("data", data);
    $.each( data.aaData, function( key, val ) 
      if(val == "")return true
      BCData.labels.push("Coater " + val[0]);
      BCData.datasets[0].data.push(parseFloat(val[2]));
      BCData.datasets[1].data.push(parseFloat(100-val[2]));
      BCData.datasets[2].data.push(parseFloat(val[1]));
      BCData.datasets[3].data.push(parseFloat(100-val[1]));
    );

    var option =    
     responsive:true,
;
console.log("BCData", BCData);


//console.log("PrevData", data);
var ctx = document.getElementById("mybarChart2").getContext("2d");
new Chart(ctx, 
  type: 'groupableBar',
  data: BCData,
  options: 
    scales: 
      yAxes: [
        ticks: 
          max: 100,
        ,
        stacked: true,
      ]
    
  
);
);




loadFTPRChart($('#reportrange').data().daterangepicker.startDate.format('MM/DD/YYYY'), $('#reportrange').data().daterangepicker.endDate.format('MM/DD/YYYY'));

销毁原始数据的最佳方法是什么,以便当我更改日期范围并将鼠标悬停在新图表上时,旧数据不再闪烁?

谢谢

【问题讨论】:

有这个问题。创建/重新创建***.com/a/51882403/1181367的解决方案 非常感谢您发布这个问题 :) 您节省了我的时间 /\ 【参考方案1】:

使用您采用的方法(例如,每次日期范围更改时创建一个新的图表对象),那么您必须首先销毁以前的图表,然后再创建新的图表。

您可以使用.destroy() 原型方法来执行此操作。这正是 API 声明的内容。

使用它来销毁任何已创建的图表实例。这会 清理存储在 Chart.js 中的图表对象的所有引用, 以及 Chart.js 附加的任何关联事件侦听器。这 必须在画布重新用于新图表之前调用。

因此,您的代码将如下所示(注意我们会销毁并重新创建)。

// define a variable to store the chart instance (this must be outside of your function)
var myChart;

function loadFTPRChart(startdate, enddate) 
  var BCData = 
    labels: [],
    datasets: [
      label: "Pass %",
      backgroundColor: "#536A7F",
      data: [],
      stack: 1
    , 
      label: "Fail %",
      backgroundColor: "#e6e6e6",
      data: [],
      stack: 1
    , 
      label: "Auto %",
      backgroundColor: "#286090",
      data: [],
      stack: 2
    , 
      label: "Manual %",
      backgroundColor: "#f0f0f0",
      data: [],
      stack: 2
    ]
  ;

  $.getJSON("content/FTPR_AM_Graph_ajax.php", 
      startdate: startdate,
      enddate: enddate,
      location: "M"
    )
    .done(function(data) 
      console.log("data", data);
      $.each(data.aaData, function(key, val) 
        if (val == "") 
          return true
        
        BCData.labels.push("Coater " + val[0]);
        BCData.datasets[0].data.push(parseFloat(val[2]));
        BCData.datasets[1].data.push(parseFloat(100 - val[2]));
        BCData.datasets[2].data.push(parseFloat(val[1]));
        BCData.datasets[3].data.push(parseFloat(100 - val[1]));
      );

      var option = 
        responsive: true,
      ;
      console.log("BCData", BCData);

      // if the chart is not undefined (e.g. it has been created)
      // then destory the old one so we can create a new one later
      if (myChart) 
        myChart.destroy();
      

      var ctx = document.getElementById("mybarChart2").getContext("2d");
      myChart = new Chart(ctx, 
        type: 'groupableBar',
        data: BCData,
        options: 
          scales: 
            yAxes: [
              ticks: 
                max: 100,
              ,
              stacked: true,
            ]
          
        
      );
    );

话虽如此,一遍又一遍地销毁/创建是昂贵的,实际上它甚至没有必要。还有另一种称为.update() 的原型方法,如果您更改了图表的基础数据或标签对象,您可以使用该方法重新渲染图表。

这是一个jsfiddle 显示更改基础数据和标签然后重新呈现图表的示例。我强烈建议您改用这种方法。

这是您的代码采用这种更好的方法后的样子。

// define a variable to store the chart instance (this must be outside of your function)
var myChart;

function loadFTPRChart(startdate, enddate) 
  var BCData = 
    labels: [],
    datasets: [
      label: "Pass %",
      backgroundColor: "#536A7F",
      data: [],
      stack: 1
    , 
      label: "Fail %",
      backgroundColor: "#e6e6e6",
      data: [],
      stack: 1
    , 
      label: "Auto %",
      backgroundColor: "#286090",
      data: [],
      stack: 2
    , 
      label: "Manual %",
      backgroundColor: "#f0f0f0",
      data: [],
      stack: 2
    ]
  ;

  $.getJSON("content/FTPR_AM_Graph_ajax.php", 
      startdate: startdate,
      enddate: enddate,
      location: "M"
    )
    .done(function(data) 
      console.log("data", data);
      $.each(data.aaData, function(key, val) 
        if (val == "") 
          return true
        
        BCData.labels.push("Coater " + val[0]);
        BCData.datasets[0].data.push(parseFloat(val[2]));
        BCData.datasets[1].data.push(parseFloat(100 - val[2]));
        BCData.datasets[2].data.push(parseFloat(val[1]));
        BCData.datasets[3].data.push(parseFloat(100 - val[1]));
      );

      var option = 
        responsive: true,
      ;
      console.log("BCData", BCData);

      // if the chart is not undefined (e.g. it has been created)
      // then just update the underlying labels and data for each
      // dataset and re-render the chart
      if (myChart) 
        myChart.data.labels = BCData.labels;
        myChart.data.datasets[0].data = BCData.datasets[0].data;
        myChart.data.datasets[1].data = BCData.datasets[1].data;
        myChart.data.datasets[2].data = BCData.datasets[2].data;
        myChart.data.datasets[3].data = BCData.datasets[3].data;
        myChart.update();
       else 
        // otherwise, this is the first time we are loading so create the chart
        var ctx = document.getElementById("mybarChart2").getContext("2d");
        myChart = new Chart(ctx, 
          type: 'groupableBar',
          data: BCData,
          options: 
            scales: 
              yAxes: [
                ticks: 
                  max: 100,
                ,
                stacked: true,
              ]
            
          
        );
      
    );

【讨论】:

抱歉,我知道我可能应该知道如何实施您的建议,但是您认为您可以给我更多的想法什么/如何做到这一点?一些 html 当然,它非常简单。我用这两种方法的例子更新了我的答案。由于您没有提供有效的 jsfiddle(或类似的东西),我当然无法对此进行测试,但您应该能够使用这些示例运行。 非常感谢!您提供的第二个选项有效。这有点慢,我会尝试找出加快速度的原因/方法。如果您有任何建议,我会全力以赴。但就目前而言,我非常感谢您的帮助,并将其标记为正确答案。 @jordanwillis 嘿,我试图调用 .destroy() 但它在悬停时仍然显示旧图表。有什么想法吗? 我尝试了第二种方法,但悬停时仍然显示旧图表。【参考方案2】:

我发现了问题,我的解决方案是先从 html 中删除它们,然后再加载新图表,然后附加画布。

HTML

 $('#chart').empty();
    
$('#chart').html('<canvas id="survey_result"   ></canvas>'); // then load chart.
    
var ctx = document.getElementById("survey_result");
    <div id="chart" class="display>
    </div>

【讨论】:

【参考方案3】:

对此有一个简单的解决方案,可以在JS本身中完成。

假设您的 html 如下所示

<div id="chartContainer">
 <canvas id="mybarChart2"></canvas>
</div>

然后在您的脚本中,您可以在更新数据之前添加以下代码行。

document.getElementById("chartContainer").innerHTML = '&nbsp;';
document.getElementById("chartContainer").innerHTML = '<canvas id="mybarChart2"></canvas>';
var ctx = document.getElementById("mybarChart2").getContext("2d");

这解决了我的问题。

【讨论】:

你拯救了我的一天兄弟...非常感谢。 第一次显示图表时,悬停有效。我应该怎么做才能防止这种情况发生 第一次显示图表时,悬停有效。我应该怎么做才能防止这种情况发生 其他解决方案不起作用。这个有效!谢谢! 最快、最好、最简单的解决方法【参考方案4】:

这是我发现的 chartjs 技巧

var ctxLine = document.getElementById("line-chart").getContext("2d");
if(window.bar != undefined) 
window.bar.destroy(); 
window.bar = new Chart(ctxLine, );

https://therichpost.com/solved-hovering-chartjs-bar-chart-showing-old-data

【讨论】:

人群中隐藏的宝石 我尝试了所有其他解决方案,但这个对我有用。使用window. 声明具有全局范围的图表的关键细节【参考方案5】:

它会帮助你...

检查MyChart是否已有配置,如果存在则用destroy()清除;方法,并将新配置绑定到画布。

示例代码..

if (window.MyChart != undefined)

    window.MyChart.destroy();

window.MyChart = new Chart(ctx, MyChartconfig);

【讨论】:

【参考方案6】:

chartjs.org 提供的示例代码表明它们不会破坏()图表并创建新图表。相反,他们从图表中弹出()现有数据并将新数据集推送()到图表,然后更新()图表。

此代码来自 chartjs.org 网站,该网站通过 POP() 从图表中删除数据集。

    document.getElementById('removeDataset').addEventListener('click', function() 
        horizontalBarChartData.datasets.pop();
        window.myHorizontalBar.update();
    );

这段代码用于通过 PUSH() 将数据集添加到图表中:

    document.getElementById('addDataset').addEventListener('click', function() 
        var colorName = colorNames[horizontalBarChartData.datasets.length % colorNames.length];
        var dsColor = window.chartColors[colorName];
        var newDataset = 
            label: 'Dataset ' + (horizontalBarChartData.datasets.length + 1),
            backgroundColor: color(dsColor).alpha(0.5).rgbString(),
            borderColor: dsColor,
            data: []
        ;

        for (var index = 0; index < horizontalBarChartData.labels.length; ++index) 
            newDataset.data.push(randomScalingFactor());
        

        horizontalBarChartData.datasets.push(newDataset);
        window.myHorizontalBar.update();
    );

这两个代码块的最后一步是更新图表。

一般来说,需要从图表中弹出要移除的数据,然后推送新数据,最后更新图表。因此,悬停时不会显示以前的数据。

【讨论】:

【参考方案7】:

在***ing 这么多小时后,我发现并轻松解决它,无需做太多更改...... 只需在选项部分添加这一行

events:[]

在选项部分,它是摆脱 Chartjs 条形图在悬停时显示旧数据的快速解决方案

如果您还需要 Hovering 事件,则尝试重新初始化或重新渲染画布添加如果条件肯定会修复

【讨论】:

这会在悬停时打破工具提示。【参考方案8】:

我知道这是旧的,但其中大多数在我的情况下都不起作用,所以我发布了对我有用的内容。

我有两个图表展示了这种行为,一个 z 堆叠条形图和一个饼图。我试过这些都无济于事:

myChart.destroy():这会改变值,但由于某种原因,也会影响我图表的大小和显示值 options: events: [] :正如那篇文章中所说,这会删除悬停时的所有工具提示,我仍然想要 innerHTML:我不知道这是否是chartjs 的新特性,但我的图表中没有一个除了"" 之外还有innerHTML 属性 myChart.datasets.pop():这个是我解决方案背后的精神,但在大多数情况下,我有不止一个数据集,所以我把它们都删除了:

  if (myChart !== undefined) 
    while (myChart.data.datasets.length > 0) 
      myChart.data.datasets.pop();
    
  

我之前还使用我用来创建图表和组织数据的函数创建了var myChart。将变量声明移到函数外并在函数内实现上述内容后,它们的工作就像一个魅力!

【讨论】:

【参考方案9】:

什么对我有用(也许它无效,但这对我来说不是什么问题,因为每次访问只会执行几次) - 销毁和重新创建整个画布对象(使用 JQuery)。

$("#canvasID").remove();
$("<canvas>").attr(
    id: "canvasID"
).appendTo("#canvasParent");

【讨论】:

【参考方案10】:

我根本无法让“destroy()”工作。我挣扎。我最终完全删除了该元素,然后在每次更新数据时重新创建。

        if(document.getElementById(chartID)) 
            document.getElementById(chartID).remove();
        
        

        var canvasParent;
        // I had 2 charts, so a ternary to select the right element
        chartID == 'fleet-fuel-chartComp1' ? canvasParent = document.getElementById('canvas-node1') : canvasParent = document.getElementById('canvas-node2');
        
        var canvas = document.createElement('canvas');
        canvas.id = chartID;
        canvasParent.appendChild(canvas);

        var ffc = document.getElementById(chartID);

【讨论】:

【参考方案11】:

将 myChart 声明为全局变量

let mychart;

在创建图表之前只写

function pieChart(pdata) 
        // destroy previous created graph
        if (myChart) 
            myChart.destroy()
        
        let ctx = document.getElementById("pie-chart").getContext('2d');
         myChart = new Chart(ctx, 

            type: 'doughnut',
            data: 
                labels: ['Count'],
                datasets: [
                    backgroundColor: [
                        "#2ecc71",
                    ],
                    data: [pdata],

                ]
            ,
            
        );
    

我们为什么要添加这个?因为,如果我们第一次创建任何图形,mychart 创建一个对象,在这种情况下,当我们对它进行排序时,它不会改变。这就是为什么我们需要销毁以前的对象并为更新的可视化创建新对象。

【讨论】:

【参考方案12】:

为什么会出现这个问题

当我们通过ajax更改图形数据时,就会出现这个问题。它将在图表中附加数据。当我们将鼠标悬停在上一个点上时,它会突出显示上一个图表。

解决方案: 100% 有效。

$('#chart').html('');
        $('#chart').html('<canvas id="Chartcanvas" style="height: 350px;"></canvas>');

【讨论】:

【参考方案13】:

我尝试了上面的所有建议,但它们都不起作用,结果证明我的功能:

function initChart(data, label) 
    if(!data)
        data = sanitizeData(!! json_encode($subsequentSickdays) !!);
        label = "Employees with X amount of sickdays";
    
    
    $('#chartjs-custom').html('');
    $('#chartjs-custom').html('<canvas id="chart-absence" class="js-chart"></canvas>');
    
    return $.HSCore.components.HSChartJS.init($('#chart-absence'), 
        "type": "pie",
        "data": setChartData(data, label),
        "options": options()
    );
    

在页面加载时被初始化了两次。一个当我定义var chart = initChart() 并用initChart() 初始化它时。在我删除 initChart() 后它起作用了。不知道为什么这很重要,但是嘿,它有效,希望这对某人有所帮助。

【讨论】:

以上是关于Chartjs 条形图在悬停时显示旧数据的主要内容,如果未能解决你的问题,请参考以下文章

ChartJS 条形图固定宽度动态数据集

在悬停时在堆积条形图上绘制水平线(图表 js)

Javafx - 将鼠标悬停在条形图上

条形图中每个条的颜色不同; ChartJS

熊猫数据框条形图在条形之间放置空间

如何使用 mplcursors 在条形图上添加悬停注释