1.2.3 • Published 9 months ago

wx-canvas-tool v1.2.3

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

wx-canvas-tool

适用于微信小程序canvas(2d)的简单绘制工具库

功能还很简单,后续有时间再慢慢完善

实现的功能

  • 内置自定义图形

    • Rect 矩形

    • Circle 圆形

    • Line 线

    • ArrowLine 箭头线

    • Image 图片

    • Text 文本

    • Path 路径

    • 自定义图形

  • 手指拖拽移动画布、图形

  • 图形点击事件

  • 双指缩放画布

  • 画布及图形均支持旋转(scale)、平移(translate)、缩放(scale)变换

示例

基本使用

微信小程序原生开发导入

  1. 如果项目根目录没有package.json,在根目录执行npm init -y

  2. 执行npm install wx-canvas-tool

  3. 在根目录的project.config.json文件里的setting配置里添加

    "packNpmRelationList": [
      {
        "packageJsonPath": "./package.json",
        "miniprogramNpmDistDir": "./miniprogram/"
      }
    ],
  4. 微信开发者工具点击工具 -> 构建npm

  5. 项目中用require导入使用const { CanvasTool, Rect } = require('wx-canvas-tool');

uniapp

<canvas id="canvas" type="2d" style="width: 100%; height: 100%"></canvas>

<script>
  import { CanvasTool, Rect } from 'wx-canvas-tool';
  let canvasTool;

  export default {
    data() {
      return {
        canvasReady: false,
      }
    },
    onReady() {
      canvasTool = new CanvasTool({
        id: 'canvas', // canvas的id
        pageInstance: this, // 页面实例
        afterInit: () => this.canvasReady = true // 初始化成功回调
      });
    },
    watch: {
      canvasReady(val) {
        if (val) {
          // addShape将图形添加到画布
          canvasTool.addShape(new Rect({
            x: 100,
            y: 100,
            width: 50,
            height: 50,
            style: {
              fillStyle: 'blue',
              strokeStyle: 'black',
            },
            fill: true,
            stroke: true,
          }));
          // 首次需调用draw才会实际绘制所有图形,此外draw方法也可以清除画布再重新绘制所有图形
          canvasTool.draw();
        }
      }
    }
  }
</script>

微信小程序原生

wxml:

<canvas
  id="canvas"
  type="2d"
  style="width: 100vw; height: 100vh;"
></canvas>

js:

const { CanvasTool, Rect } = require('wx-canvas-tool');
Page({
  data: {
    canvasTool: null,
  },
  onReady() {
    this.setData({
      canvasTool: new CanvasTool({
        id: 'canvas',
        pageInstance: this,
        draggable: true,
        afterInit: () => this.onCanvasInit()
      })
    });
  },
  onCanvasInit() {
    // addShape将图形添加到画布
    this.data.canvasTool.addShape(new Rect({
      x: 100,
      y: 100,
      height: 50,
      width: 50,
      style: {
        fillStyle: 'blue',
        strokeStyle: 'black',
      },
      fill: true,
      stroke: true,
    }));
    this.data.canvasTool.draw();
  }
});

开启拖拽/缩放

tip: 如果出现拖拽卡顿,微信小程序原生开发建议用catch:touchmove来绑定touchomve事件,uniapp用@touchomve.native.stop

uniapp

<canvas 
  id="canvas" 
  type="2d" 
  @touchstart="onTouchstart"
  @touchmove="onTouchmove"
  @touchend="onTouchend"
  @touchcanel="onTouchcancel"
  style="width: 100%; height: 100%">
</canvas>

<script>
  import { CanvasTool, Rect } from 'wx-canvas-tool';
  let tool;

  export default {
    data() {
      return {
        canvasReady: false,
      }
    },
    onReady() {
      tool = new CanvasTool({
        id: 'canvas',
        pageInstance: this,
        draggable: true, // 开启拖拽
        zoomable: true, // 开启缩放
        afterInit: () => this.canvasReady = true
      });
    },
    watch: {
      canvasReady(val) {
        if (val) {
          tool.addShape(new Rect({
            x: 100,
            y: 100,
            width: 100,
            height: 100,
            style: {
              fillStyle: 'blue',
              strokeStyle: 'black',
            },
            fill: true,
            stroke: true,
          }));
          tool.draw();
        }
      }
    },
    methods: {
      // 若要使触摸生效,需要将触摸事件都与实例绑定
      onTouchstart(e) {
        tool.onTouchstart(e);
      },
      onTouchmove(e) {
        tool.onTouchmove(e);
      },
      onTouchend() {
        tool.onTouchend();
      },
      onTouchcancel() {
        tool.onTouchcancel();
      },
    }
  }
</script>

微信小程序原生

wxml:

<canvas
  id="canvas"
  type="2d"
  bind:touchstart="onTouchstart"
  bind:touchmove="onTouchmove"
  bind:touchcancel="onTouchcancel"
  bind:touchend="onTouchend"
  style="width: 100vw; height: 100vh;"
></canvas>

js:

const { CanvasTool, Rect } = require('wx-canvas-tool');
Page({
  data: {
    canvasTool: null,
  },
  onReady() {
    this.setData({
      canvasTool: new CanvasTool({
        id: 'canvas',
        pageInstance: this,
        draggable: true,
        afterInit: () => this.onCanvasInit()
      })
    });
  },
  onCanvasInit() {
    this.data.canvasTool.addShape(new Rect({
      x: 100,
      y: 100,
      height: 50,
      width: 50,
      style: {
        fillStyle: 'blue',
        strokeStyle: 'black',
      },
      fill: true,
      stroke: true,
    }));
    this.data.canvasTool.draw();
  },
  onTouchstart(e) {
    this.data.canvasTool.onTouchstart(e);
  },
  onTouchmove(e) {
    this.data.canvasTool.onTouchmove(e);
  },
  onTouchcancel(e) {
    this.data.canvasTool.onTouchend(e);
  },
  onTouchend(e) {
    this.data.canvasTool.onTouchend(e);
  },
});

图形点击事件

uniapp

<canvas 
  id="canvas" 
  type="2d" 
  @tap="onTap"
  style="width: 100%; height: 100%">
</canvas>

<script>
  import { CanvasTool, Rect } from 'wx-canvas-tool';
  let tool;

  export default {
    data() {
      return {
        canvasReady: false,
      }
    },
    onReady() {
      tool = new CanvasTool({
        id: 'canvas',
        pageInstance: this,
        afterInit: () => this.canvasReady = true
      });
    },
    watch: {
      canvasReady(val) {
        if (val) {
          tool.addShape(new Rect({
            x: 100,
            y: 100,
            width: 100,
            height: 100,
            style: {
              fillStyle: 'blue',
              strokeStyle: 'black',
            },
            fill: true,
            stroke: true,
            // 目前只支持tap(点击)事件
            onTap: () => console.log('rect clicked'),
          }));
          tool.draw();
        }
      }
    },
    methods: {
      // 若要使点击事件生效,需要将点击事件与实例绑定
      onTap(e) {
        tool.onTap(e);
      }
    }
  }
</script>

微信小程序原生

<canvas
  id="canvas"
  type="2d"
  bind:tap="onTap"
  style="width: 100vw; height: 100vh;"
></canvas>

js

const { CanvasTool, Rect } = require('wx-canvas-tool');
Page({
  data: {
    canvasTool: null,
  },
  onReady() {
    this.setData({
      canvasTool: new CanvasTool({
        id: 'canvas',
        pageInstance: this,
        draggable: true,
        afterInit: () => this.onCanvasInit()
      })
    });
  },
  onCanvasInit() {
    this.data.canvasTool.addShape(new Rect({
      x: 100,
      y: 100,
      height: 50,
      width: 50,
      style: {
        fillStyle: 'blue',
        strokeStyle: 'black',
      },
      fill: true,
      stroke: true,
      onTap: () => console.log('rect clicked')
    }));
    this.data.canvasTool.draw();
  },
  onTap(e) {
    this.data.canvasTool.onTap(e);
  },
});

内置图形

Rect 矩形

import { Rect } from 'wx-canvas-tool';

const rect = new Rect({
  x: 100,
  y: 100,
  width: 100,
  height: 100,
  style: { // style属性可以传所有html5 CanvasRenderingContext2D的style属性
    fillStyle: 'blue',
    strokeStyle: 'black',
  },
  fill: true, // 描边
  stroke: true, // 填充
  borderRadius: 20, // 圆角,也可以传数组[20, 20, 20, 20]
  rotation: 45, // 旋转角度,其他所有图形也都支持构造时传入
  translation: { // 平移,其他所有图形也都支持构造时传入
    x: 10,
    y: 10,
  },
});

Circle 圆形

import { Circle } from 'wx-canvas-tool';

const circle = new Circle({
  x: 100, // 圆心x
  y: 100, // 圆心y
  radius: 50, // 半径
  style: {
    fillStyle: 'blue',
    strokeStyle: 'black',
  },
  fill: true, // 描边
  stroke: true, // 填充
  translation: { // 平移
    x: 10,
    y: 10,
  },
});

Line 线

import { Line } from 'wx-canvas-tool';

const line = new Line({
  points: [
    5, 70, // x, y
    140, 23, // x, y
    250, 60,
    300, 20
    // ...
  ],
  color: 'green', // 颜色
  dash: [5, 5], // 虚线,会调用CanvasRenderingContext2D的setLineDash()
});

// 实例方法,追加点
line.append([100, 100]);

ArrowLine 带箭头的线

import { ArrowLine } from 'wx-canvas-tool'

const arr = new ArrowLine({
  points: [
    20, 20,
    80, 80
  ],
  tail: true, // 是否在线段末端处绘制箭头,默认true
  arrowHeight: 30, // 线段末端箭头等腰三角形高,默认20
  arrowWidth: 10, // 线段末端箭头等腰三角形宽,默认10
  head: true, // 是否在线段开始处绘制箭头
  headArrowWidth: 10, // 线段开始处箭头等腰三角形宽,默认20,仅head为true时生效
  headArrowHeight: 30, // 线段开始处箭头等腰三角形高,默认10,仅head为true时生效
  color: 'red',
})

Image 图片

import { CanvasTool, Image } from 'wx-canvas-tool';

export default {
  data() {
    return {
      canvasReady: false,
    }
  },
  onReady() {
    tool = new CanvasTool({
      id: 'canvas',
      pageInstance: this,
      afterInit: () => this.canvasReady = true
    });
  },
  watch: {
    canvasReady(val) {
      if (val) {
        tool.addShape(new Image({
          src: 'https://example.com/image.png',
          x: 100, // 同drawImage(image, dx, dy)的dx
          y: 100, // 同drawImage(image, dx, dy)的dy
          width: 100, // 同drawImage(image, dx, dy, dWidth, dHeight)的dWidth
          height: 100, // 同drawImage(image, dx, dy, dWidth, dHeight)的dHeight
          sourceX: 0, // 同drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)的sx
          sourceY: 0, // 同drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)的sy
          sourceWidth: 100, // 同drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)的sWidth
          sourceHeight: 100, // 同drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)的sHeight
        }, tool.canvas /* 需传Canvas实例 */));
        // draw()方法会等待所有add进去的图片加载完成才开始绘制图形
        tool.draw();
      }
    }
  }
}

Text 文本

import { Text } from 'wx-canvas-tool';

const text = new Text({
  x: 100,
  y: 100,
  text: 'Hello World',
  baseline: 'top', // 基线位置,同CanvasRenderingContext2D的textBaseline属性
  align: 'center', // 对齐方式,同CanvasRenderingContext2D的textAlign属性
  font: '20px Arial', // 字体
  color: 'green' // 颜色
  strokeWidth: 2, // 描边线宽度
  maxWdith: 200, // 最大宽度
  overflow: '...', // 自定义超出maxWdith部分替换的字符
  fill: true, // 调用fillText绘制文本
  /* stroke: true, // 调用strokeText绘制文本 */
});

Path 路径

目前暂不支持传入svg path

传入svg path字符串:

import { Path } from 'wx-canvas-tool';

const path = new Path({
  x: 100,
  y: 100,
  path: 'M 5 70 L 140 23 L 250 60 L 300 20', // svg path字符串
  style: { strokeStyle: 'black' },
  stroke: true,
}, tool.canvas /* 跟Image一样,需传Canvas实例 */);

使用回调函数自定义路径:

import { Path } from 'wx-canvas-tool';

const path = new Path({
  x: 100,
  y: 100,
  pathFunc: path => {
    path.moveTo(5, 70);
    path.lineTo(140, 23);
    // ...
  },
  style: {
    strokeStyle: 'black',
  },
  stroke: true,
}, tool.canvas /* 跟Image一样,需传Canvas实例 */);

自定义图形

import { CustomShape } from 'wx-canvas-tool'

const custom = new CustomShape({
  x: 60,
  y: 60,
  style: { fillStyle: 'green' },
  fill: true,
  onTap: () => console.log('??')
}, ctx => {
  /* 
    绘制函数,如果不传最后一个该函数的话,则该函数内最好不要设置样式,
    样式统一在构造函数第一个参数的style属性中设置,否则会影响点击检测

    该绘制函数内的画布绘画原点即是上面传入的x,y属性
    因此,ctx.rect(0, 0, 80, 80)画出来的矩形实际上在画布中左上角的位置是(60, 60)
  */
  ctx.rect(0, 0, 80, 80)
}, ctx => {
  /* 
    绘制点击检测图形,该函数可不传,默认点击检测区域就是按照上一个函数内定义的绘制命令而绘制
    该函数内最好不要设置样式,否则会影响点击检测
  */
  // ...
})

椭圆

import { Ellipse } from 'wx-canvas-tool'

const ellipse = new Ellipse({
  x: 50,
  y: 50,
  radusX: 80, // x轴半径
  radusY: 50, // y轴半径
  style: { fillStyle: 'blue' },
  fill: true,
})

属性和方法

CanvasTool

属性

属性类型说明默认值
idstringcanvas的id-
pageInstanceobject页面实例-
draggableboolean是否开启拖拽false
zoomableboolean是否开启拖拽false
widthnumbercanvas宽度,只读属性,设置该属性无意义-
heightnumbercanvas高度,只读属性,设置该属性无意义-
shapesarray图形数组[]
canvasobjectcanvas实例,只读属性,设置该属性无意义-
ctxobjectcanvas的context实例,只读属性,设置该属性无意义-

方法

方法说明
addShape添加图形
clear清除画布
draw清除画布并重新绘制所有图形,与update方法的区别是会等待所有图片加载完成
update清除画布并重新绘制所有图形
clearShapes清除图形数组
resetTransform重置画布变换
translate平移变换
scale缩放
scaleAt以指定点为中心缩放
rotate旋转变换
rotateAt以指定点为中心旋转
getTranslateX获取x轴平移值
getTranslateY获取y轴平移值
getScaleX获取x轴缩放
getScaleY获取y轴缩放
getRotation获取旋转角度
calcText计算文本高度宽度
onTouchstart手指按下时触发
onTouchmove手指移动时触发
onTouchend手指抬起时触发
onTouchcancel手指离开时触发
onTap点击时触发
1.2.3

9 months ago

1.2.2

9 months ago

1.2.1

9 months ago

1.2.0

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago