Front-end implementation of electronic signature (web, mobile) common components
In the current development of the times, from the previous handwritten signatures, electronic signatures are gradually derived. Electronic signatures have the same legal effect as paper handwritten signatures. At present, electronic signatures are mainly used in product links that require personal confirmation and judicial-related products.
So how do we implement electronic signatures as the front end? In fact, an important level of auxiliary tags has appeared in html5, that is canvas.
What is canvas
Canvas is a new tag in HTML5 that is used to generate images in real time on web pages, and can manipulate image content. Basically, it is a bitmap that can be manipulated by JavaScript. The Canvas object represents an HTML canvas element that supports client-side drawing operations.
<canvas></canvas>
How to use
Canvas provides us with a lot of APIs, we only need to create a canvas tag in the body tag, get the node of the canvas tag in the script tag, and create a context to use it
<body>
<canvas></canvas>
</body>
<script>
// get the canvas instance
const canvas = document. querySelector('canvas')
canvas. getContext('2d')
</script>
Implement electronic signature
We only need to get the coordinate point of the current touch and perform line processing.
1. Add the canvas tag to the body:
Here we not only need to add the canvas tag in the body, we also need to add two buttons, cancel and save
<body>
<canvas></canvas>
<div>
<button>Cancel</button>
<button>Save</button>
</div>
</body>
2. Add files
const config = {
width: 400, // width
height: 200, // height
lineWidth: 5, // line width
strokeStyle: 'red', // line color
lineCap: 'round', // set the rounded corners at both ends of the line
lineJoin: 'round', // rounded corners where lines meet
}
3. Get the canvas instance
// get the canvas instance
const canvas = document. querySelector('canvas')
// set width and height
canvas.width = config.width
canvas.height = config.height
// Set a frame for us to view and use
canvas.style.border = '1px solid #000'
// create context
const ctx = canvas. getContext('2d')
4. Basic Settings
We make the fill color of the canvas transparent, and draw and fill a rectangle as our canvas
// set fill background color
ctx.fillStyle = 'transparent'
// draw filled rectangle
ctx.fillRect(
0, // x-axis start drawing position
0, // y-axis starting drawing position
config.width, // width
config.height // height
);
5. Save the last drawn path
Here we need to declare an object to record the end coordinate point and offset of the path we drew last time.
Why do we need to save the offset, because there is a certain offset distance between the mouse and the canvas, and we need to subtract this offset in the process of drawing, which is our actual drawing coordinates. But I found that it is not necessary to subtract this offset in chrome, and what you get is the actual coordinates. Before using it in the WeChat applet, you need to subtract the offset. Friends who need to use it in the applet need to pay attention to this.
// save the last drawn coordinates and offset
const client = {
offsetX: 0, // offset
offsetY: 0,
endX: 0, // coordinates
endY: 0
}
6. Device compatible
We obtain the current device information by calling navigator.userAgent, and make regular matching judgments
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))
7. Initialization
Here we initialize when the mouse is pressed (mousedown) (web side)/touch start (mobile side), and event monitoring uses addEventListener
// create mouse/gesture down listener
window. addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
declare initialization method:
We add an init method as a callback method to listen for mouse press/touch start.
Here we need to obtain the offset and coordinates of the current mouse press/touch start, and draw the starting point.
Tips: The web terminal can be obtained directly from the event, while the mobile terminal needs to be obtained from event.changedTouches[0].
Here we monitor the movement of the mouse after initialization
// initialization
const init = event => {
// Get the offset and coordinates
const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
// Modify the last offset and coordinates
client.offsetX = offsetX
client.offsetY = offsetY
client.endX = pageX
client.endY = pageY
// Clear all paths after the last beginPath and draw
ctx.beginPath()
// Configure according to the configuration file settings
ctx.lineWidth = config.lineWidth
ctx.strokeStyle = config.strokeStyle
ctx.lineCap = config.lineCap
ctx.lineJoin = config.lineJoin
// Set the starting point of the line
ctx.moveTo(client.endX, client.endY)
// Listen for mouse movement or gesture movement
window. addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}
8. Draw
Here we add the draw method as a callback method for monitoring mouse movement/touch movement
// draw
const draw = event => {
// Get the current coordinate point
const { pageX, pageY } = mobileStatus ? event. changedTouches[0] : event
// Modify the coordinate point of the last drawing
client.endX = pageX
client.endY = pageY
// Add lines according to coordinate point movement
ctx.lineTo(pageX, pageY)
// draw
ctx.stroke()
}
9. End drawing
After adding the monitoring of mouse movement/touch movement, we must remember to cancel the monitoring and end the drawing, otherwise it will always monitor and draw
Here we create a closeDraw method as a callback method for mouse up/end touch to end drawing and remove the monitoring of mouse movement/touch movement. When the canvas finishes drawing, you need to call closePath() to let it finish drawing
const closeDraw = () => {
// end drawing
ctx. closePath()
// Remove mouse movement or gesture movement listeners
window. removeEventListener("mousemove", draw)
}
Add end callback listener
// create mouse/gesture popup/leave listener
window.addEventListener(mobileStatus ? "touchend" : "mouseup", closeDraw)
Ok, now our electronic signature function is almost finished, and now we can sign normally
10. Cancel function/Clear canvas
const cancel = () => {
// Clear all drawing content on the current canvas
ctx. clearRect(0, 0, config. width, config. height)
}
Bind this method to the cancel button
<button onclick="cancel()">cancel</button>
11. Save function
There are many ways to save the content on the canvas as a picture/file, the more common ones are blob and toDataURL, but toDataURL is not as good as blob, so here we use the a tag + blob solution to save and download pictures
// save - save the canvas content as an image
const save = () => {
// Convert the content on the canvas to a blob stream
canvas.toBlob(blob => {
// Get the current time and convert it into a string, which is used as a file name
const date = Date.now().toString()
// Create an a tag
const a = document. createElement('a')
// Set the download file name of the a tag
a.download = `${date}.png`
// Set the jump path of the a label to the file stream address
a.href = URL.createObjectURL(blob)
// Manually trigger the click event of the a tag
a. click()
// remove the a tag
a. remove()
})
}
<button onclick="save()">save</button>
We will save the content we just drew, click the save button, and it will be downloaded and saved
Full code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas></canvas>
<div>
<button onclick="cancel()">Cancel</button>
<button onclick="save()">Save</button>
</div>
</body>
<script>
// configuration content
const config = {
width: 400, // width
height: 200, // height
lineWidth: 5, // line width
strokeStyle: 'red', // line color
lineCap: 'round', // set the rounded corners at both ends of the line
lineJoin: 'round', // rounded corners where lines meet
}
// get the canvas instance
const canvas = document. querySelector('canvas')
// set width and height
canvas.width = config.width
canvas.height = config.height
// set a border
canvas.style.border = '1px solid #000'
// create context
const ctx = canvas. getContext('2d')
// set fill background color
ctx.fillStyle = 'transparent'
// draw filled rectangle
ctx.fillRect(
0, // x-axis start drawing position
0, // y-axis starting drawing position
config.width, // width
config.height // height
);
// save the last drawn coordinates and offset
const client = {
offsetX: 0, // offset
offsetY: 0,
endX: 0, // coordinates
endY: 0
}
// Determine whether it is a mobile terminal
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent))
// initialization
const init = event => {
// Get the offset and coordinates
const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
// Modify the last offset and coordinates
client.offsetX = offsetX
client.offsetY = offsetY
client.endX = pageX
client.endY = pageY
// Clear all paths after the last beginPath and draw
ctx.beginPath()
// Set the corresponding configuration according to the configuration file
ctx.lineWidth = config.lineWidth
ctx.strokeStyle = config.strokeStyle
ctx.lineCap = config.lineCap
ctx.lineJoin = config.lineJoin
// Set the starting point of the line
ctx.moveTo(client.endX, client.endY)
// Listen for mouse movement or gesture movement
window. addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}
// draw
const draw = event => {
// Get the current coordinate point
const { pageX, pageY } = mobileStatus ? event. changedTouches[0] : event
// Modify the coordinate point of the last drawing
client.endX = pageX
client.endY = pageY
// Add lines according to coordinate point movement
ctx.lineTo(pageX, pageY)
// draw
ctx.stroke()
}
// end drawing
const closeDraw = () => {
// end drawing
ctx. closePath()
// Remove mouse movement or gesture movement listeners
window. removeEventListener("mousemove", draw)
}
// create mouse/gesture down listener
window. addEventListener(mobileStatus ? "touchstart" : "mousedown", init)
// create mouse/gesture popup/leave listener
window.addEventListener(mobileStatus ? "touchend" : "mouseup", closeDraw)
// cancel - clear the canvas
const cancel = () => {
// Clear all drawing content on the current canvas
ctx. clearRect(0, 0, config. width, config. height)
}
// save - save the canvas content as an image
const save = () => {
// Convert the content on the canvas to a blob stream
canvas.toBlob(blob => {
// Get the current time and convert it into a string, which is used as a file name
const date = Date.now().toString()
// Create an a tag
const a = document. createElement('a')
// Set the download file name of the a tag
a.download = `${date}.png`
// Set the jump path of the a label to the file stream address
a.href = URL.createObjectURL(blob)
// Manually trigger the click event of the a tag
a. click()
// remove the a tag
a. remove()
})
}
</script>
</html>
Prompt in the applet:
In the applet, we need to modify the Api that creates the instance and context, because there is no dom in the applet
-
If it is uni-app, you need to use uni.createCanvasContext for context creation
-
If it is a native WeChat applet, use
wx.createCanvasContext
to create (2.9.0) and later libraries do not support