canvas画布绘制正五角星
<style>.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<h2>效果:</h2>
<canvas id="canv" width="400" height="400"></canvas></div>
<h2>代码:</h2>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span> width=<span class="tMagenta">"400"</span> height=<span class="tMagenta">"400"</span>><<span class="tDarkRed">/canvas</span>><<span class="tDarkRed">/div</span>></cl-cd>
<cl-cd data-idx="2"> </cl-cd>
<cl-cd data-idx="3"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="4"><span class="tBlue">var</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="5"><span class="tBlue">var</span> points = [], keys = ;</cl-cd>
<cl-cd data-idx="6"> </cl-cd>
<cl-cd data-idx="7"><span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i < 5; i ++) {</cl-cd>
<cl-cd data-idx="8"> <span class="tBlue">var</span> x = 200 + 190 * <span class="tRed">Math</span>.cos((72*i-18) * <span class="tRed">Math</span>.PI/180),</cl-cd>
<cl-cd data-idx="9"> y = 200 + 190 * <span class="tRed">Math</span>.sin((72*i - 18) * <span class="tRed">Math</span>.PI/180);</cl-cd>
<cl-cd data-idx="10"> points.push({<span class="tBlue">x:</span> x, <span class="tBlue">y:</span> y});</cl-cd>
<cl-cd data-idx="11">}</cl-cd>
<cl-cd data-idx="12"> </cl-cd>
<cl-cd data-idx="13">ctx.beginPath();</cl-cd>
<cl-cd data-idx="14">points.forEach((_,key) => ctx.lineTo(points].x, points].y));</cl-cd>
<cl-cd data-idx="15">ctx.closePath();</cl-cd>
<cl-cd data-idx="16">ctx.lineWidth = 3;</cl-cd>
<cl-cd data-idx="17">ctx.fillStyle = <span class="tMagenta">'red'</span>;</cl-cd>
<cl-cd data-idx="18">ctx.fill();</cl-cd>
<cl-cd data-idx="19"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<script>
var ctx = canv.getContext('2d');
var points = [], keys = ;
for(let i = 0; i < 5; i ++) {
var x = 200 + 190 * Math.cos((72*i-18) * Math.PI/180),
y = 200 + 190 * Math.sin((72*i - 18) * Math.PI/180);
points.push({x: x, y: y});
}
ctx.beginPath();
points.forEach((_,key) => ctx.lineTo(points].x, points].y));
ctx.closePath();
ctx.lineWidth = 3;
ctx.fillStyle = 'red';
ctx.fill();
</script>
本帖最后由 马黑黑 于 2024-5-2 11:44 编辑
正五角星就是我们国旗上使用的五角星,五个角尖每个角的角度度为36度。
传统的canvas画布绘制正五角星的方法首先需要计算出五个角尖的xy坐标,再计算五个内角的xy坐标,然后按角尖→内角→角尖这样的次序将各点连接起来。这种画法需要注意一个问题:外圆和内圆的半径比例应为 5:2,否则画出的五角星不是正五角星。
一楼效果不采用这种方法。思路是酱紫:
计算出正五边形各个角的xy坐标,然后每间隔一个角将各个角连接起来。这其实是一笔手绘正五角星的方法的代码演绎,不同的是效果——代码绘制的绝对比手绘的精准。
具体画法:
先定义一个点坐标数组 points变量,用来存储即将计算的各个角的坐标值,同时设计一个数组下标序列列表 keys,用以指引绘制连线。
接着用一个for循环语句求出正五边形各个角的xy坐标,使用 x=cx+r*cos(弧度)、y=cy + r*sin(弧度) 这两个公式(cx、cy 为圆心坐标 x、y 值,r 为半径):
x = 200 + 190 * Math.cos((72*i-18) * Math.PI/180)
y = 200 + 190 * Math.sin((72*i-18) * Math.PI/180)
200 分别是圆心x、y坐标值,190 是圆的半径;72 来源于 360/5,就是五等分圆的角度值;i 是循环步进变量,不同的角角度不一样;每个角减去 18 是为了扶正五角星而做的调节;Math.PI/180 是角度转换为弧度的需要,来源于公式 弧度=角度*π/180 。
这些正五边形的角坐标值以对象 {x: 值, y: 值} 的形式存入 points 变量中,留待绘制之时使用。
最后绘制,核心要点是,按 keys 下标序列取出各个角的坐标值,依次绘制连线即可。本例,使用填充方法 fill() 给五角星着色,也可以使用 stroke() 方法描边,两者同时使用也可以(注意定义一下 strokeStyle 和 lineWidth)。
<h2>附:传统绘制代码</h2>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span> width=<span class="tMagenta">"400"</span> height=<span class="tMagenta">"400"</span>><<span class="tDarkRed">/canvas</span>></cl-cd>
<cl-cd data-idx="2"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="3"> <span class="tBlue">const</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="4"> ctx.beginPath();</cl-cd>
<cl-cd data-idx="5"> <span class="tBlue">for</span> (<span class="tBlue">let</span> i = 0; i < 5; i++) {</cl-cd>
<cl-cd data-idx="6"> ctx.lineTo(200 + <span class="tRed">Math</span>.cos((18+72*i)/180*<span class="tRed">Math</span>.PI)*190, 200 - <span class="tRed">Math</span>.sin((18+72*i)/180*<span class="tRed">Math</span>.PI)*190);</cl-cd>
<cl-cd data-idx="7"> ctx.lineTo(200 + <span class="tRed">Math</span>.cos((54+72*i)/180*<span class="tRed">Math</span>.PI)*76, 200 - <span class="tRed">Math</span>.sin((54+72*i)/180*<span class="tRed">Math</span>.PI)*76);</cl-cd>
<cl-cd data-idx="8"> }</cl-cd>
<cl-cd data-idx="9"> ctx.closePath();</cl-cd>
<cl-cd data-idx="10"> ctx.lineWidth = 3;</cl-cd>
<cl-cd data-idx="11"> ctx.strokeStyle = <span class="tMagenta">'red'</span>;</cl-cd>
<cl-cd data-idx="12"> ctx.stroke();</cl-cd>
<cl-cd data-idx="13"><<span class="tDarkRed">/script</span>></cl-cd>
</div> 传统绘制方法中,正五角星的角尖即外圆角假定为外圆(大圆)圆周上的特定点,五角星的内圆角(108度)则为内圆(小圆)圆周上的特定角。
定义内圆角在绘制复杂正五角星时是有必要的,比如不同的路径区域上不同的描边色和填充色,以营造立体感。
再次强调:传统绘制方法中,外圆半径:内圆半径 = 5:2。 这个画法真简洁啊,一笔画成,用0,2,4,1,3的次序画,再用ctx.closePath();连回到0,完美{:4_187:} 马黑黑 发表于 2024-5-2 12:04
传统绘制方法中,正五角星的角尖即外圆角假定为外圆(大圆)圆周上的特定点,五角星的内圆角(108度)则为 ...
传统的还得计算内圆半径,还要考虑内圆角,还是黑黑的一笔连线的五角星更简洁{:4_199:} 电脑预览一个大大的红五角星出来了{:4_173:} 小辣椒 发表于 2024-5-2 21:15
电脑预览一个大大的红五角星出来了
过一下我会发布一个有立体感的五角星 马黑黑 发表于 2024-5-2 21:18
过一下我会发布一个有立体感的五角星
好啊,黑黑是精彩不断,惊喜连连 小辣椒 发表于 2024-5-2 21:19
好啊,黑黑是精彩不断,惊喜连连
这也不是,学习中 马黑黑 发表于 2024-5-2 21:21
这也不是,学习中
反正你不怕胖,我们就期待效果 小辣椒 发表于 2024-5-2 21:23
反正你不怕胖,我们就期待效果
胖胖防台风 红影 发表于 2024-5-2 14:56
传统的还得计算内圆半径,还要考虑内圆角,还是黑黑的一笔连线的五角星更简洁
虽如此,但要着填充色,内外圆的角数据都需要 红影 发表于 2024-5-2 14:49
这个画法真简洁啊,一笔画成,用0,2,4,1,3的次序画,再用ctx.closePath();连回到0,完美
仅仅画正五角星的话,这是好办法 马黑黑 发表于 2024-5-2 21:24
胖胖防台风
最近台风好像我们这里还没有出现 小辣椒 发表于 2024-5-2 21:34
最近台风好像我们这里还没有出现
有备无患,胖胖更安全 马黑黑 发表于 2024-5-2 21:26
虽如此,但要着填充色,内外圆的角数据都需要
是的,看到黑黑的立体五角星了,的确都需要呢。 马黑黑 发表于 2024-5-2 21:27
仅仅画正五角星的话,这是好办法
黑黑的独创{:4_199:} 红影 发表于 2024-5-3 09:29
黑黑的独创
也不是,尝试而已 红影 发表于 2024-5-3 09:28
是的,看到黑黑的立体五角星了,的确都需要呢。
作图理论上细节越丰富图像的效果就会越好