摘要:繪制表盤指針對指針的繪制,首先以原點為中心繪制一個圓,對延伸出來的指針思考了兩種繪制方法第一種以軸左半邊為例,點為起始點,以為控制點,為終點繪制三次貝塞爾曲線第二種以軸右半邊為例,直接從點繪制直線到。
不知道大家童年時候有沒有在手上畫手表的經歷,恰好最近在看 canvas ,于是就誕生了這個高仿表盤。
實現過程我這里參照了 Apple Watch 中的這個表盤:
繪制表盤背景這里用到了一個變換屬性 translate ,跟 css 中的屬性相似,把后面繪制過程中的坐標系進行了平移,方便計算;
為了繪制圓角這里用了二次貝塞爾曲線,當然使用 ctx.arc 圓弧也可以,如下示意圖右上角的點 cp 就是該位置貝塞爾曲線的控制點。
繪制日期和表盤刻度繪制日期文字:
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"; // 繪制圓盤刻度點和數字 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 屬性,即繞中心點旋轉,需要刻畫 60 個刻度,一周的弧度為 2 Math.PI ,每次旋轉 1 / 60 ,每 5* 格添加小時文字并加粗刻度線;
這里還有個小時文字角度的問題沒有找到好的解決方法。
繪制表盤指針對指針的繪制,首先以原點為中心繪制一個圓,對延伸出來的指針思考了兩種繪制方法:
第一種:以 Y軸左半邊 為例,點 (-2, 0) 為起始點,以 cp1 、cp2 為控制點,(-1, -12) 為終點繪制三次貝塞爾曲線;
第二種:以 Y軸右半邊 為例,直接從點 (1, -1) 繪制直線到 (1, -12) 。
// 時針 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);
我把兩種都實現了一遍發現效果都差不多,大概是我繪制的圖形不夠大,看不出區別。
接下去需要把指針指向對應的時間,以 16點20分 為例,我們計算時針需要旋轉的角度:
const h = 16 % 12; // 表盤上只有12大格 const m = 20; const hAngle = h / 12; // 這里只計算旋轉角度占一圈的比例,每小時 1/12 const mAngle = (m / 60) * (1 / 12); // 不滿1小時的部分,還需要乘上分鐘數在1小時中的比例 const angle = Math.PI * 2 * (hAngle + mAngle); // 最終需要旋轉的角度 ctx.rotate(angle); ctx.fill(hour); ctx.stroke(hour);
接下去在描述分針的時候我們發現只是末端部分稍微長一點,我們可以選擇沿用時針的部分代碼,寫成這樣:
// 分針 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);
值得注意的一點是:我們在繪制完時針后,如果接下去直接計算角度繪制分針,上下文會以上次旋轉的角度為基礎,疊加旋轉效果,所以繪制分針之前需要還原到初始坐標系,我用的是 save 、 restore 函數保存狀態/還原狀態。
分針、秒針計算繪制過程雷同不再贅述。
實現動畫實現動畫過程只需要擦除已繪制的內容,再次繪制并重置變換效果即可,重繪使用 setInterval 、 requestAnimationFrame 都可以:
function draw() { ctx.resetTransform(); // 重新繪圖前清除變換效果 ctx.clearRect(0, 0, 400, 400); // 清除內容 ... window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw);完整實現
詳見jsfiddle
該文章首發于我的博客https://blog.bingqichen.me/
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93938.html
摘要:繪制一條從當前位置到指定以及位置的直線。該方法有兩個參數以及,代表坐標系中直線結束的點。一個路徑,甚至一個子路徑,都是閉合的。使用路徑繪制圖形需要一些額外的步驟。當前瀏覽器不支持重繪最外層邊框一個簡單的七巧板就出來啦 ?簡介 是 HTML5 新增的元素之一,它允許腳本語言動態渲染位圖像。最初是由 Apple 引入,用于 Mac OS X 的儀表盤,后來又在 Safiri 和 Goog...
摘要:先上效果圖這種圖形大家應該都見過,俗稱儀表盤,當然,上圖只是個最基本的儀表盤架子,可能在實際場景中還會其他很多花里胡哨的點綴,那些暫且不管,不是關鍵,這東西經常見到,但還沒親自上手在代碼層面實現過,最近做的一個需求恰好有這個場景,這里歸先上效果圖: showImg(https://user-gold-cdn.xitu.io/2019/5/23/16ae28a94cb51d3e); 這種圖形大...
摘要:先上效果圖這種圖形大家應該都見過,俗稱儀表盤,當然,上圖只是個最基本的儀表盤架子,可能在實際場景中還會其他很多花里胡哨的點綴,那些暫且不管,不是關鍵,這東西經常見到,但還沒親自上手在代碼層面實現過,最近做的一個需求恰好有這個場景,這里歸先上效果圖: showImg(https://user-gold-cdn.xitu.io/2019/5/23/16ae28a94cb51d3e); 這種圖形大...
閱讀 821·2019-08-30 14:05
閱讀 1712·2019-08-30 11:08
閱讀 3216·2019-08-29 15:41
閱讀 3591·2019-08-23 18:31
閱讀 1510·2019-08-23 18:29
閱讀 546·2019-08-23 14:51
閱讀 2103·2019-08-23 13:53
閱讀 2126·2019-08-23 13:02