摘要:繪制表盤指針對(duì)指針的繪制,首先以原點(diǎn)為中心繪制一個(gè)圓,對(duì)延伸出來(lái)的指針?biāo)伎剂藘煞N繪制方法第一種以軸左半邊為例,點(diǎn)為起始點(diǎn),以為控制點(diǎn),為終點(diǎn)繪制三次貝塞爾曲線第二種以軸右半邊為例,直接從點(diǎn)繪制直線到。
不知道大家童年時(shí)候有沒有在手上畫手表的經(jīng)歷,恰好最近在看 canvas ,于是就誕生了這個(gè)高仿表盤。
實(shí)現(xiàn)過(guò)程我這里參照了 Apple Watch 中的這個(gè)表盤:
繪制表盤背景這里用到了一個(gè)變換屬性 translate ,跟 css 中的屬性相似,把后面繪制過(guò)程中的坐標(biāo)系進(jìn)行了平移,方便計(jì)算;
為了繪制圓角這里用了二次貝塞爾曲線,當(dāng)然使用 ctx.arc 圓弧也可以,如下示意圖右上角的點(diǎn) cp 就是該位置貝塞爾曲線的控制點(diǎn)。
繪制日期和表盤刻度繪制日期文字:
const now = moment(); ctx.textAlign = "left"; ctx.fillStyle = "#ce4c50"; ctx.font = "11px "Helvetica Neue""; ctx.textBaseline = "middle"; ctx.fillText(now.format("D"), 15, 0); ctx.fillStyle = "white"; ctx.fillText(now.format("ffffd"), 33, 0);
繪制刻度:
ctx.fillStyle = "white"; ctx.font = "20px "Helvetica Neue""; ctx.strokeStyle = "white"; ctx.textAlign = "center"; // 繪制圓盤刻度點(diǎn)和數(shù)字 for (let index = 60; index > 0; index -= 1) { if (index % 5 === 0) { ctx.lineWidth = 3 ctx.fillText(index / 5, 0, -70); } else { ctx.lineWidth = 1; } ctx.beginPath(); ctx.moveTo(0, -90); ctx.lineTo(0, -85); ctx.stroke(); ctx.rotate(- Math.PI * 2 * (1 / 60)); }
這里用到了 rotate 屬性,即繞中心點(diǎn)旋轉(zhuǎn),需要刻畫 60 個(gè)刻度,一周的弧度為 2 Math.PI ,每次旋轉(zhuǎn) 1 / 60 ,每 5* 格添加小時(shí)文字并加粗刻度線;
這里還有個(gè)小時(shí)文字角度的問題沒有找到好的解決方法。
繪制表盤指針對(duì)指針的繪制,首先以原點(diǎn)為中心繪制一個(gè)圓,對(duì)延伸出來(lái)的指針?biāo)伎剂藘煞N繪制方法:
第一種:以 Y軸左半邊 為例,點(diǎn) (-2, 0) 為起始點(diǎn),以 cp1 、cp2 為控制點(diǎn),(-1, -12) 為終點(diǎn)繪制三次貝塞爾曲線;
第二種:以 Y軸右半邊 為例,直接從點(diǎn) (1, -1) 繪制直線到 (1, -12) 。
// 時(shí)針 const hour = new Path2D(); hour.arc(0, 0, 2, 0, Math.PI * 2); // hour.moveTo(-2, 0); // hour.bezierCurveTo(-2, -2, 0, -1, -1, -12); hour.moveTo(-1, -1); hour.lineTo(-1, -12) hour.lineTo(-2, -13); hour.lineTo(-2, -45); hour.arc(0, -47, 2, -Math.PI, 0); hour.lineTo(2, -13); // hour.lineTo(1, -12); // hour.bezierCurveTo(0, 1, 2, -2, 2, 0); hour.lineTo(1, -12); hour.lineTo(1, -1);
我把兩種都實(shí)現(xiàn)了一遍發(fā)現(xiàn)效果都差不多,大概是我繪制的圖形不夠大,看不出區(qū)別。
接下去需要把指針指向?qū)?yīng)的時(shí)間,以 16點(diǎn)20分 為例,我們計(jì)算時(shí)針需要旋轉(zhuǎn)的角度:
const h = 16 % 12; // 表盤上只有12大格 const m = 20; const hAngle = h / 12; // 這里只計(jì)算旋轉(zhuǎn)角度占一圈的比例,每小時(shí) 1/12 const mAngle = (m / 60) * (1 / 12); // 不滿1小時(shí)的部分,還需要乘上分鐘數(shù)在1小時(shí)中的比例 const angle = Math.PI * 2 * (hAngle + mAngle); // 最終需要旋轉(zhuǎn)的角度 ctx.rotate(angle); ctx.fill(hour); ctx.stroke(hour);
接下去在描述分針的時(shí)候我們發(fā)現(xiàn)只是末端部分稍微長(zhǎng)一點(diǎn),我們可以選擇沿用時(shí)針的部分代碼,寫成這樣:
// 分針 const minute = new Path2D(hour); // 沿用代碼 minute.moveTo(-2, -45); minute.lineTo(-2, -82); minute.arc(0, -84, 2, -Math.PI, 0); minute.lineTo(2, -13); const minute = new Path2D(); // 不沿用代碼 minute.arc(0, 0, 2, 0, Math.PI * 2); minute.moveTo(-1, -1); minute.lineTo(-1, -12) minute.lineTo(-2, -13); minute.lineTo(-2, -82); minute.arc(0, -84, 2, -Math.PI, 0); minute.lineTo(2, -13); minute.lineTo(1, -12); minute.lineTo(1, -1);
值得注意的一點(diǎn)是:我們?cè)诶L制完時(shí)針后,如果接下去直接計(jì)算角度繪制分針,上下文會(huì)以上次旋轉(zhuǎn)的角度為基礎(chǔ),疊加旋轉(zhuǎn)效果,所以繪制分針之前需要還原到初始坐標(biāo)系,我用的是 save 、 restore 函數(shù)保存狀態(tài)/還原狀態(tài)。
分針、秒針計(jì)算繪制過(guò)程雷同不再贅述。
實(shí)現(xiàn)動(dòng)畫實(shí)現(xiàn)動(dòng)畫過(guò)程只需要擦除已繪制的內(nèi)容,再次繪制并重置變換效果即可,重繪使用 setInterval 、 requestAnimationFrame 都可以:
function draw() { ctx.resetTransform(); // 重新繪圖前清除變換效果 ctx.clearRect(0, 0, 400, 400); // 清除內(nèi)容 ... window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw);完整實(shí)現(xiàn)
詳見jsfiddle
該文章首發(fā)于我的博客https://blog.bingqichen.me/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93938.html
摘要:繪制一條從當(dāng)前位置到指定以及位置的直線。該方法有兩個(gè)參數(shù)以及,代表坐標(biāo)系中直線結(jié)束的點(diǎn)。一個(gè)路徑,甚至一個(gè)子路徑,都是閉合的。使用路徑繪制圖形需要一些額外的步驟。當(dāng)前瀏覽器不支持重繪最外層邊框一個(gè)簡(jiǎn)單的七巧板就出來(lái)啦 ?簡(jiǎn)介 是 HTML5 新增的元素之一,它允許腳本語(yǔ)言動(dòng)態(tài)渲染位圖像。最初是由 Apple 引入,用于 Mac OS X 的儀表盤,后來(lái)又在 Safiri 和 Goog...
摘要:先上效果圖這種圖形大家應(yīng)該都見過(guò),俗稱儀表盤,當(dāng)然,上圖只是個(gè)最基本的儀表盤架子,可能在實(shí)際場(chǎng)景中還會(huì)其他很多花里胡哨的點(diǎn)綴,那些暫且不管,不是關(guān)鍵,這東西經(jīng)常見到,但還沒親自上手在代碼層面實(shí)現(xiàn)過(guò),最近做的一個(gè)需求恰好有這個(gè)場(chǎng)景,這里歸先上效果圖: showImg(https://user-gold-cdn.xitu.io/2019/5/23/16ae28a94cb51d3e); 這種圖形大...
摘要:先上效果圖這種圖形大家應(yīng)該都見過(guò),俗稱儀表盤,當(dāng)然,上圖只是個(gè)最基本的儀表盤架子,可能在實(shí)際場(chǎng)景中還會(huì)其他很多花里胡哨的點(diǎn)綴,那些暫且不管,不是關(guān)鍵,這東西經(jīng)常見到,但還沒親自上手在代碼層面實(shí)現(xiàn)過(guò),最近做的一個(gè)需求恰好有這個(gè)場(chǎng)景,這里歸先上效果圖: showImg(https://user-gold-cdn.xitu.io/2019/5/23/16ae28a94cb51d3e); 這種圖形大...
閱讀 833·2019-08-30 14:05
閱讀 1723·2019-08-30 11:08
閱讀 3226·2019-08-29 15:41
閱讀 3600·2019-08-23 18:31
閱讀 1522·2019-08-23 18:29
閱讀 555·2019-08-23 14:51
閱讀 2114·2019-08-23 13:53
閱讀 2135·2019-08-23 13:02