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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@polpo-studio/cax-next

v1.1.14

Published

一个轻量级的微信小程序 Canvas (type="2d") 渲染引擎

Downloads

19

Readme

cax-next

一个轻量级的微信小程序 Canvas (type="2d") 渲染引擎

特性

  • 高性能且松耦合的渲染架构
  • 超轻量级的代码体积
  • 支持 Canvas 元素管理
  • 支持 Canvas 元素事件体系
  • 完备的 group 嵌套体系
  • 支持可以变形的 clip 裁剪体系
  • 内置文本、位图、绘图对象和多种矢量绘制对象
  • 内置图片加载器

快捷访问

一分钟入门使用

下载本项目到本地,通过 npm 下载依赖,然后使用命令npm run build构建

拷贝 dist 目录下的 mian.js 到微信小程序项目中。

在 page 或者 component 中使用

在的 wxml 里声明 canvas 和声明点击事件判断的 canvas

小程序不支持虚拟 canvas,点击事件判断由 hit-canvas 渲染判断

<view class="container">
  <view class="container">
    <canvas
      bindtouchend="touchend"
      bindtouchmove="touchmove"
      bindtouchstart="touchstart"
      class="canvas"
      id="canvas"
      style="width:{{width}}px;height:{{height}}px"
      type="2d"
    ></canvas>
    <!-- 隐藏hit-canvas -->
    <canvas
      class="hit-canvas"
      id="hitCanvas"
      style="width:{{width}}px;height:{{height}}px"
      type="2d"
    ></canvas>
  </view>
</view>

在 wxss 中隐藏 class="hit-canvas"

.hit-canvas {
  position: fixed;
  top: -999rpx;
  left: -999rpx;
}

在 js 中引入并初始化项目

import mprc from 'main.js';
const { Stage, Group, Graphics, Rect, Circle } = mprc;

Page({
  data: {
    width: 375,
    height: 300
  },

  onReady: async function () {
    const canvas = await this.getContainer('#canvas');
    const stage = new Stage(canvas, this.data.width, this.data.height);
    const hitCanvas = await this.getContainer('#hitCanvas');
    stage.setHitCanvas(hitCanvas);
  },

  // 事件监听
  touchstart: function (event) {
    stage.touchStartHandler(event);
  },

  touchmove: function (event) {
    stage.touchMoveHandler(event);
  },

  touchend: function (event) {
    stage.touchEndHandler(event);
  },

  // 获取canvas对象方法
  getContainer(id) {
    return new Promise((resolve, reject) => {
      const query = wx.createSelectorQuery();
      query
        .select(id)
        .fields({ node: true, size: true })
        .exec(res => {
          const canvas = res[0].node;
          resolve(canvas);
        });
    });
  }
});

初始化项目后绘制内容

// 集合容器,设置透明度
const group = new Group();
group.x = 50;
group.y = 50;
group.alpha = 0.8;

// 绘制矩形图形,设置透明度,透明度会与集合的透明度合并展示
const rect = new Rect(100, 200, {
  fillStyle: '#000000'
});
rect.alpha = 0.2;
rect.hitBox = [0, 0, 100, 200];

// 设置裁剪,将会对举行裁剪
const clipPath = new Graphics();
clipPath.arc(50, 50, 50, 0, Math.PI * 2);
rect.clip(clipPath);

// 绘制圆形图形,设置拖拽事件
const circle = new Circle(50, {
  fillStyle: 'red'
});
circle.on('drag', function (event) {
  circle.x += event.dx;
  circle.y += event.dy;
  stage.update();
});

// 将矩形和圆形图形放入集合之中
group.add(circle);
group.add(rect);

// 将集合放入根容器
stage.add(group);

// 更新渲染
stage.update();

查看项目示例或二次开发

npm run watch

用微信小程序编辑器导入该项目下的 weapp 文件。

内置对象

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 Group();
const rect = new Rect(100, 100, {
  fillStyle: 'black'
});
group.add(rect);
stage.add(group);
stage.update();

group 拥有常用的 add 和 remove 方法进行元素的增加和删除。先 add 的会先绘制,所有后 add 的会盖在先 add 的上面。

Group 方法

add

添加对象

group.add(child);
remove

移除对象

group.remove(child);
empty

清空子对象

group.empty();
replace

使用一个对象替代子对象

group.replace(current, pre);

Stage

最大的顶层容器,继承自 Group,所以 Group 拥有的方法它全都有。

Stage 方法

update

任何元素添加到 Stage 上是看不到的,须要执行 update 方法。

任何元素属性的修改请执行 stage.update() 来更新渲染。

stage.update();
setHitCanvas

设置模拟虚拟 canvas,接受一个参数 canvas 对象,用于计算像素级的 touch 事件目标。

getTextWidth

获取要渲染文字的宽度,两个参数,第一个参数是 text: String,待绘制的文字,第二个参数是font: String,设置的文字的样式。

loadImage

Stage 内置图片加载器,接受一个参数url: string,返回一个 Promise 对象。

Promise 执行结果是 Image 对象,用于 bitmap 绘制。

const stage = new Stage(canvas, 200, 200);
const imgObj2 = await stage.loadImage('../logo.png');

const bitmap = new Bitmap(imgObj2);
stage.add(bitmap);
stage.updata();

Bitmap

Bitmap 接受一个参数,Image 对象的实例,不能使用 url 或者本地路径,bitmap 为同步,无回调方法。

const bitmap = new Bitmap(img);
stage.add(bitmap);
stage.update()

可以设置图片裁剪显示区域,和其他 transform 属性:

const bitmap = new Bitmap(img);
bitmap.x=50;
stage.add(bitmap);

const clipPath = new Graphics();
clipPath.rect(0, 0, 100, 200);
clipPath.x = 0;
clipPath.y = 50;
bitmap.clip(clipPath);
stage.add(bitmap);
stage.update()

Text

文本对象

const text = new Text(item.key, {
  font: `normal normal 20px Arial`,
  color: '#000000',
  baseline: 'bottom'
});

Text 方法

getWidth

获取文本宽度

textObj.getWidth();

Graphics

绘图对象,用于使用基本的连缀方式的 Canvas 指令绘制图形。

const graphics = new Graphics();
graphics
  .beginPath()
  .arc(0, 0, 10, 0, Math.PI * 2)
  .closePath()
  .fillStyle('#f4862c')
  .fill()
  .strokeStyle('black')
  .stroke();

graphics.x = 100;
graphics.y = 200;

stage.add(graphics);

特别注意,如果你在某个循环中执行 graphics 连缀绘制操作,请务必加上 clear() 方法,不然路径叠加到你的浏览器不堪重负:

setInterval(function () {
  graphics
    .clear()
    .beginPath()
    .arc(0, 0, 10, 0, Math.PI * 2)
    .stroke();
}, 16);

Shape

Rect

const rect = new Rect(200, 100, {
  fillStyle: 'black'
});

Circle

const circle = new Circle(10);

Ellipse

const ellipse = new Ellipse(120, 20);

属性

Transform

| 属性名 | 描述 | | -------- | ------------------------------- | | x | 水平偏移 | | y | 竖直偏移 | | scaleX | 水平缩放 | | scaleY | 竖直缩放 | | scale | 同时设置或读取 scaleX 和 scaleY | | rotation | 旋转 | | skewX | 歪斜 X | | skewY | 歪斜 Y | | regX | 旋转基点 X | | regY | 旋转基点 Y |

Alpha

| 属性名 | 描述 | | ------ | ------------ | | alpha | 元素的透明度 |

如果父子都设置了 alpha 会进行乘法叠加。

compositeOperation

| 属性名 | 描述 | | ------------------ | -------------------------------- | | compositeOperation | 源图像绘制到目标图像上的叠加模式 |

注意这里如果自身没有定义 compositeOperation 会进行向上查找,找到最近的定义了 compositeOperation 的父容器作为自己的 compositeOperation。

Shadow

| 属性名 | 描述 | | ------ | ---- | | shadow | 阴影 |

使用方式:

obj.shadow = {
  color: '#42B035',
  offsetX: -5,
  offsetY: 5,
  blur: 10
};

Stage

| Name | Describe | | ----- | -------------------- | | stage | 或者自己所在的 stage |

使用方式:

obj.stage;

方法

destroy

销毁自己

obj.destroy();

注意:Group 销毁会销毁组中所有对象

事件

| 事件名 | 描述 | | ---------- | ------------------ | | tap | 手指触摸后马上离开 | | touchstart | 手指触摸动作开始 | | touchmove | 手指触摸后移动 | | touchend | 手指触摸动作结束 | | drag | 拖拽 |

事件触发精确到像素级。如果要使用元素的矩形区域为点击区域,则需要设置设置元素的 hitBox 。

裁剪

const stage = new Stage(600, 400, 'body');
const bitmap = new Bitmap(imgObj2);

const clipPath = new Graphics();
clipPath.arc(40, 40, 25, 0, Math.PI * 2);
bitmap.clip(clipPath);

stage.add(bitmap);

使用下面的代码可以得到同样的效果:

const stage = new Stage(600, 400, 'body');
const bitmap = new Bitmap(imgObj2);

const clipPath = new Graphics();
clipPath.x = 40;
clipPath.y = 40;
clipPath.arc(0, 0, 25, 0, Math.PI * 2);
bitmap.clip(clipPath);

stage.add(bitmap);

裁剪区域同样支持所有 transform 属性(x,y,scaleX,scaleY,rotation,skewX,skewY,regX,regY)。

自定义对象

自定义 Shape

自定义 Shape 继承自 Shape:

class Sector extends 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 继承自 Group:

class Button extends Group {
  constructor (option) {
    super()
    this.width = option.width
    this.roundedRect = new  RoundedRect(option.width, option.height, option.r)
    this.text = new 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 Button({
  width: 100,
  height: 40,
  text: 'Click Me!'
});

一般情况下,稍微复杂组合体都建议使用继承自 Group,这样利于扩展也方便管理自身内部的元件。

图片加载器

图片加载器返回 Promise

const { loadImage } = mprc;

// canvas参数为获取的canvas 2d对象实例
const imgObj = await loadImage('../logo.png', canvas);

// stage的图片加载方法
const stage = new Stage(canvas, 200, 200);
const imgObj2 = await stage.loadImage('../logo.png');

const bitmap = new bitMap(imgObj2);
stage.add(bitmap);
stage.updata();

注意事项

该项目参考了小程序、小游戏以及 Web 通用 Canvas 渲染引擎 Cax 和 spritejs。对 Cax 和 spritejs 开发者表示感谢。

  • Cax 是跨平台项目,但仅支持小程序旧版本 canvas(微信已放弃维护)。本项目仅支持微信小程序 canvas2d ,(基础库 2.9.0 以上版本)

  • 项目的一些方法和属性与 Cax 相似,但有些不同,使用时请注意区分

  • 该项目初始化传入参数为 canvas 对象而不是 ID,所以应获取 canvas 对象后初始化,具体请查看示例代码

  • 暂不支持的功能

    • 不支持 Fixed 属性
    • 不支持帧动画
    • 不支持 SVG Path 渲染
    • 不支持滤镜功能

项目轻量,使用简单,可用于对文字、图片、图形等绘制。适合海报、拼图、图表展示等项目开发。

对手势相关事件有良好的支持,内置拖拽功能,支持矩形边界和像素级边界两种选择方式。

项目对 canvas 的初始化采用显示设置宽高和通过缩放适应像素密度,显示高清。

对于较为复杂的项目,建议通过类开发组件,即每一组件是一个类,类中包含自己的布局和更新方法,这样可以开发出高度复用的组件,后续也便于维护。

To do

  • 帧动画

License

MIT