马黑黑 发表于 2024-5-9 12:22

canvas画布:绘制旋转的五角星

<h2>效果</h2>
<canvas id="canv" width="400" height="400"></canvas>

<script>

var mov = true, raf = null;
var ctx = canv.getContext('2d');

class fiveStar {
        constructor(cx,cy,r,fillcolor='yellow',strokecolor='red') {
                this.cx = cx;
                this.cy = cy;
                this.r = r;
                this.points = [];
                this.keys = ;
                this.fillcolor = fillcolor;
                this.strokecolor = strokecolor;
                this.deg = 0;
        };
        create() {
                for(let i = 0; i < 5; i ++) {
                        var x = this.cx + this.r * Math.cos((72 * i - this.deg) * Math.PI/180),
                                y = this.cy + this.r * Math.sin((72 * i - this.deg) * Math.PI/180);
                        this.points.push({x: x, y: y});
                }
        };
        draw() {
                ctx.beginPath();
                this.points.forEach((_,key) => ctx.lineTo(this.points].x, this.points].y));
                ctx.closePath();
                ctx.lineWidth = 3;
                ctx.strokeStyle = this.strokecolor;
                ctx.fillStyle = this.fillcolor;
                ctx.stroke();
                ctx.fill();
        };
        rot() {
                this.deg = (this.deg + 0.5) % 360;
                ctx.save();
                ctx.translate(this.cx, this.cy);
                ctx.rotate(this.deg * Math.PI / 180);
                ctx.translate(-this.cx, -this.cy);
                star.draw();
                ctx.restore();
        };
};

var star = new fiveStar(200,200, 180);
star.create();

var render = () => {
        if (mov) raf = requestAnimationFrame(render);
                else cancelAnimationFrame(raf);
        ctx.clearRect(0, 0, canv.width, canv.height);
        star.rot();
};

render();

canv.onclick = () => {
        mov = !mov;
        render();
};

</script>

马黑黑 发表于 2024-5-9 12:23

<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>
<div class='mum'>
<cl-cd data-idx="1">&lt;<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>&gt;&lt;<span class="tDarkRed">/canvas</span>&gt;</cl-cd>
<cl-cd data-idx="2"> </cl-cd>
<cl-cd data-idx="3">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="4">&nbsp;</cl-cd>
<cl-cd data-idx="5"><span class="tBlue">var</span> mov = true, raf = null;</cl-cd>
<cl-cd data-idx="6"><span class="tBlue">var</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="7">&nbsp;</cl-cd>
<cl-cd data-idx="8"><span class="tBlue">class </span>fiveStar {</cl-cd>
<cl-cd data-idx="9">&nbsp; &nbsp; constructor(cx,cy,r,fillcolor=<span class="tMagenta">'yellow'</span>,strokecolor=<span class="tMagenta">'red'</span>) {</cl-cd>
<cl-cd data-idx="10">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.cx = cx;</cl-cd>
<cl-cd data-idx="11">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.cy = cy;</cl-cd>
<cl-cd data-idx="12">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.r = r;</cl-cd>
<cl-cd data-idx="13">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.points = [];</cl-cd>
<cl-cd data-idx="14">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.keys = ;</cl-cd>
<cl-cd data-idx="15">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.fillcolor = fillcolor;</cl-cd>
<cl-cd data-idx="16">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.strokecolor = strokecolor;</cl-cd>
<cl-cd data-idx="17">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.deg = 0;</cl-cd>
<cl-cd data-idx="18">&nbsp; &nbsp; };</cl-cd>
<cl-cd data-idx="19">&nbsp; &nbsp; create() {</cl-cd>
<cl-cd data-idx="20">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i &lt; 5; i ++) {</cl-cd>
<cl-cd data-idx="21">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">var</span> x = <span class="tBlue">this</span>.cx + <span class="tBlue">this</span>.r * <span class="tRed">Math</span>.cos((72 * i - <span class="tBlue">this</span>.deg) * <span class="tRed">Math</span>.PI/180),</cl-cd>
<cl-cd data-idx="22">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y = <span class="tBlue">this</span>.cy + <span class="tBlue">this</span>.r * <span class="tRed">Math</span>.sin((72 * i - <span class="tBlue">this</span>.deg) * <span class="tRed">Math</span>.PI/180);</cl-cd>
<cl-cd data-idx="23">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.points.push({<span class="tBlue">x:</span> x, <span class="tBlue">y:</span> y});</cl-cd>
<cl-cd data-idx="24">&nbsp; &nbsp; &nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="25">&nbsp; &nbsp; };</cl-cd>
<cl-cd data-idx="26">&nbsp; &nbsp; draw() {</cl-cd>
<cl-cd data-idx="27">&nbsp; &nbsp; &nbsp; &nbsp; ctx.beginPath();</cl-cd>
<cl-cd data-idx="28">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.points.forEach((_,key) =&gt; ctx.lineTo(<span class="tBlue">this</span>.points[<span class="tBlue">this</span>.keys].x, <span class="tBlue">this</span>.points[<span class="tBlue">this</span>.keys].y));</cl-cd>
<cl-cd data-idx="29">&nbsp; &nbsp; &nbsp; &nbsp; ctx.closePath();</cl-cd>
<cl-cd data-idx="30">&nbsp; &nbsp; &nbsp; &nbsp; ctx.lineWidth = 3;</cl-cd>
<cl-cd data-idx="31">&nbsp; &nbsp; &nbsp; &nbsp; ctx.strokeStyle = <span class="tBlue">this</span>.strokecolor;</cl-cd>
<cl-cd data-idx="32">&nbsp; &nbsp; &nbsp; &nbsp; ctx.fillStyle = <span class="tBlue">this</span>.fillcolor;</cl-cd>
<cl-cd data-idx="33">&nbsp; &nbsp; &nbsp; &nbsp; ctx.stroke();</cl-cd>
<cl-cd data-idx="34">&nbsp; &nbsp; &nbsp; &nbsp; ctx.fill();</cl-cd>
<cl-cd data-idx="35">&nbsp; &nbsp; };</cl-cd>
<cl-cd data-idx="36">&nbsp; &nbsp; rot() {</cl-cd>
<cl-cd data-idx="37">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">this</span>.deg = (<span class="tBlue">this</span>.deg + 0.5) % 360;</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; &nbsp; &nbsp; ctx.save();</cl-cd>
<cl-cd data-idx="39">&nbsp; &nbsp; &nbsp; &nbsp; ctx.translate(<span class="tBlue">this</span>.cx, <span class="tBlue">this</span>.cy);</cl-cd>
<cl-cd data-idx="40">&nbsp; &nbsp; &nbsp; &nbsp; ctx.rotate(<span class="tBlue">this</span>.deg * <span class="tRed">Math</span>.PI / 180);</cl-cd>
<cl-cd data-idx="41">&nbsp; &nbsp; &nbsp; &nbsp; ctx.translate(-<span class="tBlue">this</span>.cx, -<span class="tBlue">this</span>.cy);</cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; &nbsp; &nbsp; star.draw();</cl-cd>
<cl-cd data-idx="43">&nbsp; &nbsp; &nbsp; &nbsp; ctx.restore();</cl-cd>
<cl-cd data-idx="44">&nbsp; &nbsp; };</cl-cd>
<cl-cd data-idx="45">};</cl-cd>
<cl-cd data-idx="46">&nbsp;</cl-cd>
<cl-cd data-idx="47"><span class="tBlue">var</span> star = <span class="tBlue">new</span> fiveStar(200,200, 180);</cl-cd>
<cl-cd data-idx="48">star.create();</cl-cd>
<cl-cd data-idx="49">&nbsp;</cl-cd>
<cl-cd data-idx="50"><span class="tBlue">var</span> render = () =&gt; {</cl-cd>
<cl-cd data-idx="51">&nbsp; &nbsp; <span class="tBlue">if</span> (mov) raf = requestAnimationFrame(render);</cl-cd>
<cl-cd data-idx="52">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">else</span> cancelAnimationFrame(raf);</cl-cd>
<cl-cd data-idx="53">&nbsp; &nbsp; ctx.clearRect(0, 0, canv.width, canv.height);</cl-cd>
<cl-cd data-idx="54">&nbsp; &nbsp; star.rot();</cl-cd>
<cl-cd data-idx="55">};</cl-cd>
<cl-cd data-idx="56">&nbsp;</cl-cd>
<cl-cd data-idx="57">render();</cl-cd>
<cl-cd data-idx="58">&nbsp;</cl-cd>
<cl-cd data-idx="59">canv.onclick = () =&gt; {</cl-cd>
<cl-cd data-idx="60">&nbsp; &nbsp; mov = !mov;</cl-cd>
<cl-cd data-idx="61">&nbsp; &nbsp; render();</cl-cd>
<cl-cd data-idx="62">};</cl-cd>
<cl-cd data-idx="63">&nbsp;</cl-cd>
<cl-cd data-idx="64">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>

马黑黑 发表于 2024-5-9 12:23

本帖最后由 马黑黑 于 2024-5-9 12:57 编辑

本次绘制正五角星的方法,请参考:canvas画布绘制正五角星

以下是对二楼代码的简单解释——

第 5 行

    var mov = true, raf = null;

mov 变量是控制动画的布尔开关,raf 变量是 requestAnimationFrame API 执行返回值。当 mov 为真,requestAnimationFrame 将运行从而产生动画,否则,当 mov 为假,取消 raf。

第 8~45 行

首先声明一个 fiveStar 类,代表五角星。其中,通过构造函数 constructor() 构造五角星的一些常规属性:圆心坐标(cx, cy)、半径(r)、描边颜色和填充颜色(strokecolor、fillcolor)、顶点坐标值数组(points)、顶点连接序列(keys)、变化的角度变量(deg)。其中,cx、cy、r 为必选,即在实例化五角星时必须要给出的参数,其余属性为可选,即在实例化应用时可以配置或不配置这些参数。

接着给 fiveStar 这个类定义一些方法:

一是 create() :代码在 19~25 行,其作用是计算五角星的顶点坐标值并存储起来;

二是 draw() :代码在 26~35 行,功能是绘制五角星;

三是 rot() :代码在 36~44 行,这个方法在 360 度范围内变更 fiveStar 的 deg 变量(变更系数 0.5),更改画布坐标系,然后调用 draw 方法绘制五角星。

第 47~48 行

实例化 fiveStar 类,圆心坐标为(200,200)、半径为(180);调用类的方法 create() 生成一个五角星。

第 50~55 行

这是渲染函数:依据 mov 变量决定运行还是注销 requestAnimationFrame API,每次清空画布(如果不清空在本例效果也挺好的),然后调用类的 rot() 方法。

第 57 行首次启动动画

render();

第 59~62 行

画布点击事件:每次点击 mov 布尔变量值互反,并运行一下 render() 渲染函数,函数会根据 mov 的变量值决定是否渲染动画。

马黑黑 发表于 2024-5-9 13:07

当然,如果只是需要一个简单旋转的五角星功能,一楼的方法就显得劳民伤财了。我们可以只画一个静态的五角星,然后用 @keyframes 来驱动五角星的旋转。

红影 发表于 2024-5-9 16:49

不停重画五角星,肉眼看上去就是在转动了呢。这个厉害了{:4_204:}

红影 发表于 2024-5-9 16:52

这个把变更的角度调大,转动的速度就可以变快了吧。
这个转动还能点击暂停呢。学习了,黑黑辛苦{:4_199:}

马黑黑 发表于 2024-5-9 17:10

红影 发表于 2024-5-9 16:52
这个把变更的角度调大,转动的速度就可以变快了吧。
这个转动还能点击暂停呢。学习了,黑黑辛苦

手掌更辛苦{:4_170:}

南无月 发表于 2024-5-9 17:35

马黑黑 发表于 2024-5-9 12:23
本次绘制正五角星的方法,请参考:canvas画布绘制正五角星

以下是对二楼代码的简单解释——


好详细的解说,慢慢看{:4_199:}

南无月 发表于 2024-5-9 17:36

马黑黑 发表于 2024-5-9 13:07
当然,如果只是需要一个简单旋转的五角星功能,一楼的方法就显得劳民伤财了。我们可以只画一个静态的五角星 ...

{:4_199:}代码旋转的更加高级

马黑黑 发表于 2024-5-9 18:28

南无月 发表于 2024-5-9 17:36
代码旋转的更加高级

都是代码的

马黑黑 发表于 2024-5-9 18:29

南无月 发表于 2024-5-9 17:35
好详细的解说,慢慢看

看懂了木有

南无月 发表于 2024-5-9 19:53

马黑黑 发表于 2024-5-9 18:28
都是代码的

对噢。。
那叫做线条跑步旋转和驱动图片旋转。。{:4_173:}

南无月 发表于 2024-5-9 19:54

马黑黑 发表于 2024-5-9 18:29
看懂了木有

烧脑得很。{:4_203:}

马黑黑 发表于 2024-5-9 19:55

南无月 发表于 2024-5-9 19:53
对噢。。
那叫做线条跑步旋转和驱动图片旋转。。

哪有这种说法的?

区别在于:CSS更简单地实现了简单的动画,JS更复杂地实现了复杂的动画

马黑黑 发表于 2024-5-9 19:58

南无月 发表于 2024-5-9 19:54
烧脑得很。

按理,理解了时钟的实现原理,理解这个是三岁小盆友都可以的事情{:4_170:}

南无月 发表于 2024-5-9 20:01

马黑黑 发表于 2024-5-9 19:55
哪有这种说法的?

区别在于:CSS更简单地实现了简单的动画,JS更复杂地实现了复杂的动画

我说的形象,你说的专业。角度不同{:4_170:}

南无月 发表于 2024-5-9 20:03

马黑黑 发表于 2024-5-9 19:58
按理,理解了时钟的实现原理,理解这个是三岁小盆友都可以的事情

主要是这个三岁小盆友睡了十个小时有点少~~{:4_170:}

马黑黑 发表于 2024-5-9 20:07

南无月 发表于 2024-5-9 20:03
主要是这个三岁小盆友睡了十个小时有点少~~

嗯嗯,一般儿童睡眠的时间会在12个小时以上

南无月 发表于 2024-5-9 20:14

马黑黑 发表于 2024-5-9 20:07
嗯嗯,一般儿童睡眠的时间会在12个小时以上

这几天可烧脑了,所以动脑筋的事儿都变成灌水{:4_170:}

马黑黑 发表于 2024-5-9 20:20

南无月 发表于 2024-5-9 20:14
这几天可烧脑了,所以动脑筋的事儿都变成灌水

也挺好
页: [1] 2
查看完整版本: canvas画布:绘制旋转的五角星