当前位置:   article > 正文

一个轻量级的微信小程序 Canvas (type=“2d“) 渲染引擎_小程序canvas点击事件

小程序canvas点击事件

mini-programs-rc

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

特性

  • 高性能且松耦合的渲染架构

  • 超轻量级的代码体积

  • 支持 Canvas 元素管理

  • 支持 Canvas 元素事件体系

  • 完备的 group 嵌套体系

  • 支持可以变形的 clip 裁剪体系

  • 内置文本、位图、绘图对象和多种矢量绘制对象

  • 内置图片加载器


快捷访问

一分钟入门使用

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

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

在 page 或者 component 中使用

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

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

  1. <view class="container">
  2. <view class="container">
  3. <canvas
  4. bindtouchend="touchend"
  5. bindtouchmove="touchmove"
  6. bindtouchstart="touchstart"
  7. class="canvas"
  8. id="canvas"
  9. style="width:{{width}}px;height:{{height}}px"
  10. type="2d"
  11. ></canvas>
  12. <!-- 隐藏hit-canvas -->
  13. <canvas
  14. class="hit-canvas"
  15. id="hitCanvas"
  16. style="width:{{width}}px;height:{{height}}px"
  17. type="2d"
  18. ></canvas>
  19. </view>
  20. </view>

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

  1. .hit-canvas {
  2. position: fixed;
  3. top: -999rpx;
  4. left: -999rpx;
  5. }

在 js 中引入并初始化项目

  1. import mprc from 'main.js';
  2. const { Stage, Group, Graphics, Rect, Circle } = mprc;
  3. Page({
  4. data: {
  5. width: 375,
  6. height: 300
  7. },
  8. onReady: async function () {
  9. const canvas = await this.getContainer('#canvas');
  10. const stage = new Stage(canvas, this.data.width, this.data.height);
  11. const hitCanvas = await this.getContainer('#hitCanvas');
  12. stage.setHitCanvas(hitCanvas);
  13. },
  14. // 事件监听
  15. touchstart: function (event) {
  16. stage.touchStartHandler(event);
  17. },
  18. touchmove: function (event) {
  19. stage.touchMoveHandler(event);
  20. },
  21. touchend: function (event) {
  22. stage.touchEndHandler(event);
  23. },
  24. // 获取canvas对象方法
  25. getContainer(id) {
  26. return new Promise((resolve, reject) => {
  27. const query = wx.createSelectorQuery();
  28. query
  29. .select(id)
  30. .fields({ node: true, size: true })
  31. .exec(res => {
  32. const canvas = res[0].node;
  33. resolve(canvas);
  34. });
  35. });
  36. }
  37. });

初始化项目后绘制内容

  1. // 集合容器,设置透明度
  2. const group = new Group();
  3. group.x = 50;
  4. group.y = 50;
  5. group.alpha = 0.8;
  6. // 绘制矩形图形,设置透明度,透明度会与集合的透明度合并展示
  7. const rect = new Rect(100, 200, {
  8. fillStyle: '#000000'
  9. });
  10. rect.alpha = 0.2;
  11. rect.hitBox = [0, 0, 100, 200];
  12. // 设置裁剪,将会对举行裁剪
  13. const clipPath = new Graphics();
  14. clipPath.arc(50, 50, 50, 0, Math.PI * 2);
  15. rect.clip(clipPath);
  16. // 绘制圆形图形,设置拖拽事件
  17. const circle = new Circle(50, {
  18. fillStyle: 'red'
  19. });
  20. circle.on('drag', function (event) {
  21. circle.x += event.dx;
  22. circle.y += event.dy;
  23. stage.update();
  24. });
  25. // 将矩形和圆形图形放入集合之中
  26. group.add(circle);
  27. group.add(rect);
  28. // 将集合放入根容器
  29. stage.add(group);
  30. // 更新渲染
  31. 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

  1. const group = new Group();
  2. const rect = new Rect(100, 100, {
  3. fillStyle: 'black'
  4. });
  5. group.add(rect);
  6. stage.add(group);
  7. 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 绘制。

  1. const stage = new Stage(canvas, 200, 200);
  2. const imgObj2 = await stage.loadImage('../logo.png');
  3. const bitmap = new Bitmap(imgObj2);
  4. stage.add(bitmap);
  5. stage.updata();

Bitmap

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

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

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

  1. const bitmap = new Bitmap(img);
  2. bitmap.x=50;
  3. stage.add(bitmap);
  4. const clipPath = new Graphics();
  5. clipPath.rect(0, 0, 100, 200);
  6. clipPath.x = 0;
  7. clipPath.y = 50;
  8. bitmap.clip(clipPath);
  9. stage.add(bitmap);
  10. stage.update()

Text

文本对象

  1. const text = new Text(item.key, {
  2. font: `normal normal 20px Arial`,
  3. color: '#000000',
  4. baseline: 'bottom'
  5. });
Text 方法
getWidth

获取文本宽度

textObj.getWidth();

Graphics

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

  1. const graphics = new Graphics();
  2. graphics
  3. .beginPath()
  4. .arc(0, 0, 10, 0, Math.PI * 2)
  5. .closePath()
  6. .fillStyle('#f4862c')
  7. .fill()
  8. .strokeStyle('black')
  9. .stroke();
  10. graphics.x = 100;
  11. graphics.y = 200;
  12. stage.add(graphics);

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

  1. setInterval(function () {
  2. graphics
  3. .clear()
  4. .beginPath()
  5. .arc(0, 0, 10, 0, Math.PI * 2)
  6. .stroke();
  7. }, 16);

Shape

Rect
  1. const rect = new Rect(200, 100, {
  2. fillStyle: 'black'
  3. });
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

阴影

使用方式:

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

Stage

Name

Describe

stage

或者自己所在的 stage

使用方式:

obj.stage;

方法

destroy

销毁自己

obj.destroy();

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

事件

事件名

描述

tap

手指触摸后马上离开

touchstart

手指触摸动作开始

touchmove

手指触摸后移动

touchend

手指触摸动作结束

drag

拖拽

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

裁剪

  1. const stage = new Stage(600, 400, 'body');
  2. const bitmap = new Bitmap(imgObj2);
  3. const clipPath = new Graphics();
  4. clipPath.arc(40, 40, 25, 0, Math.PI * 2);
  5. bitmap.clip(clipPath);
  6. stage.add(bitmap);

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

  1. const stage = new Stage(600, 400, 'body');
  2. const bitmap = new Bitmap(imgObj2);
  3. const clipPath = new Graphics();
  4. clipPath.x = 40;
  5. clipPath.y = 40;
  6. clipPath.arc(0, 0, 25, 0, Math.PI * 2);
  7. bitmap.clip(clipPath);
  8. stage.add(bitmap);

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

自定义对象

自定义 Shape

自定义 Shape 继承自 Shape:

  1. class Sector extends Shape {
  2. constructor(r, from, to, option) {
  3. super();
  4. this.option = option || {};
  5. this.r = r;
  6. this.from = from;
  7. this.to = to;
  8. }
  9. draw() {
  10. this.beginPath()
  11. .moveTo(0, 0)
  12. .arc(0, 0, this.r, this.from, this.to)
  13. .closePath()
  14. .fillStyle(this.option.fillStyle)
  15. .fill()
  16. .strokeStyle(this.option.strokeStyle)
  17. .lineWidth(this.option.lineWidth)
  18. .stroke();
  19. }
  20. }

使用 Shape:

  1. const sector = new Sector(10, 0, Math.PI/6, {
  2. fillStyle: 'red'
  3. lineWidth: 2
  4. })
  5. stage.add(sector)
  6. stage.update()

自定义 Element

自定义 Element 继承自 Group:

  1. class Button extends Group {
  2. constructor (option) {
  3. super()
  4. this.width = option.width
  5. this.roundedRect = new RoundedRect(option.width, option.height, option.r)
  6. this.text = new Text(option.text, {
  7. font: option.font,
  8. color: option.color
  9. })
  10. this.text.x = option.width / 2 - this.text.getWidth() / 2 * this.text.scaleX
  11. this.text.y = option.height / 2 - 10 + 5 * this.text.scaleY
  12. this.add(this.roundedRect, this.text)
  13. }
  14. }
  15. export default Button

使用:

  1. const button = new Button({
  2. width: 100,
  3. height: 40,
  4. text: 'Click Me!'
  5. });

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

图片加载器

图片加载器返回 Promise

  1. const { loadImage } = mprc;
  2. // canvas参数为获取的canvas 2d对象实例
  3. const imgObj = await loadImage('../logo.png', canvas);
  4. // stage的图片加载方法
  5. const stage = new Stage(canvas, 200, 200);
  6. const imgObj2 = await stage.loadImage('../logo.png');
  7. const bitmap = new bitMap(imgObj2);
  8. stage.add(bitmap);
  9. 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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/549724
推荐阅读
相关标签
  

闽ICP备14008679号