首页 > 解决方案 > 无法在 Firefox 中始终将 SVG 绘制到 Canvas 元素

问题描述

我正在尝试编写一个脚本以允许用户将 SVG 下载为 PNG。SVG 是通过 d3.js 生成的,下面的脚本用于获取生成的 SVG,将其放入 canvas 元素中,然后通过锚元素触发下载。

一切都在 Chrome 和 Safari 上完美运行,但是当我在 Firefox 上进行测试时,我得到了不同的结果。

有时画布元素最终是空白的,我得到一个尺寸正确但没有内容的 png,有时下载效果很好。有时每隔一次点击下载按钮它就会起作用,有时它会在我调整页面大小后中断,只是为了让它在几次点击后开始工作。

canvas.getContext 的“等待”语句在那里,没有它我在 Chrome 和 Safari 中得到相同的行为,这也让我感到困惑,因为我不相信 getContext 方法是异步的。

我的问题是为什么 Firefox 中的行为不同,如何调整代码以允许跨这些浏览器进行相同类型的下载?

对于其他上下文,我正在使用 ReactJS,并且该函数在 useEffect 块内被调用。此外,如果我输出img在代码中创建的内容,它会 100% 正确呈现。SVG 还具有固定的宽度和高度属性,它们不是百分比。

enum FileFormat {
  SVG = 'svg',
  PNG = 'png',
}

interface Input {
  svg: Node | null;
  width: number | undefined;
  height: number | undefined;
  fileFormat?: FileFormat;
}

export default async (input: Input) => {
  const {svg, fileFormat} = input;
  const width = input.width ? input.width : 1500;
  const height = input.height ? input.height : 1500;
  const canvas = document.createElement('canvas');
  if (canvas && svg) {
    const img = new Image();
    const serializer = new XMLSerializer();
    const svgStr = serializer.serializeToString(svg);

    img.src = 'data:image/svg+xml;base64,' + window.btoa(svgStr);
    img.width = width;
    img.height = height;

    canvas.width = width;
    canvas.height = height;
    const canvasContext = await canvas.getContext('2d');
    let url = '';
    if (canvasContext) {
      canvasContext.drawImage(img, 0, 0, width, height);
      url = canvas.toDataURL('image/png');
    }

    const a = document.createElement('a');
    if (fileFormat === FileFormat.SVG) {
      a.href = img.src;
      a.download = 'chart.svg';
    } else {
      a.href = url;
      a.download = 'chart-new.png';
    }
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }
};

标签: javascriptreactjsd3.jssvgcanvas

解决方案


推荐阅读