作者:郑瑶

本文正在参加星光计划3.0–夏日挑战赛

前言

最近在学习HarmonyOS 相关的东西,看了很多网上的canvas 实现时钟,现在我也来写一个关于HarmonyOS 的时钟吧。

项目说明

工具版本:DevEco Studio 3.0 Beta3

SDK版本;3.1.5.5

主要用到知识:canvas js

效果展示

动画2.gif

实现步骤

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()  //闭合
    },

此时的页面长这样:

1.png

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(); // 结束
    },

此时页面:

2.png

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();//对封闭路径进行填充
    },

此时的页面长这样:

3.png

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();
    },

此时的页面长这样:

4.png

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

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();
      },

此时页面长这样:

6.png

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开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com/#bkwz