galaxy-canvas-sign
Version:
银河集团Canvas签名sdk
205 lines (200 loc) • 8.58 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.CanvasSign = factory());
})(this, (function () { 'use strict';
// 判断是否在移动端
const isMobile = () => 'ontouchstart' in document.documentElement;
class SignCanvas {
constructor(options) {
this.options = options;
if (this.options.cropPaddingX === undefined) {
this.options.cropPaddingX = 10;
}
this.isMobile = isMobile();
this.ctx = null;
this.currentPoints = [];
this.beginPoints = [];
this.isPress = false;
this.left = 0;
this.top = 0;
this.canvas = null;
this.eventFlag = false;
this.once = false;
}
// 根据配置初始画布
init() {
if (this.once === true) {
return;
}
this.once = true;
const dom = document.querySelector(this.options.el);
if (dom) {
const el = document.createElement("canvas");
el.width = this.options.width || 800;
el.height = this.options.height || 400;
el.style.border = `1px dashed #666`;
dom.appendChild(el);
if (this.isMobile) {
const { left, top } = el.getBoundingClientRect();
this.left = left;
this.top = top;
}
this.canvas = el;
this.initCanvas(el);
this.addEvents(el);
}
else {
console.error(`Not found node:${this.options.el}`);
}
return this;
}
// 初始化画布上下文
initCanvas(canvas) {
this.ctx = canvas.getContext('2d');
}
// 添加事件
addEvents(canvas) {
const eventStart = this.isMobile ? 'touchstart' : 'mousedown';
const eventEnd = this.isMobile ? 'touchend' : 'mouseup';
const eventMove = this.isMobile ? 'touchmove' : 'mousemove';
canvas.addEventListener(eventStart, (e) => {
if (this.isMobile) {
e = e.touches[0];
}
this.isPress = true;
// const x:number = e.pageX - this.left + 0.5
// const y:number = e.pageY - this.top + 0.5
const x = this.isMobile ? e.clientX - this.left + 0.5 : e.offsetX + 0.5;
const y = this.isMobile ? e.clientY - this.top + 0.5 : e.offsetY + 0.5;
this.currentPoints.push([x, y]);
this.beginPoints = [x, y];
if (this.isMobile && this.eventFlag === false) {
this.eventFlag = true;
this.disablePullDownRefresh();
}
});
canvas.addEventListener(eventMove, (e) => {
const context = this.ctx;
if (this.isMobile) {
e = e.touches[0];
}
if (this.isPress) {
// const x = e.clientX - this.left + 0.5
// const y = e.clientY - this.top + 0.5
const x = this.isMobile ? e.clientX - this.left + 0.5 : e.offsetX + 0.5;
const y = this.isMobile ? e.clientY - this.top + 0.5 : e.offsetY + 0.5;
this.currentPoints.push([x, y]);
let endPoint = [];
let controlPoint = [];
if (this.currentPoints.length > 3) {
const lastTwoPoints = this.currentPoints.slice(-2);
controlPoint = lastTwoPoints[0];
endPoint = [
(lastTwoPoints[0][0] + lastTwoPoints[1][0]) / 2,
(lastTwoPoints[0][1] + lastTwoPoints[1][1]) / 2,
];
}
context.beginPath();
context.lineWidth = this.options.lineWidth || 2;
context.lineCap = this.options.lineCap || 'round';
context.moveTo(this.beginPoints[0], this.beginPoints[1]);
context.quadraticCurveTo(controlPoint[0], controlPoint[1], endPoint[0], endPoint[1]);
this.beginPoints = endPoint;
context.strokeStyle = this.options.color || '#000';
context.stroke();
}
});
canvas.addEventListener(eventEnd, () => {
this.isPress = false;
if (this.isMobile) {
document.querySelector('body').removeEventListener('touchmove', this.pullDownCallback, false);
this.eventFlag = false;
}
});
if (!this.isMobile) {
canvas.addEventListener('mouseout', () => {
this.isPress = false;
});
}
}
// 解决移动端在画布上touchmove时触发网页下拉操作问题
disablePullDownRefresh() {
document.querySelector('body').addEventListener('touchmove', this.pullDownCallback, { passive: false });
}
// 阻止下拉
pullDownCallback(e) {
e.preventDefault();
}
// 清空画布
clear() {
this.eventFlag = false;
this.currentPoints = [];
this.beginPoints = [];
this.isPress = false;
this.eventFlag = false;
this.ctx && this.ctx.clearRect(0, 0, this.options.width, this.options.height);
}
// 判断点信息是否为空
getPoints() {
return this.currentPoints;
}
// 获取当前截图
exportCanvas() {
if (this.options.crop) {
const offCanvas = this.cropRange();
return offCanvas;
}
else {
return this.canvas;
}
}
cropRange() {
const imageData = this.ctx.getImageData(0, 0, this.options.width, this.options.height);
const len = imageData.data.length;
const obj = {
xmin: 0,
xmax: 0,
ymin: 0,
ymax: 0
};
let flag = false;
for (let i = 0; i < len; i += 4) {
const y = Math.floor((i + 3) / (this.options.width * 4));
const x = (((i + 4) / 4) % this.options.width);
if (imageData.data[i + 3] !== 0) { // 代表笔画点
if (flag === false) {
obj.xmin = x;
obj.xmax = x;
obj.ymin = y;
obj.ymax = y;
flag = true;
}
if (x < obj.xmin) {
obj.xmin = x;
}
if (x > obj.xmax) {
obj.xmax = x;
}
if (y < obj.ymin) {
obj.ymin = y;
}
if (y > obj.ymax) {
obj.ymax = y;
}
}
}
const offCanvas = document.createElement("canvas");
const cropPaddingX = this.options.cropPaddingX !== undefined ? this.options.cropPaddingX : 10;
const cropPaddingY = this.options.cropPaddingY !== undefined ? this.options.cropPaddingY : 10;
offCanvas.width = (obj.xmax - obj.xmin) + 2 * cropPaddingX;
offCanvas.height = (obj.ymax - obj.ymin) + 2 * cropPaddingY;
const offCtx = offCanvas.getContext("2d");
if (this.canvas && offCtx) {
offCtx.drawImage(this.canvas, obj.xmin, obj.ymin, obj.xmax - obj.xmin, obj.ymax - obj.ymin, cropPaddingX, cropPaddingY, obj.xmax - obj.xmin, obj.ymax - obj.ymin);
}
return offCanvas;
}
}
return SignCanvas;
}));