能否在画布上绘制多个SVG?

6

背景

我有一堆包含rectpath等元素的svg文档,需要将其绘制成可下载的PNG图像。为此,我了解到有两种方法:要么将页面的HTML结构绘制到canvas上,然后从那里导出;要么直接将SVG及其内容渲染到canvas上。

假设

第一个假设是使用html2canvas渲染HTML结构,但发现由于安全问题,根本无法渲染SVG。第二个假设是使用canvg将SVG渲染到canvas上,但发现只能呈现一个SVG元素,而且只呈现第一个。

结果

为了证明第一个假设的错误,可以在禁用JavaScript的情况下,输入http://www.w3schools.com/svg/tryit.asp?filename=trysvg_rect访问此URL。为了证明第二个假设的错误,我有一个可供尝试的示例


问题

我想明确一下,我之所以有多个svg是为了将它们放在响应式网格系统中,并通过长宽比进行调整大小。没有更多的话,我问一个问题:如何将多个svg元素渲染到canvas上?如果这个问题的答案是“不可能”,那么我的下一个问题就是:我应该只呈现一个svg,并用另一种方式处理响应性吗?


另一个选择是Fabric.js,它不仅可以解析和显示SVG,而且还创建了对象模型,允许通过编程和/或控件更改对象。我在http://fabricjs.com/kitchensink/(第三个选项卡 -“Load SVG”)中加载了您的示例,并使用“Load without grouping”。两个矩形都呈现在画布上;然后你可以做任何你想做的事情,包括获取画布的图像。 - kangax
@kangax:哇,这很酷。我喜欢它。我一定会去看看的,干得好! - cereallarceny
1个回答

5
你应该能够像处理其他图像一样在画布上绘制SVG:
var img1 = document.createElement('img'),
    img2 = document.createElement('img')
    count = 2;

/// image loading is async, make sure they are loaded
img1.onload = img2.onload = function() {
    count--;
    if (count === 0) drawImages();
}
img1.src = 'some1.svg';
img2.src = 'some2.svg';

/// when loaded, draw them somewhere on the canvas
function drawImages() {
    ctx.drawImage(img1, 0, 0);
    ctx.drawImage(img2, someX, someY);
}

话虽如此 - 有一些限制:

  • FireFox目前在SVG文件中没有设置宽度和高度时,不希望正确绘制图像(链接1)
  • CORS(跨域资源共享)适用于如果您想将图像提取为位图(toDataURL/getImageData)。否则,它们应该正常工作。

我不明白为什么这样做不行,所以我会将其更正。但是,我应该让人们知道,我决定完全避免这个困难,而是在一个svg元素中呈现所有内容。我将通过基于JavaScript检测到的屏幕宽度断点来显示和隐藏图形来处理响应式,以避免生成所有的svg,然后隐藏一些并混乱DOM。 - cereallarceny
就这个而言,它不能在所有浏览器上工作(主要是旧版FF、Opera 12和移动端,Android <=2.3)。您可以在我的测试页面上查看- http://kangax.github.io/jstests/canvas-drawimage-svg/ - kangax
@kangax,正如我在答案中提到的,Canvas和SVG存在问题(尤其是在FF上)。Canvas和SVG是相对较新的功能,仍未确定(不是最终状态,http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html)。不要期望它能在旧版浏览器中运行。 - user1693593

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接