我正在尝试制作一些SVG,然后将它们绘制到画布上。它们需要绘制到画布上,因为我之后会进行一些像素级操作。我跟随MDN article并试图绘制一个矩形。到目前为止一切顺利(fiddle)。但是当我尝试apply a filter时,它会中断。
(我使用的示例是一个矩形,但我稍后将使用自定义路径,因此canvas rect()方法不合适。)
发生了什么事?我的直觉是filter
节点在加载svg节点之前并不“存在”......但是rect
节点也没有,所以我真的不知道... < / p>
var data = '<svg ...' //the svg code
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img, 0, 0, 223, 223);
DOMURL.revokeObjectURL(url);
}
img.src = url;
编辑:善良,我甚至没有想到它是浏览器!我正在使用Firefox 43.它以铬显示;我确实需要在Firefox / gecko中正确显示它,因为FF在目标受众的浏览器市场中占有很大份额。我检查过FF和42的Linux和Windows版本。 43他们都有同样的问题。
答案 0 :(得分:3)
可能有一些角色无法很好地传递到blob中。
(正如罗伯特·朗森所指出的那样,它实际上是一个FF bug,但无论如何都报告了were other issues
解决方案是将[string
替换为blob
至blobURI
]为[encodedString
至dataURI
]:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="223" height="223">' +
'<defs>' +
'<filter id="f1" x="0" y="0">' +
'<feGaussianBlur in="SourceGraphic" stdDeviation="5" />' +
'</filter>' +
'</defs>' +
'<rect class="shape" x="0" y="0" width="100" height="150" transform="translate(40,15) rotate(15,50,75)" fill="#006791" filter="url(#f1)"></rect></svg>';
// first encode the special characters
var svg_data = encodeURIComponent(data);
// create a dataURI version
var url = 'data:image/svg+xml; charset=utf8, ' + svg_data;
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0, 223, 223);
}
img.src = url;
<canvas id="canvas" style="border:2px solid black;" width="223" height="223">
</canvas>
Ps:一个均匀的消毒剂解决方案,但更重一点,是使用DOMParser来解析你的字符串,然后将其结果序列化为一个XMLSerializer的字符串,编码这个字符串,最后把它变成一个dataURI:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="223" height="223">' +
'<defs>' +
'<filter id="f1" x="0" y="0">' +
'<feGaussianBlur in="SourceGraphic" stdDeviation="5" />' +
'</filter>' +
'</defs>' +
'<rect class="shape" x="0" y="0" width="100" height="150" transform="translate(40,15) rotate(15,50,75)" fill="#006791" filter="url(#f1)"></rect></svg>';
// create a new DOMParser
var parser = new DOMParser();
// Parse our string as an svg document
var doc = parser.parseFromString(data, 'image/svg+xml');
// Serialize the new svg document
var svg_data = new XMLSerializer().serializeToString(doc.documentElement);
// set it to a dataURI
var url = 'data:image/svg+xml; charset=utf8, '+encodeURIComponent(svg_data);
var img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0, 223, 223);
}
img.src = url;
<canvas id="canvas" style="border:2px solid black;" width="223" height="223">
</canvas>
现在您已经有了解决方案,我们可以尝试来回答“发生了什么事情?”
Chrome在使用xlink:href
属性或<funcIRI>
(url(#xxx)
)内部属性引用的外部元素方面存在错误。
例如,如果您在外部CSS样式表中进行此类引用,则它不会引用良好的URI路径,并且它无法获取外部引用中指定的引用。
有关详情,请参阅this codepen:
球应涂上两个radialGradient
,放在外部svg文件内。径向渐变本身引用同一文档中的linearGradient
。
当chrome只能获取直接元素(复选标记)时,Firefox会正确获取每个请求的元素。
Firefox: Chrome:
当您使用URL.createObjectURL()
时,您在浏览器的内存中创建一个新文件,并带有一个特殊位置(其location.origin
将设置为其中一个创建它的页面,但不会设置pathName
或host
。)。
我没有进入FF获取代码,但是我猜他们在这里做了一些事情,当你进入这样一个特殊的url方案时,甚至内部引用都会出错,那就是你的情况会破坏。
所以是的,这里的FF被打破了,但肯定是因为其他浏览器甚至没有尝试做过......