如何运行时编程修改SVG指定类颜色并多次绘制到canvas上
问题原因
你之前的方案失效是因为未挂载到当前文档DOM树的SVG资源无法被全局document对象检索到:你直接把原始SVG文本转Blob生成图片的过程中,SVG内部元素没有被解析到当前页面的DOM节点树里,document.getElementsByClassName自然无法匹配到对应元素。
实现方案
你可以在内存中完成SVG的解析、样式修改、序列化流程,全程不需要把SVG挂载到页面可见DOM中,具体步骤如下:
- 第一步:使用
DOMParser将原始SVG文本解析为独立的XML DOM对象 - 第二步:通过这个独立DOM对象的查询接口定位指定类的元素,修改
fill等样式属性 - 第三步:使用
XMLSerializer将修改后的SVG DOM重新序列化为文本字符串 - 第四步:将序列化后的SVG文本转为Blob/DataURL,生成Image实例后绘制到canvas
// 你的原始SVG文本 const originSvgStr = ` <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> <rect class="house-class" x="50" y="100" width="100" height="80" fill="gray"/> <polygon class="roof-class" points="50 100, 100 50, 150 100" fill="darkred"/> <rect class="door-class" x="90" y="140" width="20" height="40" fill="brown"/> <rect class="window-class" x="65" y="115" width="20" height="20" fill="lightblue"/> <rect class="window-class" x="115" y="115" width="20" height="20" fill="lightblue"/> </svg> ` // 1. 解析SVG为DOM对象 const parser = new DOMParser() const svgDom = parser.parseFromString(originSvgStr, 'image/svg+xml') // 2. 修改指定类的填充色,示例把屋顶改成橙色 const roofEls = svgDom.getElementsByClassName('roof-class') for (let el of roofEls) { el.setAttribute('fill', 'orange') } // 示例改墙体为浅黄色 const houseEls = svgDom.getElementsByClassName('house-class') for (let el of houseEls) { el.setAttribute('fill', 'lightyellow') } // 3. 序列化修改后的DOM为SVG文本 const serializer = new XMLSerializer() const modifiedSvgStr = serializer.serializeToString(svgDom) // 4. 转成Image绘制到canvas const canvas = document.getElementById('your-canvas-id') const ctx = canvas.getContext('2d') const img = new Image() // 转成DataURL,也可以用Blob URL获得更好的性能 img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(modifiedSvgStr) img.onload = () => { ctx.drawImage(img, 0, 0) // 多次绘制只要重复上面的修改-序列化-生成Image流程即可,原始SVG文本可以复用 }
注意事项
- 如果原始SVG没有设置
width/height属性,生成Image时可能出现尺寸异常,序列化前可以手动给根svg节点设置宽高属性 - 要多次绘制不同配色的SVG时,直接复用原始SVG文本重复上面的解析-修改流程即可,不要直接修改已经序列化过的SVG文本,避免样式叠加
内容的提问来源于stack exchange,提问作者Sirab33
相关产品推荐
相关产品推荐

