最近在自研紫微斗数排盘小程序,整个项目分为后端排盘计算引擎和前端十二宫画布绘制两大块。很多人拿到排盘源码,能算出星曜数据,却卡在十二宫图渲染这一步:宫位排布、星曜叠加、四化标记、文字排版拥挤、适配不同屏幕。 本文从源码角度拆解排盘数据输出结构,重点分享小程序 Canvas 绘制十二宫的开发要点、常见坑和实现思路,适合做命理测算类小程序开发的同学参考。
一、整体流程梳理
一套完整的紫微排盘,分成两个阶段。 第一阶段是后端排盘计算:根据生辰、时区、性别,算出命宫、身宫、十二宫各自宫干、星曜列表、四化、煞星、庙旺信息,输出结构化 JSON。 第二阶段是前端绘制:拿到 JSON 数据之后,在小程序 Canvas 上布局十二宫,画宫框、写宫名、摆放主星辅星、标注四化颜色,最终生成大家熟悉的紫微盘图。
很多新手容易混淆:计算逻辑和绘图逻辑要解耦。后端只负责输出标准化数据,不关心画面长什么样;前端只负责渲染,不改动排盘规则。这样后续修改盘面样式、换主题配色,不用动核心排盘源码。
二、排盘源码核心输出结构解析
排盘引擎最终输出的核心是十二宫数组,每一个宫位是独立对象。我简化后的数据结构如下,也是前端绘图的数据源。
// 单宫数据结构示意 public class ZiweiPalace { private String palaceName; // 宫位名称:命宫、财帛、官禄等 private String ganZhi; // 宫干支 private List<String> mainStar; // 主星 private List<String> minorStar; // 辅星、煞星 private String hua; // 四化标记:化禄/化权/化科/化忌 }
十二宫按照固定顺序生成,顺序不能乱,这是后面环形排布的基础。 拿到数据之后要做一次数据校验:判断宫位是否闭环、四化是否正确挂载到对应星曜,避免前端拿到脏数据,直接渲染出错。
这里有一个很重要的细节:星曜要区分主次。主星体积大、优先级高,绘图的时候优先摆放;辅星、小星挤在空隙里。如果不分优先级,很容易出现文字重叠。
三、小程序十二宫绘制方案选型
小程序里画这种环形十二宫盘,可选方案主要两种。 第一种是用 WXML + view 布局做网格环形排版。优点是简单,不用写 Canvas;缺点是适配性差,不同手机屏幕变形严重,文字换行很难控制,想要保存图片分享也麻烦。 第二种就是 Canvas 绘制,也是我最终选用的方案。可以自由控制每一段线条、文字位置,方便导出图片保存到相册,是排盘小程序最主流的方案。
小程序现在推荐使用新版 Canvas 2D,相比旧版接口,渲染更稳定,高清绘制不容易模糊。开发时建议直接基于 Canvas2D 编码。
四、十二宫绘制核心开发要点
4.1 布局思路
紫微盘是标准的十二等分圆环,外圈十二宫均匀分布,中间预留区域放命宫概述、生辰信息。 开发的时候,先确定画布中心点,设定外圆半径、内圆半径,用角度均分 360°,每一个宫占 30°。 绘制顺序跟着排盘输出的宫位顺序走,沿着圆环依次绘制宫格边线。画线的时候,注意线条分层:外圈粗线,内部分隔细线,区分层级。
4.2 文字绘制是最大难点
Canvas 的文字绘制不像 HTML 自动换行,所有文字坐标都要自己计算。 我这边的处理思路:每个宫位内部划分多个小区域,固定位置放宫干支、主星、辅星、四化标记。 四化用颜色区分,比如化禄绿色、化权红色、化科蓝色、化忌黑色,用户一眼就能识别。 还有一个高频踩坑点:文字不能超出宫格边界。星曜数量有多有少,有的宫只有一颗主星,有的宫堆满辅星。需要做简单判断,星多的时候自动缩小字号,星少用标准字号,避免文字溢出宫框。
4.3 绘图核心片段(小程序 JS)
// Canvas2D 绘制单宫文字示例 const ctx = this.ctx; ctx.save(); ctx.fillStyle = '#333'; ctx.font = `${fontSize}px sans-serif`; ctx.fillText(starName, x, y); // 四化标记上色 if(item.hua === '化禄'){ ctx.fillStyle = '#00b42a'; } ctx.fillText(item.hua, x + 40, y); ctx.restore();
绘制的时候频繁 save、restore,用来隔离样式,防止上一个宫的颜色、字体污染下一个宫。
4.4 图片导出与高清适配
小程序 Canvas 默认直接导出会模糊。解决办法是设置 devicePixelRatio,画布宽高放大倍数,绘制完成之后再缩小展示。 绘制完成后,调用 canvasToTempFilePath,支持用户保存盘面图片,也是这类产品的核心功能。
五、开发踩坑记录
第一,角度计算很容易正负搞反。小程序 Canvas 的 0 角度朝右,顺时针增加,和很多数学库默认方向不一样,一开始画出来的宫位顺序是反的,调试很久。 第二,不同机型字体渲染差异,同样字号,安卓和 iOS 文字宽度不一样,很容易出现个别机型文字挤在一起。 第三,星曜数据为空的空宫,要单独处理,不要直接不渲染,最好显示 “空宫” 标识,保持盘面统一。 第四,画布尺寸适配,不能写死固定 px,要根据屏幕宽度动态计算画布大小,小屏手机不能溢出页面。
六、排盘与绘图联动优化
排盘接口本身计算耗时,所以沿用之前做的缓存思路:后端缓存排盘 JSON,前端缓存渲染好的盘面。用户重复打开同一个生辰,不用重新请求、重新绘制画布,提升体验。 另外,绘图和计算解耦之后,可以做多套盘面主题。白底经典盘、深色盘,只需要换绘图里的颜色变量,不需要改动排盘源码。
七、总结
紫微斗数排盘小程序开发,排盘计算是地基,十二宫画布绘制是门面。排盘源码保证数据规则准确,Canvas 绘制决定用户直观体验。 核心要点总结下来:计算与渲染解耦、数据区分星曜优先级、基于角度均分做环形布局、做好 Canvas 文字位置管控、处理高清适配和多机型兼容。
这套绘制思路,同样可以迁移到八字、罗盘等其他传统测算类小程序的图形绘制场景。 如果后续要扩展,还可以加上宫位点击交互,点击宫位弹窗展示详细星曜解读。