Canvas旋转轮设置lineWidth后边缘截断及文本堆叠旋转问题
Canvas旋转轮问题修复方案
问题1:设置lineWidth后边缘被截断
原因
Canvas绘制描边时,线条宽度的一半会向外延伸出路径范围。你的代码中用rad作为扇形绘制半径,画布尺寸为2*rad,导致描边的外侧部分超出画布边界被截断。
修复方案
有两种常用解决方式:
方式1:缩小绘制半径,预留描边空间
将扇形的绘制半径从rad改为rad - lineWidth/2,让描边外侧刚好贴合画布边缘:
const drawSector = (sector, i) => { const ang = arc * i; const lineWidth = 10; const drawRad = rad - lineWidth / 2; // 调整后的绘制半径 ctx.save(); // 绘制扇形部分 ctx.lineWidth = lineWidth; ctx.strokeStyle = "#ECBA3F"; ctx.beginPath(); ctx.fillStyle = sector.color; ctx.moveTo(rad, rad); ctx.arc(rad, rad, drawRad, ang, ang + arc); // 使用调整后的半径 ctx.lineTo(rad, rad); ctx.fill(); ctx.stroke(); // 文本部分 ctx.translate(rad, rad); ctx.rotate(ang + arc / 2); ctx.textAlign = "right"; ctx.fillStyle = "#000"; ctx.font = "bold 10px sans-serif"; ctx.fillText(sector.label, drawRad - 10, 10); // 文本位置对应调整 ctx.restore(); };
方式2:扩大画布尺寸,容纳描边
将画布宽高设置为2*(rad + lineWidth/2),同时把绘制中心调整为画布中点,确保描边完全在画布内:
// 调整画布尺寸 const lineWidth = 10; const canvasSize = 2 * (rad + lineWidth / 2); canvas.width = canvasSize; canvas.height = canvasSize; const centerX = canvasSize / 2; const centerY = canvasSize / 2; const drawSector = (sector, i) => { const ang = arc * i; ctx.save(); // 绘制扇形部分 ctx.lineWidth = lineWidth; ctx.strokeStyle = "#ECBA3F"; ctx.beginPath(); ctx.fillStyle = sector.color; ctx.moveTo(centerX, centerY); ctx.arc(centerX, centerY, rad, ang, ang + arc); ctx.lineTo(centerX, centerY); ctx.fill(); ctx.stroke(); // 文本部分 ctx.translate(centerX, centerY); ctx.rotate(ang + arc / 2); ctx.textAlign = "right"; ctx.fillStyle = "#000"; ctx.font = "bold 10px sans-serif"; ctx.fillText(sector.label, rad - 10, 10); ctx.restore(); };
问题2:实现扇形内文本堆叠旋转
实现思路
把文本拆分为单个字符(或按语义拆分的词语),通过旋转画布让文本垂直排列,再逐行绘制每个单元,形成堆叠效果。
修改后的代码示例
const drawSector = (sector, i) => { const ang = arc * i; const lineWidth = 10; const drawRad = rad - lineWidth / 2; ctx.save(); // 绘制扇形部分(同问题1修复后的代码) ctx.lineWidth = lineWidth; ctx.strokeStyle = "#ECBA3F"; ctx.beginPath(); ctx.fillStyle = sector.color; ctx.moveTo(rad, rad); ctx.arc(rad, rad, drawRad, ang, ang + arc); ctx.lineTo(rad, rad); ctx.fill(); ctx.stroke(); // 堆叠旋转文本部分 ctx.translate(rad, rad); ctx.rotate(ang + arc / 2); // 额外旋转90度,使文本垂直排列 ctx.rotate(-Math.PI / 2); ctx.textAlign = "center"; ctx.fillStyle = "#000"; ctx.font = "bold 10px sans-serif"; const textLines = sector.label.split(''); // 按单个字符拆分,按词语拆分可改为split(' ') const lineSpacing = 15; // 行间距,可根据字体大小调整 // 逐行绘制文本 textLines.forEach((line, idx) => { ctx.fillText(line, drawRad - 20, idx * lineSpacing); }); ctx.restore(); };
说明
- 文本拆分:如果标签是词语组合,用
split(' ')按空格拆分更符合语义。 - 排版调整:
lineSpacing控制行间距,drawRad - 20控制文本距扇形边缘的距离,可按需修改。
内容的提问来源于stack exchange,提问作者aachukay
相关产品推荐
相关产品推荐

