canvas画布绘制钟摆
本帖最后由 马黑黑 于 2024-5-19 17:22 编辑 <br /><br /><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; }
#pdcanv { display: block; margin: 20px auto; }
</style>
<h2>效果:</h2>
<canvas id="pdcanv" width="600" height="240"></canvas>
<h2>代码:</h2>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"pdcanv"</span> width=<span class="tMagenta">"600"</span> height=<span class="tMagenta">"240"</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> pdCtx = pdcanv.getContext(<span class="tMagenta">'2d'</span>); <span class="tGreen">//画笔</span></cl-cd>
<cl-cd data-idx="6"> </cl-cd>
<cl-cd data-idx="7"><span class="tGreen">//创建钟摆的类</span></cl-cd>
<cl-cd data-idx="8"><span class="tBlue">class </span>Pendulum {</cl-cd>
<div class="tGreen"><cl-cd data-idx="9"> /* 构造函数</cl-cd>
<cl-cd data-idx="10"> ctx : 画笔</cl-cd>
<cl-cd data-idx="11"> line : 配置对象,格式为 { <span class="tBlue">x:</span> x, <span class="tBlue">y:</span> y, <span class="tBlue">len:</span> len, <span class="tBlue">vx:</span> vx, <span class="tBlue">speed:</span> speed }</cl-cd>
<cl-cd data-idx="12"> */</cl-cd></div>
<cl-cd data-idx="13"> constructor(ctx,line) {</cl-cd>
<cl-cd data-idx="14"> <span class="tBlue">this</span>.ctx = ctx;</cl-cd>
<cl-cd data-idx="15"> <span class="tBlue">this</span>.line = line;</cl-cd>
<cl-cd data-idx="16"> };</cl-cd>
<cl-cd data-idx="17"> </cl-cd>
<cl-cd data-idx="18"> <span class="tGreen">//draw方法 : 绘制静态钟摆</span></cl-cd>
<cl-cd data-idx="19"> draw() {</cl-cd>
<div class="tGreen"><cl-cd data-idx="20"> /* x1、y1是线段底端XY坐标也是摆锤圆心坐标</cl-cd>
<cl-cd data-idx="21"> x1 等于顶端 x + 摆幅(即vx)</cl-cd>
<cl-cd data-idx="22"> y1 等于,根据长度 len 和 x1 用勾股定理计算出来</cl-cd>
<cl-cd data-idx="23"> */</cl-cd></div>
<cl-cd data-idx="24"> <span class="tBlue">var</span> x1 = <span class="tBlue">this</span>.line.x + <span class="tBlue">this</span>.line.vx;</cl-cd>
<cl-cd data-idx="25"> <span class="tBlue">var</span> y1 = <span class="tRed">Math</span>.sqrt(<span class="tBlue">this</span>.line.len ** 2 - (x1 - <span class="tBlue">this</span>.line.x) ** 2);</cl-cd>
<cl-cd data-idx="26"> <span class="tGreen">//画线</span></cl-cd>
<cl-cd data-idx="27"> <span class="tBlue">this</span>.ctx.beginPath();</cl-cd>
<cl-cd data-idx="28"> <span class="tBlue">this</span>.ctx.fillStyle = <span class="tBlue">this</span>.ctx.strokeStyle = <span class="tMagenta">'plum'</span>;</cl-cd>
<cl-cd data-idx="29"> <span class="tBlue">this</span>.ctx.lineWidth = 2;</cl-cd>
<cl-cd data-idx="30"> <span class="tBlue">this</span>.ctx.moveTo(<span class="tBlue">this</span>.line.x, <span class="tBlue">this</span>.line.y);</cl-cd>
<cl-cd data-idx="31"> <span class="tBlue">this</span>.ctx.lineTo(x1, y1);</cl-cd>
<cl-cd data-idx="32"> <span class="tBlue">this</span>.ctx.stroke();</cl-cd>
<cl-cd data-idx="33"> <span class="tGreen">//画圆</span></cl-cd>
<cl-cd data-idx="34"> <span class="tBlue">this</span>.ctx.beginPath();</cl-cd>
<cl-cd data-idx="35"> <span class="tBlue">this</span>.ctx.arc(x1, y1, 20, 0, 2*<span class="tRed">Math</span>.PI);</cl-cd>
<cl-cd data-idx="36"> <span class="tBlue">this</span>.ctx.fill();</cl-cd>
<cl-cd data-idx="37"> };</cl-cd>
<cl-cd data-idx="38"> <span class="tGreen">//update 方法 : 改变摆幅 vx 并调用 draw 静态绘制方法</span></cl-cd>
<cl-cd data-idx="39"> update() {</cl-cd>
<cl-cd data-idx="40"> <span class="tBlue">this</span>.draw();</cl-cd>
<cl-cd data-idx="41"> <span class="tBlue">this</span>.line.vx += <span class="tBlue">this</span>.line.speed; <span class="tGreen">//改变摆幅</span></cl-cd>
<cl-cd data-idx="42"> <span class="tGreen">//水平方向摆动幅度不超过 ±30</span></cl-cd>
<cl-cd data-idx="43"> <span class="tBlue">if</span> (<span class="tRed">Math</span>.abs(<span class="tBlue">this</span>.line.vx) >= 30) <span class="tBlue">this</span>.line.speed = -<span class="tBlue">this</span>.line.speed;</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="tGreen">//配置钟摆 : 顶端XY坐标、长度、摆幅、速度</span></cl-cd>
<cl-cd data-idx="48"><span class="tBlue">var</span> option = { <span class="tBlue">x:</span> 300, <span class="tBlue">y:</span> 10, <span class="tBlue">len:</span> 200, <span class="tBlue">vx:</span> 0, <span class="tBlue">speed:</span> 1 };</cl-cd>
<cl-cd data-idx="49"><span class="tGreen">//创建钟摆类实例(参数两个 : 画笔、配置)</span></cl-cd>
<cl-cd data-idx="50"><span class="tBlue">var</span> pd = <span class="tBlue">new</span> Pendulum(pdCtx, option);</cl-cd>
<cl-cd data-idx="51"> </cl-cd>
<cl-cd data-idx="52"><span class="tGreen">//渲染函数</span></cl-cd>
<cl-cd data-idx="53"><span class="tBlue">var</span> render = () => {</cl-cd>
<cl-cd data-idx="54"> pdCtx.clearRect(0, 0, pdcanv.width, pdcanv.height);</cl-cd>
<cl-cd data-idx="55"> pd.update(); <span class="tGreen">//调用类的 update 方法</span></cl-cd>
<cl-cd data-idx="56"> requestAnimationFrame(render);</cl-cd>
<cl-cd data-idx="57">};</cl-cd>
<cl-cd data-idx="58"> </cl-cd>
<cl-cd data-idx="59">render(); <span class="tGreen">//启动渲染</span></cl-cd>
<cl-cd data-idx="60"> </cl-cd>
<cl-cd data-idx="61"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<script>
var pdCtx = pdcanv.getContext('2d');
class Pendulum {
constructor(ctx,line) {
this.ctx = ctx;
this.line = line;
};
draw() {
var x1 = this.line.x + this.line.vx;
var y1 = Math.sqrt(this.line.len ** 2 - (x1 - this.line.x) ** 2);
this.ctx.beginPath();
this.ctx.fillStyle = this.ctx.strokeStyle = 'plum';
this.ctx.lineWidth = 2;
this.ctx.moveTo(this.line.x, this.line.y);
this.ctx.lineTo(x1, y1);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.arc(x1, y1, 20, 0, 2*Math.PI);
this.ctx.fill();
};
update() {
this.draw();
this.line.vx += this.line.speed;
if (Math.abs(this.line.vx) >= 30) this.line.speed = -this.line.speed;
};
};
var option = { x: 300, y: 10, len: 200, vx: 0, speed: 1 };
var pd = new Pendulum(pdCtx, option);
var render = () => {
pdCtx.clearRect(0, 0, pdcanv.width, pdcanv.height);
pd.update();
requestAnimationFrame(render);
};
render();
</script>
这个讲解特别详细,canvas制作的小摆钟真漂亮{:4_199:} 这看不出y值的变化,如果摆幅大点,应该就能看出了{:4_173:} 红影 发表于 2024-5-19 14:38
这看不出y值的变化,如果摆幅大点,应该就能看出了
理论上应该看得出来的吧?
摆动过程中,y1坐标最大值可以等于 len + y 的初始值即钟摆几长度+顶端Y坐标值,最小值可以等于 y 的初始值。此例,当 y1 = y 时,x1 = ±x 红影 发表于 2024-5-19 14:36
这个讲解特别详细,canvas制作的小摆钟真漂亮
也不知道有木有错误,反正又不是不能摆{:4_170:} 马黑黑 发表于 2024-5-19 16:16
理论上应该看得出来的吧?
摆动过程中,y1坐标最大值可以等于 len + y 的初始值即钟摆几长度+顶端Y坐 ...
是的,理论上是可以看出来的{:4_187:} 马黑黑 发表于 2024-5-19 16:17
也不知道有木有错误,反正又不是不能摆
是啊,能正常摆起来就好{:4_173:} 红影 发表于 2024-5-19 17:21
是的,理论上是可以看出来的
对的。先抽象,再具化。 红影 发表于 2024-5-19 17:21
是啊,能正常摆起来就好
没错 马黑黑 发表于 2024-5-19 17:21
对的。先抽象,再具化。
具化就是把它摆到水平么{:4_173:} 马黑黑 发表于 2024-5-19 17:23
没错
目前看起来没问题呢{:4_187:} 红影 发表于 2024-5-19 18:40
目前看起来没问题呢
没问题就是问题大了{:4_170:} 红影 发表于 2024-5-19 18:40
具化就是把它摆到水平么
好比你做设计,如果你是优秀的设计师,你首先是从抽象开始你的工作:构思、算法的准备等等,无一不是先在大脑中有一个相对抽象的、不确切的思路,然后,逐一落实到图纸、计划书上,最后,具象化为产品。 马黑黑 发表于 2024-5-19 19:30
没问题就是问题大了
这叫什么逻辑{:4_173:} 马黑黑 发表于 2024-5-19 19:34
好比你做设计,如果你是优秀的设计师,你首先是从抽象开始你的工作:构思、算法的准备等等,无一不是先在 ...
黑黑就是这样实现设计的吧,这个结果很棒{:4_187:} 看到这个教程想到了三体里的大钟摆。。。{:4_173:}
南无月 发表于 2024-5-19 22:43
看到这个教程想到了三体里的大钟摆。。。
{:4_203:} 红影 发表于 2024-5-19 21:23
黑黑就是这样实现设计的吧,这个结果很棒
这个是常规过程吧,当然俺不会写计划书{:4_170:} 红影 发表于 2024-5-19 21:20
这叫什么逻辑
正确的逻辑 马黑黑 发表于 2024-5-19 22:55
这个是常规过程吧,当然俺不会写计划书
那就不能算设计师的事,应该大都事件的策划都如此呢。