javascript - 无法使用 toDataURL() 转换带有图表和图像的 Canvas

标签 javascript html canvas charts

我有一个条形图(使用 chart.js),标签作为图像,当我尝试将 Canvas 导出为图像时,它只导出图表部分而不是图像(标签),但当我右键单击并导出相同的 Canvas 时另存为图像能够正确导出(图表和标签图像)。

谁能帮我解决这个问题。

我的js文件:

var config = {
    type: 'horizontalBar',
  data: {
    labels:['a', 'b', 'c', 'd', 'e', 'f'],
    datasets: [
      {
        data: [ "20", "10", "2", "5", "1", "22" ],
        backgroundColor: [ '#f1f33a', '#99d695', "#cc8e50", '#ec9089', '#8e7bd4', '#eef5ce' ]   
      }]
  },
  options: {
    animation: {
      duration: 1,
      onComplete: function(charttt) {
        var chartInstance = charttt.chart,
        ctx = chartInstance.ctx;

        ctx.textAlign = 'right';
        ctx.textBaseline = 'bottom';

        this.data.datasets.forEach(function (dataset) {
            var meta = chartInstance.controller.getDatasetMeta(i);
            meta.data.forEach(function (bar, index) {
                var img = new Image();
                img.src = 'https://i.imgur.com/yDYW1I7.png';
                var data = dataset.data[index];

                ctx.fillStyle = 'red';
                ctx.fillText(data, bar._model.x - 20, bar._model.y - 10);
                img.onload = function() {
                  ctx.drawImage(img, bar._model.x, bar._model.y, 10, 10);
                }
            });
        });
        var url = document.getElementById('barChart').toDataURL('image/png');
        document.getElementById("testimg").src = url;
        }
    },
    legend: {
      "display": false
    },
    responsive:false,
    chartArea: {
        backgroundColor: 'blue'
    }
  }
};

var ctx = document.getElementById("barChart").getContext("2d");
var chartt = new Chart(ctx, config);

最佳答案

我想你的问题就在这里......

    this.data.datasets.forEach(function (dataset) {
        var meta = chartInstance.controller.getDatasetMeta(i);

您正在尝试获取数据集 i
的元数据 但是 i 没有定义

需要给forEach函数添加参数

    this.data.datasets.forEach(function (dataset, i) {  // <-- here
        var meta = chartInstance.controller.getDatasetMeta(i);

请参阅以下工作片段...

$(document).ready(function() {
  var config = {
      type: 'horizontalBar',
    data: {
      labels:['a', 'b', 'c', 'd', 'e', 'f'],
      datasets: [
        {
          data: [ "20", "10", "2", "5", "1", "22" ],
          backgroundColor: [ '#f1f33a', '#99d695', "#cc8e50", '#ec9089', '#8e7bd4', '#eef5ce' ]
        }]
    },
    options: {
      animation: {
        duration: 1,
        onComplete: function(charttt) {
          var chartInstance = charttt.chart,
          ctx = chartInstance.ctx;

          ctx.textAlign = 'right';
          ctx.textBaseline = 'bottom';

          this.data.datasets.forEach(function (dataset, i) {
              var meta = chartInstance.controller.getDatasetMeta(i);
              meta.data.forEach(function (bar, index) {
                  var img = new Image();
                  img.src = 'https://i.imgur.com/yDYW1I7.png';
                  var data = dataset.data[index];

                  ctx.fillStyle = 'red';
                  ctx.fillText(data, bar._model.x - 20, bar._model.y - 10);
                  img.onload = function() {
                    ctx.drawImage(img, bar._model.x, bar._model.y, 10, 10);
                  }
              });
          });
          var url = document.getElementById('barChart').toDataURL('image/png');
          document.getElementById("testimg").src = url;
          }
      },
      legend: {
        "display": false
      },
      responsive:false,
      chartArea: {
          backgroundColor: 'blue'
      }
    }
  };

  var ctx = document.getElementById("barChart").getContext("2d");
  var chartt = new Chart(ctx, config);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="barChart"></canvas>
<img id="testimg"/>


编辑

有两个问题导致图像未出现在导出中。

首先,添加来自另一个域的图像会污染 Canvas 。
之后,安全错误将阻止 Canvas 导出。
解决方法是将 crossorigin 属性添加到要添加到图表的图像。

img.setAttribute('crossorigin', 'anonymous');

接下来,在导出图表之前,
我们必须等待所有图像加载完毕,
img.onload 事件中。

请参阅以下工作片段...

$(document).ready(function() {
  var config = {
      type: 'horizontalBar',
    data: {
      labels:['a', 'b', 'c', 'd', 'e', 'f'],
      datasets: [
        {
          data: [ "20", "10", "2", "5", "1", "22" ],
          backgroundColor: [ '#f1f33a', '#99d695', "#cc8e50", '#ec9089', '#8e7bd4', '#eef5ce' ]
        }]
    },
    options: {
      animation: {
        duration: 1,
        onComplete: function(charttt) {
          var chartInstance = charttt.chart,
          ctx = chartInstance.ctx;

          ctx.textAlign = 'right';
          ctx.textBaseline = 'bottom';

          var countDatasets = this.data.datasets.length;
          this.data.datasets.forEach(function (dataset, i) {
              var meta = chartInstance.controller.getDatasetMeta(i);
              var countMeta = meta.data.length;
              meta.data.forEach(function (bar, index) {
                  var img = new Image();
                  img.setAttribute('crossorigin', 'anonymous');
                  img.src = 'https://i.imgur.com/yDYW1I7.png';
                  var data = dataset.data[index];

                  ctx.fillStyle = 'red';
                  ctx.fillText(data, bar._model.x - 20, bar._model.y - 10);
                  img.onload = function() {
                    ctx.drawImage(img, bar._model.x, bar._model.y, 10, 10);
                    countMeta--;
                    if (countMeta === 0) {
                      countDatasets--;
                    }
                    if ((countDatasets === 0) && (countMeta === 0)) {
                      var url = document.getElementById('barChart').toDataURL('image/png');
                      document.getElementById("testimg").src = url;
                    }
                  }
              });
          });
        }
      },
      legend: {
        "display": false
      },
      responsive:false,
      chartArea: {
          backgroundColor: 'blue'
      }
    }
  };

  var ctx = document.getElementById("barChart").getContext("2d");
  var chartt = new Chart(ctx, config);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="barChart"></canvas>
<img id="testimg"/>

关于javascript - 无法使用 toDataURL() 转换带有图表和图像的 Canvas,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56745980/

相关文章:

html - 使用 React 组件状态更改 currentTime

javascript - 如何仅使用变换来旋转html Canvas 形状?

javascript - canvas:创建类似游戏的爆炸星星效果以实现游戏化目的

javascript - Canvas ArcTo 困惑

javascript - jQuery Mobile 对话框在 Chrome 中立即消失

javascript - 冒泡排序不交换 Javascript 中的数组元素

javascript - 使用 jquery cookie 插件附加到此

c# - 如何限制用户重复提交表单?

javascript - 视差背景没有正确排列

html - 在标题中垂直居中 Logo 和导航链接