HarmonyOS应用《玄象》开发实战:MoonPhasesPage 月相页:Date 时间轴 + 月相 Canvas 球面光照算法
·

阅读时长:约 19 分钟 | 难度:★★★★★ | 篇章:第 8 篇 · 天文历法模块
对应源码:entry/src/main/ets/pages/astronomy/MoonPhasesPage.ets

前言
月相展示是玄象项目天文历法模块的视觉亮点。页面通过 Canvas 绘制 8 种月相(新月→满月→残月)的球面光照阴影,并通过进度条让用户选择查看不同月相。本篇将深入剖析玄象项目月相页的实现:从 MoonPhase 数据结构、Canvas 球面光照算法、arc 明暗界线绘制,到月相进度条交互。掌握这套月相绘制算法,您就能为任何 HarmonyOS 应用构建逼真的月相展示。
提示:玄象项目月相绘制采用"圆弧切割"算法模拟月球明暗界线。
一、月相数据
1.1 八种月相
private phases: MoonPhase[] = [
{ name: '新月', day: '初一' },
{ name: '蛾眉月', day: '初三' },
{ name: '上弦月', day: '初七' },
{ name: '盈凸月', day: '十二' },
{ name: '满月', day: '十五' },
{ name: '亏凸月', day: '十八' },
{ name: '下弦月', day: '廿二' },
{ name: '残月', day: '廿七' }
];
二、Canvas 月相绘制
2.1 球面光照算法
private drawMoon(canvas: CanvasRenderingContext2D, w: number, h: number): void {
const cx = w / 2, cy = h / 2;
const r = Math.min(w, h) / 2 - 10;
// 背景(暗面)
canvas.fillStyle = '#1A1A2E';
canvas.beginPath();
canvas.arc(cx, cy, r, 0, Math.PI * 2);
canvas.fill();
// 亮面(根据月相计算明暗界线)
const phase = this.currentPhase;
canvas.fillStyle = '#F0D078';
canvas.beginPath();
if (phase === 0) { // 新月
// 不绘制亮面
} else if (phase === 4) { // 满月
canvas.arc(cx, cy, r, 0, Math.PI * 2);
canvas.fill();
} else {
// 半圆 + 椭圆弧
const xOffset = r * (1 - phase / 4);
canvas.arc(cx, cy, r, -Math.PI / 2, Math.PI / 2);
canvas.ellipse(cx, cy, r, xOffset, 0, Math.PI / 2, -Math.PI / 2);
canvas.fill();
}
}
三、月相进度条
3.1 迷你月相
ForEach(this.phases, (phase: MoonPhase, index: number) => {
Column({ space: 4 }) {
Canvas(this.drawMiniMoon.bind(this, index))
.width(36).height(36)
Text(phase.name)
.fontSize(10)
.fontColor(index === this.currentPhase ? Colors.PRIMARY_GOLD : Colors.TEXT_DIM)
}
})
四、月相页设计总结
4.1 页面结构
| 区域 | 组件 | 内容 |
|---|---|---|
| 月相图 | Canvas | 220×220 月相绘制 |
| 月相名称 | Text | 当前月相名 |
| 农历日期 | Text | 对应农历日 |
| 月相进度条 | Row | 8 个迷你月相 |
总结
本篇以玄象项目月相页为蓝本,深入剖析了 Canvas 月相绘制算法:从 MoonPhase 数据结构、Canvas 球面光照算法、arc 明暗界线绘制,到月相进度条交互。掌握这套月相绘制算法,您就能为任何 HarmonyOS 应用构建逼真的月相展示。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐


所有评论(0)