Cax
小程序、小游戏以及 Web 通用 Canvas 渲染引擎
- Github → github.com/dntzhang/ca…
- 综合 DEMO | 运动 DEMO
- 小程序 DEMO 正在审核中敬请期待
- 小游戏 DEMO 正在审核中敬请期待
特性
- Learn Once, Write Anywhere(小程序、小游戏、PC Web、Mobile Web)
- 支持小程序、小游戏以及 Web 浏览器渲染
- 小程序、小游戏和 Web 拥有相同简洁轻巧的 API
- 高性能的渲染架构
- 超轻量级的代码体积
- 松耦合的渲染架构
- 支持 Canvas 元素管理
- 支持 Canvas 元素事件体系
- 图灵完毕的 group 嵌套体系
- 内置 tween 运动能力
- 内置文本、位图、序列帧、绘图对象和多种矢量绘制对象
一分钟入门小程序 cax 使用
到 GitHub 下载 cax 自定义组件,然后小程序引入 cax 自定义组件:
└── cax ├── cax.js ├── cax.json ├── cax.w ├── cax.wxss └── index.js复制代码在 page 或者 component 里声明依赖:
{ "usingComponents": { "cax":"../cax/cax" }}复制代码在的 w 里引入 cax 标签:
<cax id="myCanvas"></cax> 复制代码在 js 里渲染逻辑:
import cax from '../cax/index'Page({ : function () { //比 web 里使用 cax 多传递 this,this 代表 Page 或 Component 的实例 const stage = new cax.Stage(200, 200, 'myCanvas', this) const rect = new cax.Rect(100, 100, { fillStyle: 'black' }) rect.originX = 50 rect.originY = 50 rect.x = 100 rect.y = 100 rect.rotation = 30 rect.on('tap', () => { console.log('tap') }) stage.add(rect) stage.update() }})复制代码除了 tap 事件,也可以帮 rect 绑定其他触摸事件:rect.on('touchstart', () => { console.log('touchstart')})rect.on('touchmove', () => { console.log('touchmove')})rect.on('touchend', () => { console.log('touchend')})复制代码一分钟入门小游戏 cax 使用
const stage = new cax.Stage()复制代码和小程序以及 Web 不同的是,小游戏创建 Stage 不需要传任何参数。
一分钟入门 Web cax 使用
通过 npm 或者 CDN 获取:
npm i cax复制代码import cax from 'cax' const stage = new cax.Stage(200, 200, '#renderTo')const rect = new cax.Rect(100, 100, { fillStyle: 'black'})stage.add(rect)stage.update()复制代码除了 Stage 构造函数比小程序第四个参数 this,其他使用方式都一样。
内置对象
Group
用于分组, group 也可以嵌套 group,父容器的属性会叠加在子属性上, 比如:
- group 的 x 是 100, group 里的 bitmap 的 x 是 200, 最后 bitmap 渲染到 stage 上的 x 是 300
- group 的 alpha 是 0.7, group 里的 bitmap 的 alpha 是 0.6, 最后 bitmap 渲染到 stage 上的 alpha 是 0.42
const group = new cax.Group()const rect = new cax.Rect(100, 100 { fillStyle: 'black'})group.add(rect)stage.add(group)stage.update()复制代码group 拥有常用的 add 和 remove 方法进行元素的增加和删除。先 add 的会先绘制,所有后 add 的会盖在先 add 的上面。
Bitmap
const bitmap = new cax.Bitmap(img)stage.add(bitmap)stage.update()复制代码如果只传 url 而不是 Image 对象的实例,需要这样:
const bitmap = new cax.Bitmap('./wepay.png', ()=>{ stage.update()})stage.add(bitmap)复制代码这里需要注意小程序需要配置 downloadFile 需要配置合法域名才能正常加载到图片。
可以设置图片裁剪显示区域,和其他 transform 属性:
bitmap.rect = [0, 0, 170, 140]bitmap.x = 200 复制代码Sprite
序列帧动画组件,可以把任意图片的任意区域组合成一串动画。
const sprite = new cax.Sprite({ rate: 7, imgs: ['./mario-sheet.png'], s: [ // x, y, width, height, originX, originY ,imageIndex [0, 0, 32, 32], [32 * 1, 0, 32, 32], [32 * 2, 0, 32, 32], [32 * 3, 0, 32, 32], [32 * 4, 0, 32, 32], [32 * 5, 0, 32, 32], [32 * 6, 0, 32, 32], [32 * 7, 0, 32, 32], [32 * 8, 0, 32, 32], [32 * 9, 0, 32, 32], [32 * 10, 0, 32, 32], [32 * 11, 0, 32, 32], [32 * 12, 0, 32, 32], [32 * 13, 0, 32, 32], [32 * 14, 0, 32, 32] ], animations: { walk: { s: [0, 1] }, happy: { s: [5, 6, 7, 8, 9] }, win: { s: [12] } }, playOnce: false, currentAnimation: "walk", animationEnd: function () { }});复制代码Text
文本对象
const text = new cax.Text('Hello World', { font: '20px Arial', color: '#ff7700', line: 'top'})复制代码Graphics
绘图对象,用于使用基本的连缀方式的 Canvas 指令绘制图形。
const graphics = new cax.Graphics()graphics .beginPath() .arc(0, 0, 10, 0, Math.PI * 2) .closePath() .fillStyle('#f4862c') .fill() .strokeStyle('black') .stroke()graphics.x = 100graphics.y = 200stage.add(graphics)复制代码Shape
与 Graphics 不同的是, Shape 一般拥有有限的宽高,所以可以使用离屏 Canvas 进行缓存。下面这些属于 Shape。
Rect
const rect = new cax.Rect(200, 100, { fillStyle: 'black'})复制代码Circel
const circel = new cax.Circel(10)复制代码Ellipse
const ellipse = new cax.Ellipse(10)复制代码注意:从技术上小游戏和 Web 可以离屏 Canvas,小程序不行,因为小程序不支持动态创建离屏 Canvas。
Element
Element 是多种元素的组合,如 Bitmap、Group、 Text、 Shape 等混合起来的图像。
Button
const button = new cax.Button({ width: 100, height: 40, text: "Click Me!"})复制代码属性
Transform
| 属性名 | 描述 |
|---|---|
| x | 水平偏移 |
| y | 竖直偏移 |
| scaleX | 水平缩放 |
| scaleY | 竖直缩放 |
| rotation | 旋转 |
| skewX | 歪斜 X |
| skewY | 歪斜 Y |
| originX | 旋转基点 X |
| originY | 旋转基点 Y |
Alpha
| 属性名 | 描述 |
|---|---|
| alpha | 元素的透明度 |
注意这里父子都设置了 alpha 会进行乘法叠加。
compositeOperation
| 属性名 | 描述 |
|---|---|
| compositeOperation | 源图像绘制到目标图像上的叠加模式 |
注意这里如果自身没有定义 compositeOperation 会进行向上查找,找到最近的定义了 compositeOperation 的父容器作为自己的 compositeOperation。
Cursor
| 属性名 | 描述 |
|---|---|
| cursor | 鼠标移上去的形状 |
事件
小程序事件
| 事件名 | 描述 |
|---|---|
| tap | 手指触摸后马上离开 |
| touchstart | 手指触摸动作开始 |
| touchmove | 手指触摸后移动 |
| touchend | 手指触摸动作结束 |
| drag | 拖拽 |
Web 事件
| 事件名 | 描述 |
|---|---|
| click | 元素上发生点击时触发 |
| mousedown | 当元素上按下鼠标按钮时触发 |
| mousemove | 当鼠标指针移动到元素上时触发 |
| mouseup | 当在元素上释放鼠标按钮时触发 |
| mouseover | 当鼠标指针移动到元素上时触发 |
| mouseout | 当鼠标指针移出元素时触发 |
| tap | 手指触摸后马上离开 |
| touchstart | 手指触摸动作开始 |
| touchmove | 手指触摸后移动 |
| touchend | 手指触摸动作结束 |
| drag | 拖拽 |
运动
cax 内置了 to 的能力以连缀的方式写运动效果:
cax.To.get(bitmap) .to() .y(240, 2000, cax.easing.elasticInOut) .rotation(240, 2000, cax.easing.elasticInOut) .end(function () { console.log(" task one has completed!") }) .wait(500) .to() .rotation(0, 1400, cax.easing.elasticInOut) .end(function () { console.log(" task two has completed!") }) .wait(500) .to() .scaleX(1, 1400, cax.easing.elasticInOut) .scaleY(1, 1400, cax.easing.elasticInOut) .end(function () { console.log(" task three has completed!") }) .start()复制代码当然,也可以通过 set 方法支持任意属性的运动,如:
.set('y', 240, 2000, cax.easing.elasticInOut)复制代码等同于
.y(240, 2000, cax.easing.elasticInOut)复制代码自定义对象
自定义 Shape
自定义 Shape 继承自 cax.Shape:
class Sector extends cax.Shape { constructor (r, from, to, option) { super() this.option = option || {} this.r = r this.from = from this.to = to } draw () { this.beginPath() .moveTo(0, 0) .arc(0, 0, this.r, this.from, this.to) .closePath() .fillStyle(this.option.fillStyle) .fill() .strokeStyle(this.option.strokeStyle) .lineWidth(this.option.lineWidth) .stroke() }}复制代码使用 Shape:
const sector = new Sector(10, 0, Math.PI/6, { fillStyle: 'red' lineWidth: 2})stage.add(sector)stage.update()复制代码自定义 Element
自定义 Element 继承自 cax.Group:
class Button extends cax.Group { constructor (option) { super() this.width = option.width this.roundedRect = new cax.RoundedRect(option.width, option.height, option.r) this.text = new cax.Text(option.text, { font: option.font, color: option.color }) this.text.x = option.width / 2 - this.text.getWidth() / 2 * this.text.scaleX this.text.y = option.height / 2 - 10 + 5 * this.text.scaleY this.add(this.roundedRect, this.text) }}export default Button复制代码使用:
const button = new cax.Button({ width: 100, height: 40, text: "Click Me!"})复制代码一般情况下,稍微复杂组合体都建议使用继承自 Group,这样利于扩展也方便管理自身内部的元件。可以看到小游戏的 DEMO 里的 P 、Bullet、Enemy、Background 全都是继承自 Group。
原文发布时间:06月21日
原文作者:当耐特
本文来源掘金如需转载请紧急联系作者
继续阅读与本文标签相同的文章
浅解前端必须掌握的算法(三):直接插入排序
探索 JS 中的模块化
-
太原面经分享:如何在vue面试环节,展示你晋级阿里P6+的技术功底?
2026-06-02栏目: 教程
-
玩烂 Vuex
2026-06-02栏目: 教程
-
美团外卖iOS多端复用的推动、支撑与思考
2026-06-02栏目: 教程
-
前端不止:Web性能优化 – 关键渲染路径以及优化策略
2026-06-02栏目: 教程
-
荷兰将推出全球首个混凝土逐层3D打印住宅区
2026-06-02栏目: 教程
