汉字笔顺查询的微信小程序,支持简体和繁体。
这是一款查询汉字笔顺的微信小程序。具有一下特点:
自己在临摹大师的帖子时遇到很多繁体字的笔顺不会,例如繁体飞 "飛",便去寻找笔顺相关的工具软件。找了一圈没有满意的,就自己写,也就是有了这个小程序。当然汉字的笔顺没有所谓的标准,本程序所给出的笔顺也仅仅供用户参考。
未来计划加入手写体 ORC。因为很多繁体压根不认识,没法通过拼音输入了,手写输入又麻烦,所以准备弄个 ORC,摄像头一扫,就能识别出字,从而展示其笔画,但技术难度很大。
本项目所有笔顺数据来源于项目makemeahanzi,在此表示感谢。与笔顺数据和 SVG 动画相关的请参考这个项目。
后台使用微信提供的云开发功能,具体包括其中的数据库和存储功能。如果想自己使用,初始化方法如下:
SVG 构建就是将 ./tools/graphics-618dbab.txt 中的一条数据(一行)变为一个 SVG 笔顺动画的过程。其中存在一些控制生成动画的参数,例如演示笔画的速度,笔画的颜色等等,具体看源码,很简单。
SVG 的显示很坑。第一坑是小程序不能直接显示 SVG,得将 SVG 转为 Base64 编码才能正常显示。这导致wxml 和 wxss 中有很多内嵌的 Base64 编码,看着很扎眼。第二坑是 SVG 笔顺动画重放问题。动画放完了,怎么再放一遍?开始想法是把显示的图片设为空,然后再设置回来。例如,当前 SVG 的内容是 ”福“ 的笔顺动画,动画一遍播放完了,想重放一遍,就让 SVG 变为空,再变为 ”福“ 的 SVG。可不知道是微信的问题还是渲染引擎的问题,回来之后能正常显示SVG,动画却没了,显示的效果直接变为最终态。找了好久,没有解决方法,只能很蠢的刷新整个页面来达到动画重放的效果。后来灵机一动,猜想不播放动画应该是缓存在作怪,微信或渲染引擎判断两次要显示了东西是一样的,就直接用了缓存,如果能让两次的 SVG 代码稍微不同,应该就可以解决这个问题。而改变 SVG 代码却不影响其显示效果的就是加注释,注释的内容就是当前时间,马上试了下,成功!
离线数据模块相对复杂。引入离线数据目的是想在断网的情况下使用,因为我写字的时候习惯手机断网。实现思路很简单,直接将笔顺数据(./tools/graphics-618dbab.txt)下载到本地就好。可坑又来了:微信规定小程序本地存储空间上限为10MB,而这个文件有30MB+。这就要进行文件压缩和字选择。
分析过程如下,原始数据中每条数据有三个部分:汉字字符(character)、笔画路径数组(strokes)、笔画大致走势数组(medians)。下面以“福”(原始数据为rawData.json)字例,分别分析这三个部分压缩方法。
"character": "福",
,如果规定压缩后每条数据都以字符的 utf-16 编码开头,那就只需要两字节,编码后:[31119
]。结果是,这个部分从 17 字节变为 2 字节,压缩到原来的 12%。当然这部分数据占总数据比例很小,所以可以忽略不计。操作符
和操作数
组成,且每种操作符后面的操作数个数固定。例如操作符“M”后有2个操作数,“Q”后有4个操作数。这样解码时就很容易了。
为了统一,对操作符和操作数都采用两字节表示。福字第一画路径原始数据为:"M 298 770 Q 329 748 361 719 Q 377 706 395 707 Q 408 708 412 724 Q 416 742 404 775 Q 397 796 361 809 Q 277 830 264 823 Q 258 819 261 804 Q 265 791 298 770 Z",
压缩后为:
[M][298][770][Q][329][748][361][719][Q][377][706][395][707][Q][408][708][412][724][Q][416][742][404][775][Q][397][796][361][809][Q][277][830][264][823][Q][258][819][261][804][Q][265][791][298][770][Z][,]
其中一个中括号表示两字节。从原来的 158 字节压缩到 90 字节。压缩后大小 / 原始大小 = 57%。最后使用[newline]表示整个部分结束。
[[269,816],[364,767],[393,726]],
压缩后为:
[6][269][816][364][767][393][726]
压缩后数据中,一个中括号表示两字节,为方便解压,这里采用前缀个数,第一个元素[6]表示接下来6个数是一组。从原来的 32 字节压缩到 7 字节。压缩后大小 / 原始大小 = 22%。最后使用[end]表示整条数据结束。
总结上面三部分,最终压缩应该为原来的 40% 到 50% 左右,最大8MB左右,满足10MB的要求。
以上是对单条数据编码进行压缩,但是编码后只能进行顺序查找,时间复杂度为O(N),而且每次为了查一个字得加载整个文件到内存,时间消耗太大,所以就有了下面的数据分块和索引。
文件越大,读取到内存时间越长,所以减小单个文件大小能加快速度。而数据索引不仅仅能描述目标数据在那一块,还能记录目标数据在一块的起始位置,从而减少查找时间。而查找索引本身可以使用二分查找,时间复杂度为lg(n)。具体到索引格式的设计:每条索引有四个部分,字符的 utf-16 编码、所在的数据块编号、起始地址、数据长度。所有索引按照第一个部分也就是字符的 utf-16 编码排序,方便后面的二分查找。
本项目使用了开源的文鼎楷体笔顺库中的graphics.txt,笔顺库的版权受《文鼎公众授权书》的约束。
项目的其它部分采用MIT授权。