作者:鄭瑤
本文正在參加星光計劃3.0–夏日挑戰賽
前言
最近在學習HarmonyOS 相關的東西,看了很多網上的canvas 實作時鐘,現在我也來寫一個關于HarmonyOS 的時鐘吧。
項目說明
工具版本:DevEco Studio 3.0 Beta3
SDK版本;3.1.5.5
主要用到知識:canvas js
效果展示

實作步驟
1. 在頁面index.hml 中定義一個canvas 元素
<div class="container">
<canvas ref="clock" style="width: 600px; height:600px; background-color:#5a5a5a "></canvas>
</div
2. 需要在index.js data 中定義兩個變量用來存放目标元素和繪制2d
export default {
data: {
c:'',
ctx:''
}
}
3. 需要在onShow 生命周期中拿到目标元素并且繪制 2d
onShow(){
this.el = this.$refs.clock;
//擷取canvas繪圖上下文
this.ctx = this.el.getContext('2d');
this.initData()
},
4. 定義一個初始化函數initData(),調用繪制函數
initData:function(){
this.updateClock(this.ctx)
},
5. 繪制函數clock函數
5.1 首先繪制外部最大的圓
drawPanel:function(ctx){
ctx.beginPath() //開始
ctx.arc(300, 300, 200, 0, Math.PI * 2) //繪制弧線路徑
ctx.fillStyle = 'white' //填充顔色
ctx.fill() //填充
ctx.closePath() //閉合
},
此時的頁面長這樣:
5.2 繪制時間(時)刻度(12小時刻度)
hourCalibration:function(ctx){
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; //定義刻度的數字
ctx.beginPath(); //開始
ctx.translate(300, 300) //移動目前坐标系的原點
ctx.font = '30px bold' //文字的大小
ctx.textAlign = "center"; // 文字居中
ctx.textBaseline = "middle"; // 設定文本繪制中的水準對齊方式 為文本塊的中間
ctx.fillStyle = "black"; // 填充顔色
for (var i = 0; i < arr.length; i++) {
//繪制填充類文本
ctx.fillText(
arr[i],
168 * Math.cos(((i * 30 - 60) * Math.PI) / 180),
168 * Math.sin(((i * 30 - 60) * Math.PI) / 180)
);
}
ctx.closePath(); // 結束
},
此時頁面:
5.3 繪制中心的小圓點
centerDot:function(ctx){
ctx.beginPath(); // 開始
ctx.arc(0, 0, 8, 0, 2 * Math.PI); //繪制弧線路徑
ctx.fill(); //對封閉路徑進行填充
ctx.beginPath(); //開始
ctx.fillStyle = "white";
ctx.arc(0, 0, 5, 0, 2 * Math.PI); //繪制弧線路徑
ctx.fill();//對封閉路徑進行填充
},
此時的頁面長這樣:
5.4 擷取時間并且轉化成中原標準時間
此時需要擷取目前系統的本地時間,在此處遇到了一個小麻煩,鴻蒙開發者工具new Date() 擷取到的時間為格林威治時間,而我們現在采用的是中原標準時間,需要寫函數來轉化時間,轉化函數為getTimeStamp()
getTimeStamp:function(){
var zoneOffset = 8;
//算出時差,并轉換為毫秒:
var offset2 = new Date().getTimezoneOffset()* 60 * 1000;
//算出現在的時間:
var nowDate2 = new Date().getTime();
//此時東八區的時間
var currentZoneDate = new Date(nowDate2 + offset2 + zoneOffset*60*60*1000);
return currentZoneDate;
}
擷取目前中原標準時間:
//修改時間 預設擷取的是格林威治時間 需要将時間轉化為中原標準時間才行
var date = this.getTimeStamp(new Date())
//擷取目前的小時
var hours = date.getHours()
console.log(hours+'hours')
//擷取目前分鐘
var minutes = date.getMinutes()
console.log(minutes+'minutes')
//擷取目前秒數
var seconds = date.getSeconds()
console.log(seconds+'seconds')
5.5 繪制時鐘的指針
hourHand:function(ctx,hours, minutes){
var radius =
((2 * Math.PI) / 12) * hours + (((1 / 6) * Math.PI) / 60) * minutes;
ctx.save();// 儲存目前狀态,為了旋轉後能回到當初狀态。
ctx.beginPath(); //開始
ctx.lineWidth = 8; // 針的寬度
ctx.lineCap = "round"; // 針頭為圓角
ctx.strokeStyle = "green"; //針的顔色
ctx.rotate(radius); // 旋轉
ctx.moveTo(0, 0);
ctx.lineTo(0, -90);
ctx.stroke();
ctx.closePath() // 結束
// 回到儲存的狀态
ctx.restore();
},
此時的頁面長這樣:
5.6 繪制分針的指針
minuteHand:function(ctx,minutes){
2 * Math.PI;
var radius = ((2 * Math.PI) / 60) * minutes;
ctx.save(); // 儲存目前狀态,為了旋轉後能回到當初狀态。
ctx.beginPath(); //開始
ctx.lineWidth = 4; // 針的寬度
ctx.lineCap = "round"; //針頭為圓角
ctx.strokeStyle = "black";
ctx.rotate(radius); //旋轉
ctx.moveTo(0, 0);
ctx.lineTo(0, -110);
ctx.stroke(); //繪制輪廓圓
ctx.closePath() //結束
ctx.restore();
},
此時頁面長這樣:
5.7 繪制秒針
secondHand:function(ctx,seconds) {
var radius = ((2 * Math.PI) / 60) * seconds;
ctx.save(); // 儲存目前狀态,為了旋轉後能回到當初狀态。
ctx.beginPath(); //開始
ctx.lineWidth = 2; // 針的寬度
ctx.lineCap = "round"; //針頭為圓角
ctx.strokeStyle = "red";
ctx.rotate(radius); //旋轉
ctx.moveTo(0, 0);
ctx.lineTo(0, -140);
ctx.stroke();//繪制輪廓圓
ctx.closePath() //結束
ctx.restore();
},
此時頁面長這樣:
5.8 最後一步我們需要寫一個更新函數用來調用所有繪畫函數并且在更新函數中擷取對應的中原標準時間:
updateClock:function(ctx){
var time = this.getTimeStamp(new Date())
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
ctx.save();
this.drawPanel(this.ctx);
this.hourCalibration(this.ctx);
this.secondHand(this.ctx,seconds);
this.minuteHand(this.ctx,minutes);
this.hourHand(this.ctx,hours, minutes);
this.centerDot(this.ctx)
ctx.closePath();
ctx.restore();
}
6. 最後一步我們需要讓這個鐘表轉動起來
那麼就需要在initData 函數中寫一個定時器沒一秒鐘執行一次繪制函數即可: 最後的圖檔如上圖第一張圖所示的效果
initData:function(){
// 定時器一分鐘重新整理一次時間
let timer = setInterval(()=>{
this.ctx.clearRect(0, 0, 600, 600); //删除指定區域内的繪制内容。
this.updateClock(this.ctx)
},1000)
},
總結:
以上就是canvas 繪制一個時鐘的全部步驟了。 最重要的一點是要能正确的擷取到時間(中原標準時間)但是我發現在編輯器上new Date() 到的時間跟咋們的中原標準時間相差了八小時,在一位同僚的提醒下才知道這個擷取的時間為格林威治時間,那麼我們需要将這個格林威治時間轉化成中原標準時間,在網上找了一段轉化方法終于轉化成功。
更多原創内容請關注:中軟國際 HarmonyOS 技術團隊
入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生态。