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}