已开启
钟表-集美大学-蔡昱钦-罗方芳 #417
caiyuqin创建于 6月30日
钟表-集美大学-蔡昱钦-罗方芳 #417
已开启
共 2 个文件变更+111-16
| @@ -12,6 +12,8 @@ import std.time.* | |||
| 12 | import std.sync.* | 12 | import std.sync.* |
| 13 | import std.format.* | 13 | import std.format.* |
| 14 | 14 | ||
| 15 | +let timezoneList = [("本地", 0.0), ("东京", 1.0), ("伦敦", -8.0), ("纽约", -13.0)] | ||
| 16 | + | ||
| 15 | @Entry | 17 | @Entry |
| 16 | @Component | 18 | @Component |
| 17 | class EntryView { | 19 | class EntryView { |
| @@ -20,13 +22,23 @@ class EntryView { | |||
| 20 | var settings: RenderingContextSettings = RenderingContextSettings(antialias: true) | 22 | var settings: RenderingContextSettings = RenderingContextSettings(antialias: true) |
| 21 | var context: CanvasRenderingContext2D = CanvasRenderingContext2D(this.settings) | 23 | var context: CanvasRenderingContext2D = CanvasRenderingContext2D(this.settings) |
| 22 | var timer: ?Timer = None | 24 | var timer: ?Timer = None |
| 25 | + @State var currentThemeIndex: Int64 = 0 | ||
| 26 | + @State var currentTimezoneIndex: Int64 = 0 | ||
| 27 | + var clock: ?Clock = None | ||
| 23 | 28 | ||
| 24 | protected override func onPageShow() { | 29 | protected override func onPageShow() { |
| 25 | - let clock = Clock(context, width) | 30 | + let c = Clock(context, width) |
| 31 | + c.theme = themes[currentThemeIndex] | ||
| 32 | + c.timezoneOffset = timezoneList[currentTimezoneIndex][1] | ||
| 33 | + c.timezoneLabel = timezoneList[currentTimezoneIndex][0] | ||
| 34 | + this.clock = c | ||
| 26 | this.timer = Timer.repeat(Duration.Zero, Duration.second, { => | 35 | this.timer = Timer.repeat(Duration.Zero, Duration.second, { => |
| 27 | launch { | 36 | launch { |
| 28 | context.clearRect(0.0, 0.0, width, height) | 37 | context.clearRect(0.0, 0.0, width, height) |
| 29 | - clock.draw(DateTime.now()) | 38 | + match (this.clock) { |
| 39 | + case let clk: Clock => clk.draw(DateTime.now()) | ||
| 40 | + case _ => () | ||
| 41 | + } | ||
| 30 | } | 42 | } |
| 31 | }, style: CatchupStyle.Skip) | 43 | }, style: CatchupStyle.Skip) |
| 32 | } | 44 | } |
| @@ -44,9 +56,33 @@ class EntryView { | |||
| 44 | } | 56 | } |
| 45 | } | 57 | } |
| 46 | 58 | ||
| 59 | + func switchTheme(): Unit { | ||
| 60 | + currentThemeIndex = (currentThemeIndex + 1) % themes.size | ||
| 61 | + match (this.clock) { | ||
| 62 | + case let c: Clock => c.theme = themes[currentThemeIndex] | ||
| 63 | + case _ => () | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + func switchTimezone(): Unit { | ||
| 68 | + currentTimezoneIndex = (currentTimezoneIndex + 1) % timezoneList.size | ||
| 69 | + match (this.clock) { | ||
| 70 | + case let c: Clock => | ||
| 71 | + c.timezoneOffset = timezoneList[currentTimezoneIndex][1] | ||
| 72 | + c.timezoneLabel = timezoneList[currentTimezoneIndex][0] | ||
| 73 | + case _ => () | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + | ||
| 47 | func build() { | 77 | func build() { |
| 48 | Column { | 78 | Column { |
| 49 | - Canvas(this.context).padding(top: 76).width(width).height(height) | 79 | + Row { |
| 80 | + Text("[ 主题 ]").fontSize(14.px).fontColor(0x0055FF) | ||
| 81 | + .onClick({ => this.switchTheme() }) | ||
| 82 | + Text("[ 时区 ]").fontSize(14.px).fontColor(0x0055FF) | ||
| 83 | + .onClick({ => this.switchTimezone() }) | ||
| 84 | + }.width(100.percent).justifyContent(FlexAlign.SpaceEvenly).padding(top: 24) | ||
| 85 | + Canvas(this.context).padding(top: 10).width(width).height(height) | ||
| 50 | }.width(100.percent).height(100.percent) | 86 | }.width(100.percent).height(100.percent) |
| 51 | } | 87 | } |
| 52 | } | 88 | } |
| @@ -8,17 +8,73 @@ import ohos.component.* | |||
| 8 | import std.math.* | 8 | import std.math.* |
| 9 | import std.time.DateTime | 9 | import std.time.DateTime |
| 10 | 10 | ||
| 11 | +public struct ThemeColors { | ||
| 12 | + var bgInner: UInt32 | ||
| 13 | + var bgMid: UInt32 | ||
| 14 | + var bgOuter: UInt32 | ||
| 15 | + var frameColor: UInt32 | ||
| 16 | + var numberColor: UInt32 | ||
| 17 | + var majorTickColor: UInt32 | ||
| 18 | + var minorTickColor: UInt32 | ||
| 19 | + var hourHandColor: UInt32 | ||
| 20 | + var minuteHandColor: UInt32 | ||
| 21 | + var secondHandColor: UInt32 | ||
| 22 | + var centerColor: UInt32 | ||
| 23 | + var textColor: UInt32 | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +public let lightTheme = ThemeColors( | ||
| 27 | + bgInner: 0xFFFFFF, bgMid: 0xEEEEEE, bgOuter: 0xFFFFFF, | ||
| 28 | + frameColor: 0xFFFFFF, numberColor: 0x000000, | ||
| 29 | + majorTickColor: 0x000000, minorTickColor: 0xCCCCCC, | ||
| 30 | + hourHandColor: 0x000000, minuteHandColor: 0x000000, | ||
| 31 | + secondHandColor: 0x0055FF, centerColor: 0x0055FF, | ||
| 32 | + textColor: 0x000000 | ||
| 33 | +) | ||
| 34 | + | ||
| 35 | +public let darkTheme = ThemeColors( | ||
| 36 | + bgInner: 0x2D2D2D, bgMid: 0x1A1A1A, bgOuter: 0x2D2D2D, | ||
| 37 | + frameColor: 0x444444, numberColor: 0xFFFFFF, | ||
| 38 | + majorTickColor: 0xFFFFFF, minorTickColor: 0x666666, | ||
| 39 | + hourHandColor: 0xFFFFFF, minuteHandColor: 0xFFFFFF, | ||
| 40 | + secondHandColor: 0x00CCFF, centerColor: 0x00CCFF, | ||
| 41 | + textColor: 0xFFFFFF | ||
| 42 | +) | ||
| 43 | + | ||
| 44 | +public let oceanTheme = ThemeColors( | ||
| 45 | + bgInner: 0x1A3A5C, bgMid: 0x0D2137, bgOuter: 0x1A3A5C, | ||
| 46 | + frameColor: 0x2A5A8C, numberColor: 0xFFFFFF, | ||
| 47 | + majorTickColor: 0x88CCFF, minorTickColor: 0x446688, | ||
| 48 | + hourHandColor: 0x88CCFF, minuteHandColor: 0x88CCFF, | ||
| 49 | + secondHandColor: 0xFF8844, centerColor: 0xFF8844, | ||
| 50 | + textColor: 0x88CCFF | ||
| 51 | +) | ||
| 52 | + | ||
| 53 | +public let sunsetTheme = ThemeColors( | ||
| 54 | + bgInner: 0xFF6B35, bgMid: 0xCC4400, bgOuter: 0xFF6B35, | ||
| 55 | + frameColor: 0xFF8855, numberColor: 0xFFFFFF, | ||
| 56 | + majorTickColor: 0xFFDDAA, minorTickColor: 0x995522, | ||
| 57 | + hourHandColor: 0xFFDDAA, minuteHandColor: 0xFFDDAA, | ||
| 58 | + secondHandColor: 0xFFFF00, centerColor: 0xFFFF00, | ||
| 59 | + textColor: 0xFFDDAA | ||
| 60 | +) | ||
| 61 | + | ||
| 62 | +public let themes = [lightTheme, darkTheme, oceanTheme, sunsetTheme] | ||
| 63 | + | ||
| 11 | public class Clock { | 64 | public class Clock { |
| 12 | var hour: Float64 = 0.0 | 65 | var hour: Float64 = 0.0 |
| 13 | var minute: Float64 = 0.0 | 66 | var minute: Float64 = 0.0 |
| 14 | var second: Float64 = 0.0 | 67 | var second: Float64 = 0.0 |
| 15 | let radius: Float64 | 68 | let radius: Float64 |
| 69 | + public var theme: ThemeColors = lightTheme | ||
| 70 | + public var timezoneOffset: Float64 = 0.0 | ||
| 71 | + public var timezoneLabel: String = "本地" | ||
| 16 | 72 | ||
| 17 | public Clock(let context: CanvasRenderingContext2D, | 73 | public Clock(let context: CanvasRenderingContext2D, |
| 18 | let width: Float64) { radius = width / 2.0 } | 74 | let width: Float64) { radius = width / 2.0 } |
| 19 | 75 | ||
| 20 | public func draw(time: DateTime) { | 76 | public func draw(time: DateTime) { |
| 21 | - hour = Float64(time.hour) | 77 | + hour = (Float64(time.hour) + timezoneOffset + 24.0) % 24.0 |
| 22 | minute = Float64(time.minute) | 78 | minute = Float64(time.minute) |
| 23 | second = Float64(time.second) | 79 | second = Float64(time.second) |
| 24 | 80 | ||
| @@ -35,9 +91,9 @@ public class Clock { | |||
| 35 | // 绘制渐变背景 | 91 | // 绘制渐变背景 |
| 36 | func background() { | 92 | func background() { |
| 37 | let grad = context.createRadialGradient(radius, radius, radius - 32.0, radius, radius, radius) | 93 | let grad = context.createRadialGradient(radius, radius, radius - 32.0, radius, radius, radius) |
| 38 | - grad.addColorStop(0.0, Color.WHITE) | 94 | + grad.addColorStop(0.0, theme.bgInner) |
| 39 | - grad.addColorStop(0.9, 0xEEEEEE) | 95 | + grad.addColorStop(0.9, theme.bgMid) |
| 40 | - grad.addColorStop(1.0, Color.WHITE) | 96 | + grad.addColorStop(1.0, theme.bgOuter) |
| 41 | context.fillStyle(grad) | 97 | context.fillStyle(grad) |
| 42 | context.fillRect(0.0, 0.0, width, width) | 98 | context.fillRect(0.0, 0.0, width, width) |
| 43 | } | 99 | } |
| @@ -48,7 +104,7 @@ public class Clock { | |||
| 48 | // 边框 | 104 | // 边框 |
| 49 | context.lineWidth(6.0) | 105 | context.lineWidth(6.0) |
| 50 | context.beginPath() | 106 | context.beginPath() |
| 51 | - context.strokeStyle(0xffffff) | 107 | + context.strokeStyle(theme.frameColor) |
| 52 | context.arc(0.0, 0.0, radius - 5.0, 0.0, 2.0 * Float64.PI, anticlockwise: false) | 108 | context.arc(0.0, 0.0, radius - 5.0, 0.0, 2.0 * Float64.PI, anticlockwise: false) |
| 53 | context.stroke() | 109 | context.stroke() |
| 54 | 110 | ||
| @@ -56,7 +112,7 @@ public class Clock { | |||
| 56 | context.font(size: 40.px) | 112 | context.font(size: 40.px) |
| 57 | context.textAlign(TextAlignStyle.Center) | 113 | context.textAlign(TextAlignStyle.Center) |
| 58 | context.textBaseline(TextBaseline.Middle) | 114 | context.textBaseline(TextBaseline.Middle) |
| 59 | - context.fillStyle(0x000000) | 115 | + context.fillStyle(theme.numberColor) |
| 60 | for (hour in 1..=12) { | 116 | for (hour in 1..=12) { |
| 61 | let rad = 2.0 * Float64.PI / 12.0 * Float64(hour - 3) | 117 | let rad = 2.0 * Float64.PI / 12.0 * Float64(hour - 3) |
| 62 | let x = cos(rad) * (radius - 38.0) | 118 | let x = cos(rad) * (radius - 38.0) |
| @@ -74,13 +130,13 @@ public class Clock { | |||
| 74 | if (i % 5 == 0) { | 130 | if (i % 5 == 0) { |
| 75 | let x = cos(rad) * (radius - 20.0) | 131 | let x = cos(rad) * (radius - 20.0) |
| 76 | let y = sin(rad) * (radius - 20.0) | 132 | let y = sin(rad) * (radius - 20.0) |
| 77 | - context.strokeStyle(0x000000) | 133 | + context.strokeStyle(theme.majorTickColor) |
| 78 | context.lineWidth(2.0) | 134 | context.lineWidth(2.0) |
| 79 | context.lineTo(x, y) | 135 | context.lineTo(x, y) |
| 80 | } else { | 136 | } else { |
| 81 | let x = cos(rad) * (radius - 18.0) | 137 | let x = cos(rad) * (radius - 18.0) |
| 82 | let y = sin(rad) * (radius - 18.0) | 138 | let y = sin(rad) * (radius - 18.0) |
| 83 | - context.strokeStyle(0xCCCCCC) | 139 | + context.strokeStyle(theme.minorTickColor) |
| 84 | context.lineWidth(1.0) | 140 | context.lineWidth(1.0) |
| 85 | context.lineTo(x, y) | 141 | context.lineTo(x, y) |
| 86 | } | 142 | } |
| @@ -94,9 +150,9 @@ public class Clock { | |||
| 94 | let hourAngle = 2.0 * Float64.PI / 12.0 * (hour + minute / 60.0) | 150 | let hourAngle = 2.0 * Float64.PI / 12.0 * (hour + minute / 60.0) |
| 95 | let minuteAngle = 2.0 * Float64.PI / 60.0 * minute | 151 | let minuteAngle = 2.0 * Float64.PI / 60.0 * minute |
| 96 | let secondAngle = 2.0 * Float64.PI / 60.0 * second | 152 | let secondAngle = 2.0 * Float64.PI / 60.0 * second |
| 97 | - for (params in [(8.0, hourAngle, 0u32, 0.5), | 153 | + for (params in [(8.0, hourAngle, theme.hourHandColor, 0.5), |
| 98 | - (5.0, minuteAngle, 0u32, 0.8), | 154 | + (5.0, minuteAngle, theme.minuteHandColor, 0.8), |
| 99 | - (2.0, secondAngle, 0x0055FFu32, 0.9)]) { | 155 | + (2.0, secondAngle, theme.secondHandColor, 0.9)]) { |
| 100 | context.save() | 156 | context.save() |
| 101 | context.beginPath() | 157 | context.beginPath() |
| 102 | context.lineWidth(params[0]) | 158 | context.lineWidth(params[0]) |
| @@ -114,7 +170,7 @@ public class Clock { | |||
| 114 | func center() { | 170 | func center() { |
| 115 | context.save() | 171 | context.save() |
| 116 | context.beginPath() | 172 | context.beginPath() |
| 117 | - context.fillStyle(0x0055ff) | 173 | + context.fillStyle(theme.centerColor) |
| 118 | context.arc(0.0, 0.0, 4.0, 0.0, 2.0 * Float64.PI, anticlockwise: false) | 174 | context.arc(0.0, 0.0, 4.0, 0.0, 2.0 * Float64.PI, anticlockwise: false) |
| 119 | context.fill() | 175 | context.fill() |
| 120 | context.restore() | 176 | context.restore() |
| @@ -127,8 +183,11 @@ public class Clock { | |||
| 127 | context.font(size: 90.px) | 183 | context.font(size: 90.px) |
| 128 | context.textAlign(TextAlignStyle.Center) | 184 | context.textAlign(TextAlignStyle.Center) |
| 129 | context.textBaseline(TextBaseline.Middle) | 185 | context.textBaseline(TextBaseline.Middle) |
| 130 | - context.fillStyle(0x000) | 186 | + context.fillStyle(theme.textColor) |
| 131 | context.fillText(time, 0.0, radius + 80.0) | 187 | context.fillText(time, 0.0, radius + 80.0) |
| 188 | + context.font(size: 28.px) | ||
| 189 | + context.fillStyle(theme.secondHandColor) | ||
| 190 | + context.fillText(timezoneLabel, 0.0, radius + 98.0) | ||
| 132 | context.restore() | 191 | context.restore() |
| 133 | } | 192 | } |
| 134 | } | 193 | } |