使用PixiJS渲染带镂空路径的定位SVG图标失败
解决PixiJS Graphics.svg()渲染SVG镂空失效的问题
问题描述
使用PixiJS渲染定位SVG图标时,中间镂空区域无法显示,SVG代码如下:
<svg width="28" height="40" viewBox="0 0 28 40" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M14 0C6.26 0 0 6.26 0 14C0 24.5 14 40 14 40C14 40 28 24.5 28 14C28 6.26 21.74 0 14 0ZM14 19C11.24 19 9 16.76 9 14C9 11.24 11.24 9 14 9C16.76 9 19 11.24 19 14C19 16.76 16.76 19 14 19Z" /> </svg>
该图标在Figma中显示正常,但通过Graphics.svg()方法渲染时镂空消失。尝试设置fill-rule="evenodd"和nonzero均无效,当前绘制代码:
o.graphic = new Graphics() this.#artboard.addChild(o.graphic) o.graphic.svg(pinSVG) o.graphic.stroke({ color: 'black', width: 2 }) o.graphic.fill('red')
若将SVG加载为Texture,镂空显示正常,但无法修改描边等属性。
问题原因
Graphics.svg()方法默认不会自动继承SVG路径的fill-rule配置,尤其是evenodd这种依赖路径环绕方向的填充规则。- 后续调用的
fill()方法会覆盖路径原本的填充设置,强制使用默认填充逻辑,导致镂空失效。
解决方案
方案1:在svg()方法中明确指定填充规则
调用svg()时传入配置项指定填充规则,避免后续fill()方法覆盖设置:
o.graphic = new Graphics() this.#artboard.addChild(o.graphic) // 解析SVG时指定填充规则 o.graphic.svg(pinSVG, { fillRule: 'evenodd' }) // 通过style属性设置填充和描边,而非直接调用fill()/stroke() o.graphic.style.fill = 'red' o.graphic.style.stroke = 'black' o.graphic.style.lineWidth = 2
方案2:手动构建路径并设置填充规则
拆分SVG的内外路径,手动绘制并设置fillRule,利用路径环绕方向实现镂空:
o.graphic = new Graphics() this.#artboard.addChild(o.graphic) // 绘制外层路径 o.graphic.moveTo(14, 0) o.graphic.bezierCurveTo(6.26, 0, 0, 6.26, 0, 14) o.graphic.bezierCurveTo(0, 24.5, 14, 40, 14, 40) o.graphic.bezierCurveTo(14, 40, 28, 24.5, 28, 14) o.graphic.bezierCurveTo(28, 6.26, 21.74, 0, 14, 0) o.graphic.closePath() // 绘制内层镂空路径(反向环绕) o.graphic.moveTo(14, 19) o.graphic.bezierCurveTo(11.24, 19, 9, 16.76, 9, 14) o.graphic.bezierCurveTo(9, 11.24, 11.24, 9, 14, 9) o.graphic.bezierCurveTo(16.76, 9, 19, 11.24, 19, 14) o.graphic.bezierCurveTo(19, 16.76, 16.76, 19, 14, 19) o.graphic.closePath() // 设置填充规则并应用样式 o.graphic.fillRule = 'evenodd' o.graphic.fill('red') o.graphic.stroke({ color: 'black', width: 2 })
方案3:使用SVGLoader解析路径后构建Graphics
通过PIXI.SVGLoader加载SVG,获取原始路径数据后构建Graphics,确保正确保留fill-rule:
import { SVGLoader } from 'pixi.js'; const loader = new SVGLoader(); // 替换为你的SVG文件路径或直接传入SVG字符串 loader.load('pin.svg', (svgData) => { o.graphic = new Graphics(); this.#artboard.addChild(o.graphic); // 遍历解析后的路径,添加到Graphics并应用填充规则 svgData.paths.forEach(path => { o.graphic.drawShape(path.shape); o.graphic.fillRule = path.fillRule; }); // 设置样式 o.graphic.style.fill = 'red'; o.graphic.style.stroke = 'black'; o.graphic.style.lineWidth = 2; });
内容的提问来源于stack exchange,提问作者Nikolay Dyankov
相关产品推荐
相关产品推荐

