在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; }
.tMid { text-align: center; }
</style>
<h2>效果</h2>
<p class="tMid"><canvas id="canv" width="400" height="400"></canvas></p>
<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"> </cl-cd>
<cl-cd data-idx="3"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="4"> </cl-cd>
<cl-cd data-idx="5"><span class="tBlue">var</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="6"><span class="tBlue">var</span> size = canv.width / 2, r1 = size - 10, r2 = r1 * 2/5, points = [];</cl-cd>
<cl-cd data-idx="7"> </cl-cd>
<cl-cd data-idx="8"><span class="tBlue">for</span>(<span class="tBlue">var</span> i = 0; i < 5; i ++) {</cl-cd>
<cl-cd data-idx="9"> <span class="tBlue">var</span> x1 = <span class="tRed">Math</span>.cos((18 + i * 72) / 180 * <span class="tRed">Math</span>.PI) * r1 + size,</cl-cd>
<cl-cd data-idx="10"> y1 = -<span class="tRed">Math</span>.sin((18 + i * 72) / 180 * <span class="tRed">Math</span>.PI) * r1 + size,</cl-cd>
<cl-cd data-idx="11"> x2 = <span class="tRed">Math</span>.cos((54 + i * 72) / 180 * <span class="tRed">Math</span>.PI) * r2 + size,</cl-cd>
<cl-cd data-idx="12"> y2 = -<span class="tRed">Math</span>.sin((54 + i * 72) / 180 * <span class="tRed">Math</span>.PI) * r2 + size;</cl-cd>
<cl-cd data-idx="13"> points.push({x1: x1, y1: y1, x2: x2, y2: y2});</cl-cd>
<cl-cd data-idx="14">}</cl-cd>
<cl-cd data-idx="15"> </cl-cd>
<cl-cd data-idx="16"><span class="tBlue">var</span> drawTriangle = () => {</cl-cd>
<cl-cd data-idx="17"> <span class="tBlue">for</span>(<span class="tBlue">var</span> j = 0; j < 5; j++) {</cl-cd>
<cl-cd data-idx="18"> ctx.beginPath();</cl-cd>
<cl-cd data-idx="19"> ctx.moveTo(points.x1, points.y1);</cl-cd>
<cl-cd data-idx="20"> ctx.lineTo(size, size);</cl-cd>
<cl-cd data-idx="21"> ctx.lineTo(points.x2, points.y2);</cl-cd>
<cl-cd data-idx="22"> ctx.lineTo(points.x1, points.y1);</cl-cd>
<cl-cd data-idx="23"> ctx.fill();</cl-cd>
<cl-cd data-idx="24"> }</cl-cd>
<cl-cd data-idx="25">};</cl-cd>
<cl-cd data-idx="26"> </cl-cd>
<cl-cd data-idx="27"><span class="tBlue">var</span> draw5star = () => {</cl-cd>
<cl-cd data-idx="28"> ctx.fillStyle = <span class="tMagenta">'red'</span>;</cl-cd>
<cl-cd data-idx="29"> drawTriangle();</cl-cd>
<cl-cd data-idx="30"> ctx.save();</cl-cd>
<cl-cd data-idx="31"> ctx.fillStyle = <span class="tMagenta">'darkred'</span>;</cl-cd>
<cl-cd data-idx="32"> ctx.translate(size, size);</cl-cd>
<cl-cd data-idx="33"> ctx.scale(-1, 1);</cl-cd>
<cl-cd data-idx="34"> ctx.translate(-size, -size);</cl-cd>
<cl-cd data-idx="35"> drawTriangle();</cl-cd>
<cl-cd data-idx="36"> ctx.restore();</cl-cd>
<cl-cd data-idx="37">};</cl-cd>
<cl-cd data-idx="38"> </cl-cd>
<cl-cd data-idx="39">draw5star();</cl-cd>
<cl-cd data-idx="40"> </cl-cd>
<cl-cd data-idx="41"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<script>
var ctx = canv.getContext('2d');
var size = canv.width / 2, r1 = size - 10, r2 = r1 * 2/5, points = [];
for(var i = 0; i < 5; i ++) {
var x1 = Math.cos((18 + i * 72) / 180 * Math.PI) * r1 + size,
y1 = -Math.sin((18 + i * 72) / 180 * Math.PI) * r1 + size,
x2 = Math.cos((54 + i * 72) / 180 * Math.PI) * r2 + size,
y2 = -Math.sin((54 + i * 72) / 180 * Math.PI) * r2 + size;
points.push({x1: x1, y1: y1, x2: x2, y2: y2});
}
var drawTriangle = () => {
for(var j = 0; j < 5; j++) {
ctx.beginPath();
ctx.moveTo(points.x1, points.y1);
ctx.lineTo(size, size);
ctx.lineTo(points.x2, points.y2);
ctx.lineTo(points.x1, points.y1);
ctx.fill();
}
};
var draw5star = () => {
ctx.fillStyle = 'red';
drawTriangle();
ctx.save();
ctx.fillStyle = 'darkred';
ctx.translate(size, size);
ctx.scale(-1, 1);
ctx.translate(-size, -size);
drawTriangle();
ctx.restore();
};
draw5star();
</script>
本帖最后由 马黑黑 于 2024-5-2 21:56 编辑
思路:
(一)获取内、外圆五个角的xy坐标,以对象形式存入变量 points 数组中(代码 8~14行);
(二)绘制三角形:连接 {x1, y2} → {cx, cy} → {x2, y2} → {x1, y1},其中 cx、cy 为圆心点坐标。这将绘制出正五角星第一个角柱的一半,循环绘制后得出整体正五角星的一半(代码 16~25行);
(三)调用绘制三角形函数,绘制好正五角星的一半之后,位移、变换(scale)画布坐标系再画另一半,得出完整正五角星(代码 27~37行)。
其它细节:
① 第 6 行代码声明了一系列变量:
var size = canv.width / 2, r1 = size - 10, r2 = r1 * 2/5, points = [];
size 是画布宽度的一半,因为画布宽高一样,所以,变量 szie 极为圆形 {cx, cy} 坐标值;
r1 是外圆半径,size - 10 是为了让绘制的图像不顶到边缘。r2 是内圆半径,按照 5:2 的比例取 r1 的值;
points 数组变量用于存储各叫的坐标值。
② 函数 drawTriangle() 用于绘制三角形:脚本将正五角星拆分为 10 个三角形,以顶角为例说明如下:顶角至圆心,分左边、右边两个三角形,每一次绘制只其中的一个。
③ 函数 draw5star() 调用 函数 drawTriangle(),分两次绘制正五角星的每一个角柱的左右边,具体画法是先循环绘制其中的一半,再通过移位、变换坐标系画另一半,两次绘制使用不同的颜色填充以营造立体感。
声明:本画法为原创,但不知其中是否存在错误或不妥。
电脑预览立体五角星,立体感特别强 黑黑新的花样层出不穷 小辣椒 发表于 2024-5-2 21:36
电脑预览立体五角星,立体感特别强
是的吧? 小辣椒 发表于 2024-5-2 21:37
黑黑新的花样层出不穷
动动脑而已 马黑黑 发表于 2024-5-2 21:42
是的吧?
非常美,颜色配的特别好 小辣椒 发表于 2024-5-2 21:46
非常美,颜色配的特别好
这是标准配色 这个五角星真漂亮! 这个设置了r1r2,知道长宽就直接能算出各点坐标了,然后用循环,得到不同颜色的另一半,非常简洁完美{:4_199:} 前面那个的画法不经过圆心,无论是传统的还是黑黑的一笔画,都是保证能呈现五角星的形状。
这个通过圆心并让每个相邻小三角颜色不同,可以得到立体的了,真的很有立体感呢{:4_199:} 红影 发表于 2024-5-2 22:23
前面那个的画法不经过圆心,无论是传统的还是黑黑的一笔画,都是保证能呈现五角星的形状。
这个通过圆心并 ...
这是画复杂形态五角星的较为简洁的方法了吧?做一楼这个效果之前(知道现在),我没看过任何其他的实现源码,但我想比我这个做法更简洁的可能很难找到 亚伦影音工作室 发表于 2024-5-2 22:06
这个五角星真漂亮!
晚上好 红影 发表于 2024-5-2 22:13
这个设置了r1r2,知道长宽就直接能算出各点坐标了,然后用循环,得到不同颜色的另一半,非常简洁完美{:4_19 ...
实际上需要的全局参数就是画布的尺寸和外圆的半径设定,其他的参数都在此基础上得出,例如内圆半径是外圆半径的2/5,75度是五等分的角度值、18和 18+36+54 是角度修正值 马黑黑 发表于 2024-5-2 23:24
这是画复杂形态五角星的较为简洁的方法了吧?做一楼这个效果之前(知道现在),我没看过任何其他的实现源 ...
我想大多数是画5个一边的赋予颜色,然后画5个另一边的另给颜色的吧,你的这个另一半同步就完成了。{:4_187:} 马黑黑 发表于 2024-5-2 23:29
实际上需要的全局参数就是画布的尺寸和外圆的半径设定,其他的参数都在此基础上得出,例如内圆半径是外圆 ...
是的,你这样一设置,让代码修改五角星大小变得十分方便了。 红影 发表于 2024-5-3 10:15
我想大多数是画5个一边的赋予颜色,然后画5个另一边的另给颜色的吧,你的这个另一半同步就完成了。{:4_18 ...
画的流程也是先画每个角柱的左半部,着色,再画右半部,着色 红影 发表于 2024-5-3 10:17
是的,你这样一设置,让代码修改五角星大小变得十分方便了。
这些就是简单的算法 马黑黑 发表于 2024-5-2 21:41
思路:
(一)获取内、外圆五个角的xy坐标,以对象形式存入变量 points 数组中(代码 8~14行);
立体的效果这么好,错误肯定是不存在的{:4_187:} {:4_170:}我看加个之前的粒子就是八一电影制片厂片头,就动手整一个
页:
[1]
2