preface:
During this period of time, a new requirement was encountered during the project iteration. A Pc version electronic signature function was implemented based on react, and pictures were generated and uploaded. So I thought signature_pad And used this plug-in in the project
I have to say that the wheels made by others are really fragrant. Out of curiosity, I want to use native to realize the function of electronic signature
The following is the implementation process
HTML and css can be referenced Source code , there is no more introduction here
First introduce eventBus To facilitate code decoupling
Then implement the Base class to store public methods and attributes. What common attributes or methods can be added later
//Base classes: public methods and properties import event from './eventBus.js' export default class Base { constructor(canvasEle, dom = document) { this.event = event //Register publish subscription this.canvasEle = canvasEle //Canvas label to be operated this.dom = dom //dom return this; } }
After completion, we first implement the electronic signature function of Pc version, and create a new PcPrint inherited from Base, referring to the previously written Mouse drag case , realize the drag and drop function on canvas and publish the coordinates of event results.
clearDefaultEvent function and getClient function are implemented in Base class
// PC side, mouse event import Base from './base.js' let that = null export default class PcPrint extends Base { constructor(ele, dom) { super(ele, dom) that = this //Register global this this.init() return this; } init() { that.canvasEle.addEventListener('mousedown', that.onMouseDown) } onMouseDown(e = event) { that.clearDefaultEvent(e) that.dom.addEventListener('mouseup', that.onMouseUp) //Add mouseup to dom to avoid other problems caused by moving out of the canvas when the mouse clicks that.canvasEle.addEventListener('mousemove', that.onMouseMove) that.event.emitEvent('pointStart', that.getClient(e)) //Trigger signing start event } onMouseUp(e = event) { that.clearDefaultEvent(e) that.event.emitEvent('pointEnd') //Trigger end signing event that.canvasEle.removeEventListener('mousemove', that.onMouseMove) //Remove move event } onMouseMove(e = event) { that.clearDefaultEvent(e) that.event.emitEvent('pointMove', that.getClient(e)) //Trigger signing event } }
Add the following code to the Base class:
/** * Default and cancel bubble events * @param e Event object */ clearDefaultEvent(e) { e.preventDefault() e.stopPropagation() } /** * Get the coordinates of the event element from the visible area of the body * @param target Event target */ getClient(target) { return { x: target.clientX, y: target.clientY } }
Then, we subscribe to the three publications thrown by the event, create a new Print class, and draw the obtained coordinates through canvas
import Base from "./Base.js" import PcPrint from './pc.js'; // import MobilePrint from './mobile.js'; let that = null export default class Print extends Base { constructor(canvasEle, options, dom) { super(canvasEle, dom) that = this this.options = options //Configure the brush color, thickness and whether to turn on the mobile terminal or PC terminal, this.init() //Initialize properties, configure, register, publish and subscribe, etc this.initCanvas() //Initialize canvas return this } init() { //Pc and Mobile enable switches this.Pc = this.options.Pc ? (new PcPrint(this.canvasEle)) : null // this.Mobile = this.options.Mobile ? (new MobilePrint(this.canvasEle)) : null this.point = null //Store last coordinates this.event.onEvent('pointMove', that.pointMove) //Subscription signing event this.event.onEvent('pointStart', that.pointStart) //Subscription signing start event this.event.onEvent('pointEnd', that.pointEnd) //Subscription signing end event } initCanvas() { this.clientRect = this.canvasEle.getBoundingClientRect() // Gets the offset of the label from the visible area this.canvasEle.width = this.canvasEle.parentNode.offsetWidth //Set to the width of the parent element this.canvasEle.height = this.canvasEle.parentNode.offsetHeight //Set to the height of the parent element this.context = this.canvasEle.getContext('2d') this.context.strokeStyle = this.options.color; // line color this.context.lineWidth = this.options.weight; // Line width } pointStart(point) { that.point = that.shiftingPosition(point, that.clientRect) //Initialization start position } pointEnd() { that.point = null //Clear start position } pointMove(point) { that.canvasDraw(that.shiftingPosition(point, that.clientRect)) //Signature effect } canvasDraw(point) { //Canvas operation this.context.beginPath() //New (reset) path this.context.moveTo(this.point.x, this.point.y) //The starting point of canvas painting moves to the previous coordinate this.context.lineTo(point.x, point.y) //Canvas from previous coordinate to current coordinate this.context.stroke() //Draw from moveTo to lineTo this.context.closePath() //Creates a path from the current coordinate back to the previous coordinate that.point = point //Assign this coordinate to the previous one in the next move } }
Considering the offset problem of canvas, the shiftingPosition function is added to Base to solve the coordinate offset problem during canvas drawing
/** * Offset canvas offset * @param point Current coordinates * @param shift Offset */ shiftingPosition(point, shift) { return { x: point.x - shift.left, y: point.y - shift.top } }
Finally, instantiate the electronic signature in index
<script type="module"> import Print from "./js/print.js" new Print(printBox,{ Pc:true, Mobile:true, color:'lightcoral', weight:5 }) </script>
The effect is as follows:
After the Pc end is implemented, the Mobile end has the same code. In addition to not using the event type, there is also the multi finger touch support of the Mobile end, and touchevent supports double finger events. At this time, we need to judge whether to single finger input
// Mobile terminal, touch event import Base from './base.js' let that = null export default class MobilePrint extends Base { constructor(ele, dom) { super(ele, dom) that = this //Register global this this.init() return this; } init() { that.canvasEle.addEventListener('touchstart', that.onTouchStart) } onTouchStart(e = event) { that.clearDefaultEvent(e) that.canvasEle.addEventListener('touchend', that.onTouchEnd) //Touchend is not added to dom like pc, because touchmove is triggered between touchstart and touchend. As long as touchend is triggered, touchmove will fail that.canvasEle.addEventListener('touchmove', that.onTouchMove) that.event.emitEvent('pointStart', that.getClient(e.touches[0])) //Here, we can judge whether there is only one e.touches (e.touches means several fingers touch) } onTouchEnd(e = event) { that.clearDefaultEvent(e) that.event.emitEvent('pointEnd') that.canvasEle.removeEventListener('touchmove', that.onTouchMove) } onTouchMove(e = event) { that.clearDefaultEvent(e) that.event.emitEvent('pointMove', that.getClient(e.touches[0])) } }
Effects achieved at the mobile end:
last:
Attach the source code address: Gitee
Thank you for reading. If this article is helpful to you, I hope it can be supported by the third company. Your support is the driving force of my creation. At the same time, you are welcome to make suggestions and corrections