npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hanzi-writer-wechatmini

v3.0.2

Published

Hanzi Writer 微信小程序适配版 — 基于 chanind/hanzi-writer v3.0.0,修复 Canvas 2D 兼容性问题,npm 直装即用。

Readme

Hanzi Writer — 微信小程序适配版

License: MIT

本项目是 chanind/hanzi-writer 的微信小程序适配分支,在原版基础上修改了渲染层代码,使其能够在微信小程序的 Canvas 2D 环境中正常工作。

Hanzi Writer 是一个免费开源的 JavaScript 汉字笔顺动画和笔画练习库,支持简体和繁体汉字。

原版在线演示


目录


为什么需要适配

原版 hanzi-writer 基于浏览器 DOM API 实现,在微信小程序中存在以下不兼容问题:

| 问题 | 原版行为 | 小程序限制 | |------|---------|-----------| | DOM 操作 | 使用 document.getElementById / document.createElement | 小程序无 document 全局对象 | | 节点尺寸 | 调用 setAttribute('width', ...) / getBoundingClientRect() | 小程序 Canvas 不支持这些方法 | | 事件绑定 | 使用 document.addEventListener 监听全局 mouseup / touchend | 小程序 Canvas 无全局事件机制 | | Path2D | 使用 new Path2D() 构造笔画路径 | 小程序 Canvas 2D 不支持 Path2D(会报警告) |

适配版针对上述问题逐一修改了源码,用小程序兼容的方式替代了浏览器专属 API。


源码修改说明

基于原版 v3.0.0 源码,共修改 4 个核心文件

1. src/renderers/canvas/RenderTarget.ts(核心改动)

Canvas 渲染目标是小程序适配的核心,主要改动:

  • init() 静态方法:移除 document.getElementById / document.createElement 逻辑,直接接收 Canvas 节点引用
  • 尺寸设置:用 canvas.width = ... 替代 setAttribute();新增 updateDimensions() 方法供页面动态调整
  • getBoundingClientRect():返回基于 Canvas 实际尺寸的虚拟矩形(因为小程序中没有真实的 DOM 布局)
  • 事件系统重构:Canvas 版改为手动触发模式——通过 emitTouchStart(x, y) / emitTouchMove(x, y) / emitTouchEnd() 三个方法供小程序页面在 touchstart / touchmove / touchend 事件中主动调用
// 小程序中触摸事件的转发方式
canvas.addEventListener('touchstart', (e) => {
  const touch = e.touches[0];
  renderTarget.emitTouchStart(touch.x, touch.y);
});

2. src/renderers/RenderTargetBase.ts

addPointerEndListener()document.addEventListener 改为 this.node.addEventListener,避免依赖全局 document 对象。

3. src/renderers/canvas/CharacterRenderer.ts

StrokeRenderer 构造时的 Path2D 参数设为 false,禁用 Path2D 路径构建,避免小程序环境报警告。

4. rollup.config.js

TypeScript 编译配置增加 target: 'es5' 以保证最大兼容性,同时 skipLibCheck: true 跳过类型库检查以加速构建。CJS 输出关闭 sourcemap,避免 //# sourceMappingURL= 在小程序构建 npm 时产生警告。


快速开始

安装

npm install hanzi-writer-wechatmini

安装后在微信开发者工具中点击 工具 → 构建 npm,即会自动将 dist/index.cjs.js 复制到 miniprogram_npm/hanzi-writer-wechatmini/index.js 供项目使用。

基本用法

以下是在小程序页面中使用 Hanzi Writer 的完整示例:

1. WXML 模板

<view class="stroke-wrapper">
  <canvas
    type="2d"
    id="strokeCanvas"
    style="width: 300px; height: 300px;"
    bindtouchstart="onTouchStart"
    bindtouchmove="onTouchMove"
    bindtouchend="onTouchEnd"
  />
</view>

2. TS/JS 页面逻辑

import HanziWriter from 'hanzi-writer-wechatmini';

Page({
  _writer: null as any,
  _renderTarget: null as any,

  onLoad() {
    this.initCanvas();
  },

  initCanvas() {
    const query = wx.createSelectorQuery();
    query.select('#strokeCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node;
        const dpr = wx.getWindowInfo().pixelRatio;

        // 设置 Canvas 实际像素尺寸
        canvas.width = 300 * dpr;
        canvas.height = 300 * dpr;

        // 创建 HanziWriter 实例
        this._writer = HanziWriter.create(canvas, '汉', {
          width: 300 * dpr,
          height: 300 * dpr,
          strokeAnimationSpeed: 1,
          delayBetweenStrokes: 300,
          showCharacter: true,
          showOutline: true,
        });

        // 获取 RenderTarget 用于事件转发(仅 quiz/test 模式需要)
        this._renderTarget = (this._writer as any).target;
      });
  },

  // ── 触摸事件转发到 HanziWriter ──
  onTouchStart(e: any) {
    const touch = e.touches[0];
    this._renderTarget?.emitTouchStart(touch.x, touch.y);
  },

  onTouchMove(e: any) {
    const touch = e.touches[0];
    this._renderTarget?.emitTouchMove(touch.x, touch.y);
  },

  onTouchEnd() {
    this._renderTarget?.emitTouchEnd();
  },
});

注意:仅 quiz(笔顺练习)和 stroke(逐笔绘制)等需要用户交互的模式才需要设置触摸事件转发。纯动画演示模式(animateCharacter)不需要。


API 说明

HanziWriter.create(element, character, options?)

创建 HanziWriter 实例并加载汉字。参数:

| 参数 | 类型 | 说明 | |------|------|------| | element | HTMLCanvasElement | 小程序中直接传入 Canvas 节点引用(非字符串 ID) | | character | string | 要显示的汉字 | | options | object | 配置选项(见下方) |

配置选项

interface HanziWriterOptions {
  width?: number;                // Canvas 宽度(像素)
  height?: number;               // Canvas 高度(像素)
  padding?: number;              // 内边距(默认 5)
  showOutline?: boolean;         // 显示笔画轮廓
  showCharacter?: boolean;       // 显示完整汉字
  showHintAfterMisses?: number;  // 答错 N 次后显示提示
  highlightColor?: string;       // 正确笔画高亮色
  strokeColor?: string;          // 笔画颜色
  outlineColor?: string;         // 轮廓颜色
  radicalColor?: string;         // 部首颜色
  strokeAnimationSpeed?: number; // 笔画动画速度(1=正常)
  delayBetweenStrokes?: number;  // 笔画间延迟(ms)
  delayBetweenLoops?: number;    // 循环间延迟(ms)
  charDataLoader?: Function;     // 自定义汉字数据加载器
  onLoadCharDataSuccess?: Function;  // 数据加载成功回调
  onLoadCharDataError?: Function;    // 数据加载失败回调
  // ... 更多选项见原版文档
}

核心方法

| 方法 | 说明 | |------|------| | animateCharacter() | 播放汉字笔顺动画 | | loopCharacterAnimation() | 循环播放笔顺动画 | | showCharacter() | 显示完整汉字 | | showOutline() | 显示笔画轮廓 | | hideCharacter() | 隐藏汉字 | | hideOutline() | 隐藏轮廓 | | quiz(options?) | 启动笔顺练习模式 | | setCharacter(character) | 切换汉字 | | updateDimensions({ width, height }) | 动态更新 Canvas 尺寸 |

小程序新增方法

| 方法 | 说明 | |------|------| | renderTarget.emitTouchStart(x, y) | 手动触发触摸开始事件 | | renderTarget.emitTouchMove(x, y) | 手动触发触摸移动事件 | | renderTarget.emitTouchEnd() | 手动触发触摸结束事件 | | renderTarget.updateDimensions(w, h) | 更新 Canvas 渲染尺寸 |


构建与开发

yarn install       # 安装依赖
yarn build         # 编译
yarn test          # 运行测试
yarn typecheck     # TypeScript 类型检查

构建产物输出到 dist/ 目录:

| 文件 | 格式 | 说明 | |------|------|------| | dist/index.cjs.js | CommonJS | 小程序构建 npm 使用的入口 | | dist/index.esm.js | ES Module | 现代打包工具使用 | | dist/hanzi-writer.js | IIFE | 浏览器直接引用 | | dist/hanzi-writer.min.js | IIFE (minified) | 浏览器引用(压缩版) |


数据结构与数据源

Hanzi Writer 使用的汉字 SVG 和笔顺数据来自 Make me a Hanzi 项目,经过微调后托管在 Hanzi Writer Data 仓库。

默认情况下,字符数据从 jsDelivr CDN 加载。在小程序中,你可能需要实现自定义 charDataLoader 来配合离线或内网环境:

const writer = HanziWriter.create(canvas, '汉', {
  charDataLoader: (char: string, onComplete: Function) => {
    // 自定义数据加载逻辑
    // onComplete({ strokes: [...], medians: [...] })
  },
});

与上游差异对照

| 文件 | 改动内容 | 影响范围 | |------|---------|---------| | src/renderers/canvas/RenderTarget.ts | init() 去除 DOM 操作;新增 emitTouch* 方法;getBoundingClientRect() 重写;updateDimensions 兼容 string\|number | Canvas 初始化、触摸交互 | | src/renderers/RenderTargetBase.ts | addPointerEndListener DOM 事件改为节点事件 | Canvas/SVG 触摸结束监听 | | src/renderers/canvas/CharacterRenderer.ts | 禁用 Path2D(传入 false) | Canvas 笔画渲染 | | src/utils.ts | 添加 declare const global: any | 解决 types: [] 下找不到 global 的类型错误 | | src/Mutation.ts | 添加 declare namespace NodeJS | 解决 NodeJS.Timeout 类型缺失 | | rollup.config.js | target: es5 + skipLibCheck + CJS sourcemap: false | 构建兼容性与产出清洁度 | | package.json | 添加 miniprogram 字段,Windows 兼容 build 脚本 | 微信小程序 npm 支持 |


许可

Hanzi Writer 基于 MIT 许可发布。

Hanzi Writer 的汉字数据源自 Make Me A Hanzi 项目,该项目从 文鼎科技 的字体中提取数据,文鼎科技于 1999 年在宽松许可下发布了这些字体。你可以根据文鼎科技发布的大众授权条款重新分发和/或修改这些数据。许可副本见 ARPHICPL.TXT