如何在HTML Canvas中绘制圆角星形?
绘制圆角星形的实现方案
问题分析
你当前的代码实际绘制的是30边形,而非星形,且未包含圆角处理逻辑。下面先整理你找到的Android平台圆角路径核心思路,再给出适配Canvas的圆角星形实现代码。
Android平台圆角路径核心思路(翻译整理)
该方案通过圆弧过渡实现路径转角的圆角效果,核心步骤为:
- 针对路径上连续的三个顶点(前顶点A、当前顶点B、后顶点C),计算AB、BC两条边的方向向量
- 从B点出发,沿AB反向、BC方向各截取一段长度等于圆角半径的距离,得到两个过渡点P、Q
- 以B为参考点,用圆弧连接P、Q两点,替代原本的尖锐转角B
- 依次处理所有顶点,最终形成带圆角的闭合路径
Canvas实现圆角星形代码
let canvas: HTMLCanvasElement | undefined = undefined; // 角度转弧度 function toRadians(degrees: number) { return degrees * (Math.PI / 180); } // 计算两点间距离 function getDistance(x1: number, y1: number, x2: number, y2: number) { return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); } // 绘制圆角星形 function drawRoundedStar(centerX: number, centerY: number, outerRadius: number, innerRadius: number, points: number, cornerRadius: number) { if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.lineWidth = 2; ctx.strokeStyle = '#000'; ctx.fillStyle = '#fff'; const angleStep = toRadians(360 / points / 2); // 星形步长取半角 const vertices: {x: number, y: number}[] = []; // 生成星形交替顶点(外半径、内半径依次排列) for (let i = 0; i < points * 2; i++) { const radius = i % 2 === 0 ? outerRadius : innerRadius; const angle = toRadians(90) + i * angleStep; // 从顶部开始绘制 const x = centerX + radius * Math.cos(angle); const y = centerY + radius * Math.sin(angle); vertices.push({x, y}); } ctx.beginPath(); // 遍历顶点处理圆角 for (let i = 0; i < vertices.length; i++) { const curr = vertices[i]; const prev = vertices[(i - 1 + vertices.length) % vertices.length]; const next = vertices[(i + 1) % vertices.length]; // 计算前边上的过渡点 const prevDist = getDistance(prev.x, prev.y, curr.x, curr.y); const prevRatio = cornerRadius / prevDist; const pX = curr.x - (curr.x - prev.x) * prevRatio; const pY = curr.y - (curr.y - prev.y) * prevRatio; // 计算后边上的过渡点 const nextDist = getDistance(curr.x, curr.y, next.x, next.y); const nextRatio = cornerRadius / nextDist; const qX = curr.x + (next.x - curr.x) * nextRatio; const qY = curr.y + (next.y - curr.y) * nextRatio; // 绘制线段到过渡点,再用圆弧连接到下一个过渡点 if (i === 0) { ctx.moveTo(pX, pY); } else { ctx.lineTo(pX, pY); } ctx.arcTo(curr.x, curr.y, qX, qY, cornerRadius); } ctx.closePath(); ctx.fill(); ctx.stroke(); } onMount(() => { if (canvas) { // 参数:中心坐标、外半径、内半径、星形角数、圆角半径 drawRoundedStar(150, 150, 80, 40, 5, 10); } });
代码说明
- 先生成星形的交替顶点(外半径、内半径依次排列),构建基础轮廓
- 对每个顶点,计算前后边上距离顶点为圆角半径的过渡点
- 使用
arcTo方法在过渡点间绘制圆弧,替换尖锐转角 - 最后闭合路径并执行填充、描边操作,得到带圆角的星形
内容的提问来源于stack exchange,提问作者garam hyeon
相关产品推荐
相关产品推荐

