使用Path2D后LinearGradient渐变不随路径变换问题求助
问题:Path2D变换后渐变效果未同步更新
我通过ctx.createLinearGradient设置填充样式的图形,此前使用ctx.beginPath和ctx.transform时功能正常,但改用Path2D后,其他功能正常,唯独渐变效果无法随Path2D的平移、缩放或旋转变换同步改变,希望渐变能和Path2D的变换同步更新。
核心代码如下:
const ctx = document.body.appendChild(document.createElement('canvas')).getContext('2d') // 创建渐变 const gradient = ctx.createLinearGradient(40, 0, 40, 80) gradient.addColorStop(0, '#fff') gradient.addColorStop(1, '#ff0000') ctx.fillStyle = gradient let translate = 60, scaleY = 1.1 // 未变换的路径 const p1 = new Path2D() p1.arc(40, 40, 40, 0, 2 * Math.PI) ctx.fill(p1) // 应用变换后的路径 const p2 = new Path2D() p2.addPath(p1, new DOMMatrix().translate(translate, translate).scale(1, scaleY)); ctx.fill(p2)
效果说明:第一个未变换的圆形渐变显示正常,第二个经过平移和缩放的圆形,渐变未同步变换,仍保持原渐变的方向和范围。
解决方案
问题根源在于渐变是基于画布全局坐标系创建的,Path2D的内部变换仅作用于路径形状,不会自动关联到填充样式的渐变上。以下是两种可行的解决方法:
方案1:为渐变应用相同的变换矩阵
手动将Path2D使用的变换矩阵应用到渐变的起止坐标上,生成适配变换后路径的新渐变:
const ctx = document.body.appendChild(document.createElement('canvas')).getContext('2d') // 原渐变配置 const gradient = ctx.createLinearGradient(40, 0, 40, 80) gradient.addColorStop(0, '#fff') gradient.addColorStop(1, '#ff0000') let translate = 60, scaleY = 1.1 // 绘制未变换的图形 const p1 = new Path2D() p1.arc(40, 40, 40, 0, 2 * Math.PI) ctx.fillStyle = gradient ctx.fill(p1) // 创建路径使用的变换矩阵 const transformMatrix = new DOMMatrix().translate(translate, translate).scale(1, scaleY) // 对渐变的起止点应用变换 const startPoint = transformMatrix.transformPoint(new DOMPoint(40, 0)) const endPoint = transformMatrix.transformPoint(new DOMPoint(40, 80)) // 生成变换后的渐变 const transformedGradient = ctx.createLinearGradient(startPoint.x, startPoint.y, endPoint.x, endPoint.y) transformedGradient.addColorStop(0, '#fff') transformedGradient.addColorStop(1, '#ff0000') // 绘制变换后的路径 const p2 = new Path2D() p2.addPath(p1, transformMatrix) ctx.fillStyle = transformedGradient ctx.fill(p2)
方案2:使用上下文变换替代Path2D内部变换
回到之前的上下文变换思路,通过ctx.translate、ctx.scale等方法修改画布坐标系,此时渐变会自动跟随坐标系变换:
const ctx = document.body.appendChild(document.createElement('canvas')).getContext('2d') const gradient = ctx.createLinearGradient(40, 0, 40, 80) gradient.addColorStop(0, '#fff') gradient.addColorStop(1, '#ff0000') ctx.fillStyle = gradient // 绘制未变换的图形 const p1 = new Path2D() p1.arc(40, 40, 40, 0, 2 * Math.PI) ctx.fill(p1) // 保存当前上下文状态,避免影响后续绘制 ctx.save() // 应用平移和缩放变换 let translate = 60, scaleY = 1.1 ctx.translate(translate, translate) ctx.scale(1, scaleY) // 绘制变换后的图形(渐变会自动适配当前坐标系) ctx.fill(p1) // 恢复上下文状态 ctx.restore()
内容的提问来源于stack exchange,提问作者Meysam Ghorbani
相关产品推荐
相关产品推荐

