如何用多边形(星形)和边缘模糊的圆形裁剪Canvas?
Canvas 实现锐利星形裁剪与边缘模糊圆形裁剪
要同时实现锐利边缘的星形裁剪和边缘渐变淡出的圆形裁剪,核心是利用Canvas的全局合成模式(globalCompositeOperation)分别处理两种遮罩效果,替代单纯依赖clip的逻辑。以下是修正后的实现:
完整代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style> body { margin: 0; overflow: hidden; } canvas { display: block; } </style> </head> <body> <canvas id="canvas"></canvas> </body> </html>
JavaScript
const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; const img = new Image(); img.src = "你的背景图片路径"; // 替换为实际图片路径 img.onload = function () { let mouseX = canvas.width / 2; let mouseY = canvas.height / 2; const starOuterRadius = 100; const starInnerRadius = 50; const circleRadius = 70; function draw() { // 1. 绘制背景图 ctx.drawImage(img, 0, 0, canvas.width, canvas.height); // 2. 添加深色遮罩层 ctx.fillStyle = "rgba(0, 0, 0, 0.7)"; ctx.fillRect(0, 0, canvas.width, canvas.height); // 3. 使用 destination-out 模式:绘制内容会清除原有像素(实现"挖洞") ctx.globalCompositeOperation = "destination-out"; // 4. 绘制锐利边缘的星形挖洞 const starPoints = createStar(5, mouseX, mouseY, starOuterRadius, starInnerRadius); ctx.beginPath(); ctx.moveTo(starPoints[0].x, starPoints[0].y); for (let i = 1; i < starPoints.length; i++) { ctx.lineTo(starPoints[i].x, starPoints[i].y); } ctx.closePath(); ctx.fill(); // 5. 绘制边缘渐变的圆形挖洞 const gradient = ctx.createRadialGradient( mouseX, mouseY, circleRadius * 0.6, mouseX, mouseY, circleRadius ); // 渐变从中心完全挖空过渡到边缘保留遮罩,实现淡出效果 gradient.addColorStop(0, "rgba(0, 0, 0, 1)"); gradient.addColorStop(1, "rgba(0, 0, 0, 0)"); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(mouseX, mouseY, circleRadius, 0, Math.PI * 2); ctx.fill(); // 6. 恢复默认合成模式 ctx.globalCompositeOperation = "source-over"; } function createStar(points, cx, cy, outerRadius, innerRadius) { const result = []; const angleStep = Math.PI / points; for (let i = 0; i < 2 * points; i++) { const angle = i * angleStep - Math.PI / 2; const radius = i % 2 === 0 ? outerRadius : innerRadius; result.push({ x: cx + radius * Math.cos(angle), y: cy + radius * Math.sin(angle), }); } return result; } canvas.addEventListener("mousemove", function (event) { mouseX = event.clientX; mouseY = event.clientY; draw(); }); draw(); };
关键修改说明
- 合成模式切换:用
destination-out模式实现“挖洞”,替代原clip逻辑——clip会限制后续所有绘制区域,无法单独实现渐变边缘,而合成模式可精准控制像素清除。 - 星形处理:直接绘制星形路径并填充,在
destination-out模式下会生成锐利边缘的挖空区域。 - 圆形渐变调整:反转渐变颜色停止点,从中心完全透明(挖空)过渡到边缘不透明(保留遮罩),自然呈现圆形边缘的渐变淡出效果。
- 绘制顺序优化:先画背景图,再叠加遮罩,最后挖洞显示底层图像,逻辑更直观。
内容的提问来源于stack exchange,提问作者Guile
相关产品推荐
相关产品推荐

