马黑黑 发表于 2024-3-25 08:15

做一个canvas时钟(五)

<style>
.mama { font: normal 18px / 26px sans-serif; }
.mama p { margin: 12px 0; }
.mama mark { padding: 0 6px; background: lightblue; }
.wrap { margin: 20px auto 0; text-align: center; }
#canv, #canv1 { border: 1px solid gray; }

.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>

<div class="mama">

<p>时钟少不了刻度,我们打算用小圆点来模拟刻度,每分钟一个刻度标志,让60个小圆点均匀分布在钟盘的边缘、或嵌入时钟的外壳或与外壳保持一定距离,我们选择后者。前面的课程我们编写了一个画圆的函数,我们还是用它来画这60个小圆点,不同的是,我们还需要将这些小圆点安排到钟盘的边缘。这需要一些算法,辅之以一个 for 循环语句便可完成:</p>

<div class='mum'>
<cl-cd data-idx="1"><span class="tGreen">/* 绘制 60 个小圆点刻度 */</span></cl-cd>
<cl-cd data-idx="2"><span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i &lt; 60; i ++) {</cl-cd>
<cl-cd data-idx="3">&nbsp; &nbsp; <span class="tBlue">let</span> radian = <span class="tRed">Math</span>.PI/180*(i*6);</cl-cd>
<cl-cd data-idx="4">&nbsp; &nbsp; <span class="tBlue">let</span> x = 150 + 130 * <span class="tRed">Math</span>.cos(radian), y = 150 + 130 * <span class="tRed">Math</span>.sin(radian);</cl-cd>
<cl-cd data-idx="5">&nbsp; &nbsp; draw_circle(x,y,1,2,<span class="tMagenta">'gray'</span>,<span class="tMagenta">'gray'</span>);</cl-cd>
<cl-cd data-idx="6">}</cl-cd>
</div>

<p>解释一下代码:for(...) {...} 是一个循环语句。先理解小括号里的内容:i 是一个循环次序变量,它从 0 开始;在它 < 60 这个条件下,花括号里的语句都将得到执行;i ++ 表示 i 是一个自增变量,每循环完一次自己 + 1,这样 i < 60 才会有结束的时候,要不然for语句就是死循环了。再来理解花括号里的语句,首先我们声明一个变量 radian,弧度变量,这个变量的赋值是计算当下准备绘制的圆点相对于它所在坐标系中心的弧度,这个圆点偏移坐标系原点(0,0)一定角度,我们需要将角度变为弧度,之前的章节提到过,从角度中求弧度的公式是<mark>Math.PI/180*角度</mark>,那么,第 i 个圆点就是第三行代码所表示的,即,<mark>Math.PI/180*(i*6);</mark>,其中 i*6 不必放在括号里,这里这么放是为了让大家明白:60个圆点均匀分布在圆周上时两个圆点间的平均偏移量是 6 度,在for循环中第 i 个圆点的角度乘以 i 才是它偏移坐标系原点的角度;其次,求小圆点在画布上的圆心XY坐标值。有了弧度,我们就可以利用三角函数公式算出圆点在圆周上的左上角XY坐标的xy值,公式为<mark>x = r*cos(弧度), y = r*sin(弧度)</mark>,其中 r 为圆的半径(圆指小圆点分布于其圆周上的那个大圆,这里可以看成是钟盘,不是指小圆点的半径)。这个用 JS 来表示,就是第四行代码<mark>let x = 150 + 130 * Math.cos(radian), y = 150 + 130 * Math.sin(radian);</mark>。这里为什么加150呢?因为我们画圆的函数使用HTML坐标系,没有对画布做坐标系移位,其原点位于画布的左上角(0,0),画出的小圆点只有四分之一显示在画布里,所以小圆点的圆心xy坐标位置要加上画布宽、高各一半才能推送到我们期望的钟盘的圆周上;准备就绪,接着可以真正绘制小圆点了,第五行代码,<mark>draw_circle(x,y,1,2,'gray','gray');</mark>,其中:xy参数是刚刚计算出来的第 i 个小圆点的左上角坐标值,1 是小圆点的半径,2 是小圆点的边框线宽,后两个 'gray' 是填充色和描边色,这样画出来的小圆点其实就是直径为6像素的实心圆。效果如下:</p>

<div class="wrap"><canvas id="canv1" width="300" height="300"></canvas></div>

<p>指针的颜色和前面的有所不同,事实上,一些细节也相应做了调整,毕竟时钟的部件越来越多,彼此间需要相互照应,打磨过程中修改一些细节内容不可避免,这里就不一一说明了。</p>
<p>现在,需要给钟盘加上钟点标志,1~12的数字。这先得弄懂canvas画布怎样绘制文本,使用 <mark>drawText()</mark> 方法,语法如下:</p>
<blockquote><span class="tRed">ctx.drawText(text,x,y);</span><br><br>其中,参数 text 是要绘制的文本,x,y 是起始位置。绘制文本还涉及到文本样式的设置,<mark>ctx.font = 'bold 18px "宋体"';</mark>,采用的是CSS的 font 属性设置方法;文本的水平方向对齐方式,<mark>ctx.textAlign = 'center';</mark>,还是CSS方法,表示水平方向居中对齐;文本垂直方向对齐指的是基于文本基线,文本基线就像我们在这里见到的每一行文本一样都有一条虚拟的基线(默认在文本的底部),<mark>ctx.textBaseline = 'middle';</mark>,表示文本在垂直方向基于文本基线居中对齐,换句话说就是文本基线穿过每一个字的中心,这个设置对时钟的钟点标志有帮助,因为时钟钟点数字是环绕布局的;还有文本的填充颜色,<mark>ctx.fillStyle = 'red';</mark>,文本描边颜色,<mark>ctx.strokeStyle = 'green'</mark>;</mark>最后,文本若是以填充方式绘制,就用 <mark>ctx.fill();</mark>方法,若是以描边方式绘制就用<mark>ctx.stroke();</mark>方法绘制,假若既要描边又要填充就两种方法都用。必须注意,如果使用 stroke() 方法绘制文本会涉及到新路径的开辟,所以要在 stroke() 前先 <mark>ctx.beginPath();</mark>,以免被前面绘制操作中可能存在的路径干扰,fill() 方法没有这个要求。</blockquote>
<p>我们把文本绘制 drawText() 也封装成自定义函数,先看代码:</p>

<div class='mum'>
<cl-cd data-idx="1"><span class="tGreen">/* 函数 :绘制文本 */</span></cl-cd>
<cl-cd data-idx="2"><span class="tBlue">let</span> draw_text = (txt,x,y,color,fontsize=18,b=<span class="tMagenta">"bold"</span>) =&gt; {</cl-cd>
<cl-cd data-idx="3">&nbsp; &nbsp; ctx.save(); <span class="tGreen">/* 保存画布状态 */</span></cl-cd>
<cl-cd data-idx="4">&nbsp; &nbsp; ctx.translate(150,150); <span class="tGreen">/* 画布坐标系移动到画布的中心 */</span></cl-cd>
<cl-cd data-idx="5">&nbsp; &nbsp; ctx.font = `${b} ${fontsize}px sans-serif`; <span class="tGreen">/* 设置字体 */</span></cl-cd>
<cl-cd data-idx="6">&nbsp; &nbsp; ctx.textAlign = <span class="tMagenta">'center'</span>; <span class="tGreen">/* 文本水平居中 */</span></cl-cd>
<cl-cd data-idx="7">&nbsp; &nbsp; ctx.textBaseline=<span class="tMagenta">"middle"</span>; <span class="tGreen">/* 文本垂直方向在文本基线的中间 */</span></cl-cd>
<cl-cd data-idx="8">&nbsp; &nbsp; ctx.fillStyle = color; <span class="tGreen">/* 文本颜色(其实是画笔颜色) */</span></cl-cd>
<cl-cd data-idx="9">&nbsp; &nbsp; ctx.fillText(txt,x,y); <span class="tGreen">/* 填充文本 */</span></cl-cd>
<cl-cd data-idx="10">&nbsp; &nbsp; ctx.restore();</cl-cd>
<cl-cd data-idx="11">};</cl-cd>
</div>

<p>函数参数较多,所幸都遵循原始绘制函数的参数需求且其他参数都是语义化,并不难理解,其中,text 为要绘制的文本,x,y 为 文本绘制于何处的XY坐标,fontsize 和 b 两个参数可选,调用者不传值时使用函数定义的值,fontsize 是字体大小,默认等于18px,b 是粗体与否,默认粗体 bold。用这个函数绘制12个钟点标志,方法和绘制刻度小圆点基本相同,只是不加上画布坐标系的半径,因为函数已经转换了坐标系。可以在后面提供的代码体会。</p>
<p>以下是加上钟点数字标志之后的时钟效果,还顺带加上了产品的 Logo 以避免可能发生的不必要的产权纠纷。画布的边框我们不再设置,脚手架是时候撤走了:</p>

<div class="wrap"><canvas id="canv2" width="300" height="300"></canvas></div>

<p>最后给出上述效果的完整代码:</p>

<div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="2">&nbsp; &nbsp; .wrap { <span class="tBlue">margin-top:</span> 20px; <span class="tBlue">text-align:</span> center; }</cl-cd>
<cl-cd data-idx="3">&lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="4">&nbsp;</cl-cd>
<cl-cd data-idx="5">&lt;<span class="tDarkRed">div</span> class=<span class="tMagenta">"wrap"</span>&gt;&lt;<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span> width=<span class="tMagenta">"300"</span> height=<span class="tMagenta">"300"</span>&gt;&lt;<span class="tDarkRed">/canvas</span>&gt;&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
<cl-cd data-idx="6"> </cl-cd>
<cl-cd data-idx="7">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="8"><span class="tGreen">/* 获取画笔 */</span></cl-cd>
<cl-cd data-idx="9"><span class="tBlue">let</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="10">&nbsp;</cl-cd>
<cl-cd data-idx="11"><span class="tGreen">/* 函数 :绘制矩形(指针) */</span></cl-cd>
<cl-cd data-idx="12"><span class="tBlue">let</span> draw_rect = (x, y, w, h, rad, color) =&gt; {</cl-cd>
<cl-cd data-idx="13">    ctx.save();</cl-cd>
<cl-cd data-idx="14">    ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="15">    ctx.translate(150,150);</cl-cd>
<cl-cd data-idx="16">    ctx.rotate(rad);</cl-cd>
<cl-cd data-idx="17">    ctx.fillRect(x,y,w,h);</cl-cd>
<cl-cd data-idx="18">    ctx.restore();</cl-cd>
<cl-cd data-idx="19">};</cl-cd>
<cl-cd data-idx="20">&nbsp;</cl-cd>
<cl-cd data-idx="21"><span class="tGreen">/* 函数 :绘制圆(环) */</span></cl-cd>
<cl-cd data-idx="22"><span class="tBlue">let</span> draw_circle = (x,y,r,lw,color1,color2) =&gt; {</cl-cd>
<cl-cd data-idx="23">    ctx.save();</cl-cd>
<cl-cd data-idx="24">    ctx.fillStyle = color1;</cl-cd>
<cl-cd data-idx="25">    ctx.strokeStyle = color2;</cl-cd>
<cl-cd data-idx="26">    ctx.lineWidth = lw;</cl-cd>
<cl-cd data-idx="27">    ctx.beginPath();</cl-cd>
<cl-cd data-idx="28">    ctx.arc(x,y,r,0,<span class="tRed">Math</span>.PI * 2);</cl-cd>
<cl-cd data-idx="29">    ctx.fill();</cl-cd>
<cl-cd data-idx="30">    ctx.stroke();</cl-cd>
<cl-cd data-idx="31">    ctx.restore();</cl-cd>
<cl-cd data-idx="32">};</cl-cd>
<cl-cd data-idx="33">&nbsp;</cl-cd>
<cl-cd data-idx="34"><span class="tGreen">/* 函数 :绘制文本 */</span></cl-cd>
<cl-cd data-idx="35"><span class="tBlue">let</span> draw_text = (txt,x,y,color,fontsize=18,b=<span class="tMagenta">"bold"</span>) =&gt; {</cl-cd>
<cl-cd data-idx="36">&nbsp; &nbsp; ctx.save();</cl-cd>
<cl-cd data-idx="37">&nbsp; &nbsp; ctx.translate(150,150);</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; ctx.font = `${b} ${fontsize}px sans-serif`;</cl-cd>
<cl-cd data-idx="39">&nbsp; &nbsp; ctx.textAlign = <span class="tMagenta">'center'</span>;</cl-cd>
<cl-cd data-idx="40">&nbsp; &nbsp; ctx.textBaseline=<span class="tMagenta">"middle"</span>;</cl-cd>
<cl-cd data-idx="41">&nbsp; &nbsp; ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; ctx.fillText(txt,x,y);</cl-cd>
<cl-cd data-idx="43">&nbsp; &nbsp; ctx.restore();</cl-cd>
<cl-cd data-idx="44">};</cl-cd>
<cl-cd data-idx="45">&nbsp;</cl-cd>
<cl-cd data-idx="46"><span class="tGreen">/* 将所有的具体画法集中在一个函数里 */</span></cl-cd>
<cl-cd data-idx="47"><span class="tBlue">let</span> render = () =&gt; {</cl-cd>
<cl-cd data-idx="48">&nbsp; &nbsp; ctx.clearRect(0,0,300,300); <span class="tGreen">/* 每一次绘制前都首先擦除画布(檫黑板) */</span></cl-cd>
<cl-cd data-idx="49">&nbsp; &nbsp; draw_circle(150,150,140,10,<span class="tMagenta">'tan'</span>,<span class="tMagenta">'darkgreen'</span>); <span class="tGreen">/* 钟壳和钟面 */</span></cl-cd>
<cl-cd data-idx="50">&nbsp;</cl-cd>
<cl-cd data-idx="51">&nbsp; &nbsp; <span class="tGreen">/* 钟点 */</span></cl-cd>
<cl-cd data-idx="52">&nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i &lt; 12; i ++) {</cl-cd>
<cl-cd data-idx="53">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> radian = <span class="tRed">Math</span>.PI/180*(i*30-60);</cl-cd>
<cl-cd data-idx="54">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> x = 115 * <span class="tRed">Math</span>.cos(radian), y = 115 * <span class="tRed">Math</span>.sin(radian);</cl-cd>
<cl-cd data-idx="55">&nbsp; &nbsp; &nbsp; &nbsp; draw_text(i+1, x, y, <span class="tMagenta">'green'</span>);</cl-cd>
<cl-cd data-idx="56">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="57">&nbsp;</cl-cd>
<cl-cd data-idx="58">&nbsp; &nbsp; <span class="tGreen">/* 刻度 */</span></cl-cd>
<cl-cd data-idx="59">&nbsp; &nbsp; <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i &lt; 60; i ++) {</cl-cd>
<cl-cd data-idx="60">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> radian = <span class="tRed">Math</span>.PI/180*(i*6);</cl-cd>
<cl-cd data-idx="61">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tBlue">let</span> x = 150 + 130 * <span class="tRed">Math</span>.cos(radian), y = 150 + 130 * <span class="tRed">Math</span>.sin(radian);</cl-cd>
<cl-cd data-idx="62">&nbsp; &nbsp; &nbsp; &nbsp; draw_circle(x,y,1,2,<span class="tMagenta">'gray'</span>,<span class="tMagenta">'gray'</span>);</cl-cd>
<cl-cd data-idx="63">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="64">&nbsp;</cl-cd>
<cl-cd data-idx="65">&nbsp; &nbsp; draw_text(<span class="tMagenta">'HUACHAO'</span>,0,60,<span class="tMagenta">'gray'</span>); <span class="tGreen">/* 时钟 Logo */</span></cl-cd>
<cl-cd data-idx="66">&nbsp; &nbsp; draw_rect(0, -3, 90, 6, 0, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 时针 */</span></cl-cd>
<cl-cd data-idx="67">&nbsp; &nbsp; draw_rect(0, -2, 100, 4, 270 * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 分针 */</span></cl-cd>
<cl-cd data-idx="68">&nbsp; &nbsp; draw_rect(0, -1, 120, 2, 240 * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 秒针 */</span></cl-cd>
<cl-cd data-idx="69">&nbsp; &nbsp; draw_circle(150,150,6,6,<span class="tMagenta">'white'</span>,<span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 指针扣 */</span></cl-cd>
<cl-cd data-idx="70">};</cl-cd>
<cl-cd data-idx="71">&nbsp;</cl-cd>
<cl-cd data-idx="72">render();</cl-cd>
<cl-cd data-idx="73">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>

</div>

<script>
/* 获取画笔 */
let ctx1 = canv1.getContext('2d'), ctx2 = canv2.getContext('2d');

/* 函数 :绘制矩形(指针) */
let draw_rect = (ctx, x, y, w, h, rad, color) => {
    ctx.save();
    ctx.fillStyle = color;
    ctx.translate(150,150);
    ctx.rotate(rad);
    ctx.fillRect(x,y,w,h);
    ctx.restore();
};
/* 函数 :绘制圆(环) */
let draw_circle = (ctx,x,y,r,lw,color1,color2) => {
    ctx.save();
    ctx.fillStyle = color1;
    ctx.strokeStyle = color2;
    ctx.lineWidth = lw;
    ctx.beginPath();
    ctx.arc(x,y,r,0,Math.PI * 2);
    ctx.fill();
    ctx.stroke();
    ctx.restore();
};
/* 函数 :绘制文本 */
let draw_text = (ctx,txt,x,y,color,fontsize=18,b="bold") => {
        ctx.save();
        ctx.translate(150,150);
        ctx.font = `${b} ${fontsize}px sans-serif`;
        ctx.textAlign = 'center';
        ctx.textBaseline="middle";
        ctx.fillStyle = color;
        ctx.fillText(txt,x,y);
        ctx.restore();
};

let render1 = () => {
        draw_circle(ctx1,150,150,140,10,'tan','darkgreen'); /* 钟壳和钟面 */
        for(let i = 0; i < 60; i ++) {
                let radian = Math.PI/180*(i*6);
                let x = 150 + 130 * Math.cos(radian), y = 150 + 130 * Math.sin(radian);
                draw_circle(ctx1,x,y,1,2,'gray','gray');
        }
        draw_rect(ctx1,0,-3,90,6,0*Math.PI/180,'lightgreen'); /* 时针 */
        draw_rect(ctx1,0,-2,100,4,270*Math.PI/180,'lightgreen'); /* 分针 */
        draw_rect(ctx1,0,-1,120,2,240*Math.PI/180,'lightgreen'); /* 秒针 */
        draw_circle(ctx1,150,150,6,6,'white','lightgreen'); /* 指针扣 */
};

let render2 = () => {
        ctx2.clearRect(0,0,300,300);
        draw_circle(ctx2,150,150,140,10,'tan','darkgreen');
        for(let i = 0; i < 12; i ++) {
                let radian = Math.PI/180*(i*30-60);
                let x = 115 * Math.cos(radian), y = 115 * Math.sin(radian);
                draw_text(ctx2, i+1, x, y, 'green');
        }
        for(let i = 0; i < 60; i ++) {
                let radian = Math.PI/180*(i*6);
                let x = 150 + 130 * Math.cos(radian), y = 150 + 130 * Math.sin(radian);
                draw_circle(ctx2,x,y,1,2,'gray','gray');
        }
        draw_text(ctx2,'HUACHAO',0,60,'gray'); /* Logo */
        draw_rect(ctx2, 0, -3, 90, 6, 0 * Math.PI/180, 'lightgreen'); /* 时针 */
        draw_rect(ctx2, 0, -2, 100, 4, 270 * Math.PI/180, 'lightgreen'); /* 分针 */
        draw_rect(ctx2, 0, -1, 120, 2, 240 * Math.PI/180, 'lightgreen'); /* 秒针 */
        draw_circle(ctx2,150,150,6,6,'white','lightgreen'); /* 指针扣 */
};

render1();
render2();
</script>

红影 发表于 2024-3-25 12:16

“draw_circle(x,y,1,2,'gray','gray'); 小圆点其实就是直径为6像素的实心圆 ”
直径应该是4像素吧。{:4_203:}

红影 发表于 2024-3-25 12:17

小圆点做刻度好,不用管方向了。否则用小短线做还要考虑转向{:4_173:}

红影 发表于 2024-3-25 12:21

let radian = Math.PI/180*(i*30-60); 这个是调整数字对应的吧{:4_187:}

红影 发表于 2024-3-25 12:22

完美的表盘终于出来了,每一步都讲述得那么细致,这个教学真的太好了{:4_199:}

马黑黑 发表于 2024-3-25 14:51

红影 发表于 2024-3-25 12:16
“draw_circle(x,y,1,2,'gray','gray'); 小圆点其实就是直径为6像素的实心圆 ”
直径应该是4像素吧。{:4_2 ...

没量过,卡尺卡不住它。

不过你可以测试一下下面的代码,看看 fill + stroke 的效果:

<canvas id="canv"></canvas?

<script>
let ctx = canv.getContext('2d');

/* 画一个半径为 12px 的圆,填充+描边 */
ctx.fillStyle = 'tan';
ctx.strokeStyle = 'green';
ctx.arc(22,40,12,0,Math.PI * 2);
ctx.fill();
ctx.stroke();

/* 画一条 24px 的水平线 */
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(10, 40);
ctx.lineTo(34, 40);
ctx.stroke();

</script>

马黑黑 发表于 2024-3-25 15:01

红影 发表于 2024-3-25 12:21
let radian = Math.PI/180*(i*30-60); 这个是调整数字对应的吧
绘制文本函数值位移了坐标系,但没有旋转坐标系,所以通过调整角度将它们一一推送到准确的位置。

12个数字,平均每一个数字占 30 度。以一点钟为例,i 为 0, 0*30 = 0,这时它指向三点钟方向,要减去 60 度它才能到它应到的时钟的一点钟方向。其他数字依此类推。

这个我在正文中忘了介绍。

马黑黑 发表于 2024-3-25 15:01

红影 发表于 2024-3-25 12:17
小圆点做刻度好,不用管方向了。否则用小短线做还要考虑转向

少一些计算

南无月 发表于 2024-3-25 20:41

中午看了前半段,刚才看了后半段关于数字的位置算法。。
(i*30-60);
以三点钟方向为起点,
当I是0时,结果是-60,倒回60度即1的位置
当I是1时,结果是-30,倒回30度即2的位置
当I是2时,结果是0.就是3的位置。
{:4_170:}进来看到回复里有讨论这一块。。

南无月 发表于 2024-3-25 20:42

马黑黑 发表于 2024-3-25 15:01
绘制文本函数值位移了坐标系,但没有旋转坐标系,所以通过调整角度将它们一一推送到准确的位置。

12个 ...
{:4_199:}老师设计的好妙啊。。。

南无月 发表于 2024-3-25 20:43

其实加了HUACHAO标志后,我就想起之前的花潮完美时钟。
我还用它做过一个《光辉岁月》的贴子,
回头看了一下代码,跟这个画布画的完全不一样。。
{:4_173:}一个时钟多种实现方法。。。
黑神厉害。。

红影 发表于 2024-3-25 21:30

马黑黑 发表于 2024-3-25 14:51
没量过,卡尺卡不住它。

不过你可以测试一下下面的代码,看看 fill + stroke 的效果:

我没量啊,我是感觉描边是平分边线的,所以2的描边超出圆的部分是1,加上1的半径,感觉应该是4{:4_173:}

红影 发表于 2024-3-25 21:32

马黑黑 发表于 2024-3-25 15:01
绘制文本函数值位移了坐标系,但没有旋转坐标系,所以通过调整角度将它们一一推送到准确的位置。

12个 ...

嗯嗯,我仔细想了一下,也想明白了这点{:4_187:}

红影 发表于 2024-3-25 21:33

马黑黑 发表于 2024-3-25 15:01
少一些计算

是的,小圆点的好处呢{:4_187:}

马黑黑 发表于 2024-3-25 22:09

红影 发表于 2024-3-25 21:33
是的,小圆点的好处呢

苦干加巧干{:4_181:}

马黑黑 发表于 2024-3-25 22:11

红影 发表于 2024-3-25 21:32
嗯嗯,我仔细想了一下,也想明白了这点

道理和小圆点是差不多的,正文中说到区别。另外,为什么不旋转画布坐标,也是有选择的:一旦选择旋转画布坐标系,文字就可能是躺着的本躺着的,或站不直的,还得花力气旋转文本还不一定能旋转。

马黑黑 发表于 2024-3-25 22:16

南无月 发表于 2024-3-25 20:43
其实加了HUACHAO标志后,我就想起之前的花潮完美时钟。
我还用它做过一个《光辉岁月》的贴子,
回头看了 ...

目前,从实现语言上看,有 HTML的,有svg的,马上就有 canvas 画布的

马黑黑 发表于 2024-3-25 22:16

南无月 发表于 2024-3-25 20:42
老师设计的好妙啊。。。
顺着画布的特性去实现一些功能而已

红影 发表于 2024-3-25 23:08

马黑黑 发表于 2024-3-25 22:09
苦干加巧干

巧干更重要{:4_187:}

红影 发表于 2024-3-25 23:10

马黑黑 发表于 2024-3-25 22:11
道理和小圆点是差不多的,正文中说到区别。另外,为什么不旋转画布坐标,也是有选择的:一旦选择旋转画布 ...

是的,只要调整文字的角度就好。这个是数字,如果加汉字怎么加?
页: [1] 2 3 4
查看完整版本: 做一个canvas时钟(五)