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>
<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"><<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> 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"> </cl-cd>
<cl-cd data-idx="8"><span class="tBlue">class </span>fiveStar {</cl-cd>
<cl-cd data-idx="9"> constructor(cx,cy,r,fillcolor=<span class="tMagenta">'yellow'</span>,strokecolor=<span class="tMagenta">'red'</span>) {</cl-cd>
<cl-cd data-idx="10"> <span class="tBlue">this</span>.cx = cx;</cl-cd>
<cl-cd data-idx="11"> <span class="tBlue">this</span>.cy = cy;</cl-cd>
<cl-cd data-idx="12"> <span class="tBlue">this</span>.r = r;</cl-cd>
<cl-cd data-idx="13"> <span class="tBlue">this</span>.points = [];</cl-cd>
<cl-cd data-idx="14"> <span class="tBlue">this</span>.keys = ;</cl-cd>
<cl-cd data-idx="15"> <span class="tBlue">this</span>.fillcolor = fillcolor;</cl-cd>
<cl-cd data-idx="16"> <span class="tBlue">this</span>.strokecolor = strokecolor;</cl-cd>
<cl-cd data-idx="17"> <span class="tBlue">this</span>.deg = 0;</cl-cd>
<cl-cd data-idx="18"> };</cl-cd>
<cl-cd data-idx="19"> create() {</cl-cd>
<cl-cd data-idx="20"> <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i < 5; i ++) {</cl-cd>
<cl-cd data-idx="21"> <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"> 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"> <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"> }</cl-cd>
<cl-cd data-idx="25"> };</cl-cd>
<cl-cd data-idx="26"> draw() {</cl-cd>
<cl-cd data-idx="27"> ctx.beginPath();</cl-cd>
<cl-cd data-idx="28"> <span class="tBlue">this</span>.points.forEach((_,key) => 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"> ctx.closePath();</cl-cd>
<cl-cd data-idx="30"> ctx.lineWidth = 3;</cl-cd>
<cl-cd data-idx="31"> ctx.strokeStyle = <span class="tBlue">this</span>.strokecolor;</cl-cd>
<cl-cd data-idx="32"> ctx.fillStyle = <span class="tBlue">this</span>.fillcolor;</cl-cd>
<cl-cd data-idx="33"> ctx.stroke();</cl-cd>
<cl-cd data-idx="34"> ctx.fill();</cl-cd>
<cl-cd data-idx="35"> };</cl-cd>
<cl-cd data-idx="36"> rot() {</cl-cd>
<cl-cd data-idx="37"> <span class="tBlue">this</span>.deg = (<span class="tBlue">this</span>.deg + 0.5) % 360;</cl-cd>
<cl-cd data-idx="38"> ctx.save();</cl-cd>
<cl-cd data-idx="39"> ctx.translate(<span class="tBlue">this</span>.cx, <span class="tBlue">this</span>.cy);</cl-cd>
<cl-cd data-idx="40"> ctx.rotate(<span class="tBlue">this</span>.deg * <span class="tRed">Math</span>.PI / 180);</cl-cd>
<cl-cd data-idx="41"> ctx.translate(-<span class="tBlue">this</span>.cx, -<span class="tBlue">this</span>.cy);</cl-cd>
<cl-cd data-idx="42"> star.draw();</cl-cd>
<cl-cd data-idx="43"> ctx.restore();</cl-cd>
<cl-cd data-idx="44"> };</cl-cd>
<cl-cd data-idx="45">};</cl-cd>
<cl-cd data-idx="46"> </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"> </cl-cd>
<cl-cd data-idx="50"><span class="tBlue">var</span> render = () => {</cl-cd>
<cl-cd data-idx="51"> <span class="tBlue">if</span> (mov) raf = requestAnimationFrame(render);</cl-cd>
<cl-cd data-idx="52"> <span class="tBlue">else</span> cancelAnimationFrame(raf);</cl-cd>
<cl-cd data-idx="53"> ctx.clearRect(0, 0, canv.width, canv.height);</cl-cd>
<cl-cd data-idx="54"> star.rot();</cl-cd>
<cl-cd data-idx="55">};</cl-cd>
<cl-cd data-idx="56"> </cl-cd>
<cl-cd data-idx="57">render();</cl-cd>
<cl-cd data-idx="58"> </cl-cd>
<cl-cd data-idx="59">canv.onclick = () => {</cl-cd>
<cl-cd data-idx="60"> mov = !mov;</cl-cd>
<cl-cd data-idx="61"> render();</cl-cd>
<cl-cd data-idx="62">};</cl-cd>
<cl-cd data-idx="63"> </cl-cd>
<cl-cd data-idx="64"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
本帖最后由 马黑黑 于 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 的变量值决定是否渲染动画。
当然,如果只是需要一个简单旋转的五角星功能,一楼的方法就显得劳民伤财了。我们可以只画一个静态的五角星,然后用 @keyframes 来驱动五角星的旋转。 不停重画五角星,肉眼看上去就是在转动了呢。这个厉害了{:4_204:} 这个把变更的角度调大,转动的速度就可以变快了吧。
这个转动还能点击暂停呢。学习了,黑黑辛苦{:4_199:} 红影 发表于 2024-5-9 16:52
这个把变更的角度调大,转动的速度就可以变快了吧。
这个转动还能点击暂停呢。学习了,黑黑辛苦
手掌更辛苦{:4_170:} 马黑黑 发表于 2024-5-9 12:23
本次绘制正五角星的方法,请参考:canvas画布绘制正五角星
以下是对二楼代码的简单解释——
好详细的解说,慢慢看{:4_199:} 马黑黑 发表于 2024-5-9 13:07
当然,如果只是需要一个简单旋转的五角星功能,一楼的方法就显得劳民伤财了。我们可以只画一个静态的五角星 ...
{:4_199:}代码旋转的更加高级 南无月 发表于 2024-5-9 17:36
代码旋转的更加高级
都是代码的 南无月 发表于 2024-5-9 17:35
好详细的解说,慢慢看
看懂了木有 马黑黑 发表于 2024-5-9 18:28
都是代码的
对噢。。
那叫做线条跑步旋转和驱动图片旋转。。{:4_173:} 马黑黑 发表于 2024-5-9 18:29
看懂了木有
烧脑得很。{:4_203:} 南无月 发表于 2024-5-9 19:53
对噢。。
那叫做线条跑步旋转和驱动图片旋转。。
哪有这种说法的?
区别在于:CSS更简单地实现了简单的动画,JS更复杂地实现了复杂的动画 南无月 发表于 2024-5-9 19:54
烧脑得很。
按理,理解了时钟的实现原理,理解这个是三岁小盆友都可以的事情{:4_170:} 马黑黑 发表于 2024-5-9 19:55
哪有这种说法的?
区别在于:CSS更简单地实现了简单的动画,JS更复杂地实现了复杂的动画
我说的形象,你说的专业。角度不同{:4_170:} 马黑黑 发表于 2024-5-9 19:58
按理,理解了时钟的实现原理,理解这个是三岁小盆友都可以的事情
主要是这个三岁小盆友睡了十个小时有点少~~{:4_170:}
南无月 发表于 2024-5-9 20:03
主要是这个三岁小盆友睡了十个小时有点少~~
嗯嗯,一般儿童睡眠的时间会在12个小时以上 马黑黑 发表于 2024-5-9 20:07
嗯嗯,一般儿童睡眠的时间会在12个小时以上
这几天可烧脑了,所以动脑筋的事儿都变成灌水{:4_170:} 南无月 发表于 2024-5-9 20:14
这几天可烧脑了,所以动脑筋的事儿都变成灌水
也挺好
页:
[1]
2