• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import display from '@ohos.display'
16import Logger from '../model/Logger'
17
18const HOURS: Array<string> = ['3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '1', '2']
19const HEIGHT_ADD: number = 150 // 表盘下面需要绘制时间,canvas高度是宽度加150
20const TAG: string = 'Index'
21
22@Entry
23@Component
24struct Clock {
25  private settings: RenderingContextSettings = new RenderingContextSettings(true)
26  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
27  @State canvasWidth: number = 300 // 300是表盘默认大小
28  private radius: number = 150 // 默认表盘半径
29  private intervalId: number = 0
30  updateTime = () => {
31    this.context.clearRect(0, 0, this.canvasWidth, this.canvasWidth + HEIGHT_ADD)
32    let nowTime = new Date()
33    let hour = nowTime.getHours()
34    let minute = nowTime.getMinutes()
35    let second = nowTime.getSeconds()
36    let time = `${this.fillTime(hour)}:${this.fillTime(minute)}:${this.fillTime(second)}`
37    this.drawBackGround()
38    this.drawHour(hour, minute)
39    this.drawMinute(minute)
40    this.drawSecond(second)
41    this.drawDot()
42    this.drawTime(time)
43    this.context.translate(-this.radius, -this.radius)
44  }
45
46  fillTime(time) {
47    return time < 10 ? `0${time}` : `${time}`
48  }
49
50  aboutToAppear() {
51    this.getSize()
52  }
53
54  // 获取设备宽高计算表盘大小
55  async getSize() {
56    let mDisplay = await display.getDefaultDisplay()
57    Logger.info(TAG, `getDefaultDisplay mDisplay = ${JSON.stringify(mDisplay)}`)
58    this.canvasWidth = px2vp(mDisplay.width > mDisplay.height ? mDisplay.height * 0.5 : mDisplay.width * 0.5)
59    this.radius = this.canvasWidth / 2
60  }
61
62  drawBackGround() {
63    this.context.save()
64
65    // 绘制背景
66    var grad = this.context.createRadialGradient(this.radius, this.radius, this.radius - 35, this.radius,
67    this.radius, this.radius)
68    grad.addColorStop(0.0, 'white')
69    grad.addColorStop(0.9, '#eee')
70    grad.addColorStop(1.0, 'white')
71    this.context.fillStyle = grad
72    this.context.fillRect(0, 0, this.canvasWidth, this.canvasWidth)
73
74    // 绘制外圈圆
75    this.context.translate(this.radius, this.radius)
76    this.context.lineWidth = 6
77    this.context.beginPath()
78    this.context.strokeStyle = '#fff'
79    this.context.arc(0, 0, this.radius - 6, 0, 2 * Math.PI, false)
80    this.context.stroke()
81
82    // 绘制时间文字
83    this.context.font = '25px'
84    this.context.textAlign = "center"
85    this.context.textBaseline = "middle"
86    this.context.fillStyle = '#000'
87    HOURS.forEach((num, index) => {
88      this.context.save()
89      let rad = 2 * Math.PI / 12 * index
90      let x = Math.cos(rad) * (this.radius - 38)
91      let y = Math.sin(rad) * (this.radius - 38)
92      this.context.fillText(num, x, y)
93    })
94
95    // 绘制刻度
96    for (let i = 0; i < 60; i++) {
97      let rad = 2 * Math.PI / 60 * i
98      let x = Math.cos(rad) * (this.radius - 12)
99      let y = Math.sin(rad) * (this.radius - 12)
100      this.context.beginPath()
101      this.context.moveTo(x, y)
102      if (i % 5 == 0) {
103        let x1 = Math.cos(rad) * (this.radius - 20)
104        let y1 = Math.sin(rad) * (this.radius - 20)
105        this.context.strokeStyle = '#000'
106        this.context.lineWidth = 4
107        this.context.lineTo(x1, y1)
108      } else {
109        let x1 = Math.cos(rad) * (this.radius - 18)
110        let y1 = Math.sin(rad) * (this.radius - 18)
111        this.context.strokeStyle = '#ccc'
112        this.context.lineWidth = 3
113        this.context.lineTo(x1, y1)
114      }
115      this.context.stroke()
116    }
117  }
118
119  // 绘制时针
120  drawHour(hour, minute) {
121    this.context.save()
122    this.context.beginPath()
123    this.context.lineWidth = 8
124    this.context.lineCap = 'round'
125    let rad = 2 * Math.PI / 12 * hour
126    let mrad = 2 * Math.PI / 12 / 60 * minute
127    this.context.rotate(rad + mrad)
128    this.context.moveTo(0, 10)
129    this.context.strokeStyle = '#000'
130    this.context.lineTo(0, -this.radius / 2)
131    this.context.stroke()
132    this.context.restore()
133  }
134
135  // 绘制分针
136  drawMinute(minute) {
137    this.context.save()
138    this.context.beginPath()
139    this.context.lineWidth = 6
140    this.context.lineCap = 'round'
141    let rad = 2 * Math.PI / 60 * minute
142    this.context.rotate(rad)
143    this.context.moveTo(0, 10)
144    this.context.strokeStyle = '#000'
145    this.context.lineTo(0, -this.radius + 40)
146    this.context.stroke()
147    this.context.restore()
148  }
149
150  // 绘制秒针
151  drawSecond(second) {
152    this.context.save()
153    this.context.beginPath()
154    this.context.lineWidth = 4
155    this.context.lineCap = 'round'
156    let rad = 2 * Math.PI / 60 * second
157    this.context.rotate(rad)
158    this.context.moveTo(0, 10)
159    this.context.strokeStyle = '#05f'
160    this.context.lineTo(0, -this.radius + 18)
161    this.context.stroke()
162    this.context.restore()
163  }
164
165  // 绘制中心点
166  drawDot() {
167    this.context.save()
168    this.context.beginPath()
169    this.context.fillStyle = '#05f'
170    this.context.arc(0, 0, 4, 0, 2 * Math.PI, false)
171    this.context.fill()
172    this.context.restore()
173  }
174
175  // 绘制表盘下面时间文本
176  drawTime(time) {
177    this.context.save()
178    this.context.beginPath()
179    this.context.font = '60px'
180    this.context.textAlign = "center"
181    this.context.textBaseline = "middle"
182    this.context.fillStyle = '#000'
183    this.context.fillText(time, 0, this.radius + 80)
184    this.context.restore()
185  }
186
187  build() {
188    Stack({ alignContent: Alignment.Center }) {
189      Canvas(this.context)
190        .width(this.canvasWidth)
191        .height(this.canvasWidth + HEIGHT_ADD)
192        .onReady(() => {
193          this.updateTime()
194          this.intervalId = setInterval(this.updateTime, 1000)
195        })
196    }
197    .width('100%')
198    .height('100%')
199  }
200
201  onPageHide() {
202    clearInterval(this.intervalId)
203  }
204}