background
The other day the front end interviewer asked a question: “Do you know anything about Canvas?”
“This I know, I have done DEMO, this is not difficult, look at its API interface can achieve!”
Seeing him so confident, I decided to get to know him better!
“E-commerce big turntable, nine squares, scratch-off, how to use canvas to achieve, tell me your idea?
“How to achieve the generation of two-dimensional code and scan code recognition?”
“What about the particle explosion effect of the picture?
“……”
Therefore, I plan to write a series of articles about canvas to explore and improve myself and share them with you.
Generation of TWO-DIMENSIONAL code
The generation of two-dimensional code needs to use the third-party library, use its algorithm to convert the text into two-dimensional code, and draw it with canvas. Use canva. toDataURL(‘image/ PNG ‘) to get the qr code to base64 value and assign it to the SRC attribute of the IMG tag
Here I use a library, QrcodeJS.
Click “Demo” to see the effect
The usage method is as follows:
<! -- index.html -->
<! DOCTYPEhtml>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Suporka Vue App</title>
<style>
.container {
padding: 60px;
margin: 0 auto;
line-height: 50px;
}
input {
display: inline-block;
width: 200px;
height: 32px;
line-height: 1.5;
padding: 4px 7px;
font-size: 12px;
border: 1px solid #dcdee2;
border-radius: 4px;
color: #515a6e;
background-color: #fff;
background-image: none;
position: relative;
cursor: text;
transition: border 0.2 s ease-in-out, background 0.2 s ease-in-out,
box-shadow 0.2 s ease-in-out;
}
button {
color: #fff;
background-color: #19be6b;
border-color: #19be6b;
outline: 0;
vertical-align: middle;
line-height: 1.5;
display: inline-block;
font-weight: 400;
text-align: center;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
padding: 5px 15px 6px;
font-size: 12px;
border-radius: 4px;
transition: color 0.2 s linear, background-color 0.2 s linear,
border 0.2 s linear, box-shadow 0.2 s linear;
}
#qrcode {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<input
type="text"
placeholder="Please enter the string you want to convert to qr code."
id="input"
/>
<button onclick="creatQRcode();">A key generation</button>
<div id="qrcode"></div>
</div>
<script src="https://zxpsuper.github.io/Demo/qrcode/qrcode-dev.js"></script>
<script type="text/javascript">
var qrcode = null;
function creatQRcode() {
document.getElementById("qrcode").innerHTML = "";
qrcode = new QRCode(document.getElementById("qrcode"), {
text: document.getElementById("input").value,
width: 200.height: 200.colorDark: "# 000000".colorLight: "#ffffff".correctLevel: QRCode.CorrectLevel.H
});
}
</script>
</body>
</html>
Copy the code
options
- The first parameter is generate store
img
The parent of the tag - The second parameter is
Object
The type ofoptions
attribute | type | instructions |
---|---|---|
text | String | Target text |
width | Number | Image width |
height | Number | Picture height |
colorDark | String | Two-dimensional code color |
colorLight | The default QRCode. CorrectLevel. L | L, qrcode.correctLevel. M, qrcode.correctlevel. Q, qrcode.correctlevel.h |
Qr code scanning identification
Here, a library llqrcode.js is used to decode the canvas with ID QR-canvas using qrcode.decode().
Demo and project source code first
What we need to do is to call the camera of the device (rear camera is preferred), and the obtained picture is displayed in real time with the video tag. Then, the picture is periodically taken to generate canvas and decrypted by calling qrcode.decode().
// variable.js
var gCtx = null; //canvas.ctx
var gCanvas = null; // qr-canvas
// var c = 0;
var stype = 0; // Identify flow 0 not started, 1 in progress, 2 completed
var gUM = false;
var webkit = false;
var moz = false;
var v = null; // Store the video variable
var scanCodeStart = false; // Start scanning
var mediaStreamTrack = null; Mediastreamtrack.stop ()
var imghtml =
'<div id="qrfile"><canvas id="out-canvas" width="320" height="240"></canvas>' +
'<div id="imghelp">drag and drop a QRCode here' +
"<br>or select a file" +
'<input type="file" onchange="handleFiles(this.files)" id="upload-img"/>' +
"</div>" +
"</div>";
var vidhtml = '<video id="v" autoplay muted></video>';
Copy the code
// methods.js
function qrcodeScanLoad(width, height) {
if (isCanvasSupported() && window.File && window.FileReader) {
initCanvas(width, height);
qrcode.callback = scanCodeCallback;
document.getElementById("mainbody").style.display = "inline";
setwebcam();
} else {
document.getElementById("mainbody").style.display = "inline";
document.getElementById("mainbody").innerHTML =
'<p id="mp1">QR code scanner for HTML5 capable browsers</p><br>' +
'<br><p id="mp2">sorry your browser is not supported</p><br><br>'; }}// Draw the mask layer canvas
function setMask() {
var canvas = document.querySelector("#scancode-mask");
canvas.width =
document.body.clientWidth > 1024 ? 1024 : document.body.clientWidth;
canvas.height =
document.body.clientWidth > 1024 ? 1136 : document.body.clientHeight;
var ctx = canvas.getContext("2d");
ctx.fillRect(0.0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
let x1,
y1,
width = canvas.width * 0.6;
x1 = (canvas.width - width) / 2;
y1 = (canvas.height - width) / 2;
ctx.fillRect(x1, y1, width, width);
ctx.fill();
ctx.save();
ctx.globalCompositeOperation = "source-over";
// Second quadrant point
ctx.moveTo(x1, y1 + 2);
ctx.lineTo(x1 + 20, y1 + 2);
ctx.moveTo(x1 + 2, y1);
ctx.lineTo(x1 + 2, y1 + 20);
// First quadrant point
ctx.moveTo(x1 + width - 20, y1 + 2);
ctx.lineTo(x1 + width, y1 + 2);
ctx.moveTo(x1 + width - 2, y1 + 1);
ctx.lineTo(x1 + width - 2, y1 + 20);
// The fourth quadrant
ctx.moveTo(x1 + width - 20, y1 + width - 2);
ctx.lineTo(x1 + width, y1 + width - 2);
ctx.moveTo(x1 + width - 2, y1 + width - 1);
ctx.lineTo(x1 + width - 2, y1 + width - 20);
// The third quadrant
ctx.moveTo(x1 + 20, y1 + width - 2);
ctx.lineTo(x1, y1 + width - 2);
ctx.moveTo(x1 + 2, y1 + width - 2);
ctx.lineTo(x1 + 2, y1 + width - 20);
ctx.lineWidth = 4;
ctx.strokeStyle = "green";
ctx.stroke();
}
function setwebcam() {
var options = true;
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
try {
navigator.mediaDevices.enumerateDevices().then(function(devices) {
let video = [];
devices.forEach(function(device) {
if (device.kind === "videoinput") { video.push(device); }});// Call the camera of the device. Video [1] is the rear camera, or label containing "back" is the rear camera
if (video.length >= 2) {
options = {
deviceId: { exact: video[1].deviceId },
facingMode: { exact: "environment"}}; } video.forEach(item= > {
if (item.label.toLowerCase().search("back") > -1)
options = {
deviceId: { exact: device.deviceId },
facingMode: { exact: "environment"}}; }); scanCodeStart =true;
setwebcam2(options);
});
} catch (e) {
console.error(e); }}else {
console.log("no navigator.mediaDevices.enumerateDevices"); setwebcam2(options); }}function setwebcam2(options) {
if (stype == 1) {
setTimeout(captureToCanvas, 500);
return;
}
var n = navigator;
document.getElementById("outdiv").innerHTML = vidhtml;
v = document.getElementById("v");
try {
if (n.mediaDevices && n.mediaDevices.getUserMedia) {
n.mediaDevices
.getUserMedia({ video: options, audio: false })
.then(function(stream) {
success(stream);
})
.catch(function(error) {
error(error);
});
} else if (n.getUserMedia) {
webkit = true;
n.getUserMedia({ video: options, audio: false }, success, error);
} else if (n.webkitGetUserMedia) {
webkit = true;
n.webkitGetUserMedia({ video: options, audio: false}, success, error); }}catch (err) {
console.log(err);
}
stype = 1;
if (getSystem() === "ios") {
alert("Your device does not support real-time scan code, please upload pictures to identify!");
return;
}
if (
(n.mediaDevices && n.mediaDevices.getUserMedia) ||
n.getUserMedia ||
n.webkitGetUserMedia
)
setTimeout(captureToCanvas, 500);
else {
alert("Your device does not support real-time scan code, please upload pictures to identify!"); }}// Get the operating system
function getSystem() {
var u = navigator.userAgent;
var isAndroid = u.indexOf("Android") > -1 || u.indexOf("Linux") > -1; //g
varisIOS = !! u.match(/\(i[^;] +; ( U;) ? CPU.+Mac OS X/); / / ios terminal
if (isAndroid) {
// This is android operating system
return "android";
} else if (isIOS) {
// This is the ios operating system
return "ios";
} else {
return "other"; }}// Select the image to upload
function setimg($event) {
qrcode.callback = scanCodeCallback;
$event && $event.preventDefault();
stype = 2;
let file = document.getElementById("upload-img");
file.click();
}
// Successful upload callback
function scanCodeCallback(a) {
var html = htmlEntities(a);
stype = 0;
alert(html);
}
// Handle upload file identification
function handleFiles(f) {
var o = [];
for (var i = 0; i < f.length; i++) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
gCtx.clearRect(0.0, gCanvas.width, gCanvas.height); qrcode.decode(e.target.result); }; })(f[i]); reader.readAsDataURL(f[i]); }}function initCanvas(w, h) {
gCanvas = document.getElementById("qr-canvas");
gCanvas.style.width = w + "px";
gCanvas.style.height = h + "px";
gCanvas.width = w;
gCanvas.height = h;
gCtx = gCanvas.getContext("2d");
gCtx.clearRect(0.0, w, h);
}
// Canvas to canvas
function captureToCanvas() {
if(stype ! =1) return;
if (gUM && scanCodeStart) {
try {
gCtx.drawImage(v, 0.0);
try {
qrcode.decode(); // The default id=qr-canvas canvas is converted to base64 for the image
} catch (e) {
console.log(e);
setTimeout(captureToCanvas, 500); }}catch (e) {
console.log(e);
setTimeout(captureToCanvas, 500); }}}// Handle special symbols
function htmlEntities(str) {
return String(str)
.replace(/&/g."&")
.replace(/</g."<")
.replace(/>/g.">")
.replace(/"/g.""");
}
// Determine whether canvas is supported
function isCanvasSupported() {
var elem = document.createElement("canvas");
return!!!!! (elem.getContext && elem.getContext("2d"));
}
function success(stream) {
// mediaStreamTrack to close the camera function
if (stream)
mediaStreamTrack =
typeof stream.stop === "function" ? stream : stream.getTracks()[0];
v.srcObject = stream;
if (scanCodeStart) {
v.play();
gUM = true;
setTimeout(captureToCanvas, 500);
} else{}}function error(error) {
gUM = false;
return;
}
Copy the code
SetMask is the method of drawing the mask layer, and qrcodeScanLoad is the initial loading method.
<body>
<div class="body">
<div id="mainbody" style="display: inline;">
<div id="outdiv" autoplay muted></div>
</div>
<canvas id="qr-canvas" width="800" height="600"></canvas>
<canvas id="scancode-mask"></canvas>
<div class="scancode-tips-group" id="scancode-tips-group">
<span class="tips">Put the QR Code into the box and it will be scanned automatically</span>
<div class="upload-my-code" onClick="setimg()">My QR Code</div>
</div>
<div id="img-upload-container" style="display: none">
<div id="qrfile">
<canvas id="out-canvas" width="320" height="240"></canvas>
<div id="imghelp">
drag and drop a QRCode here
<br />or select a file
<input
type="file"
onchange="handleFiles(this.files)"
id="upload-img"
/>
</div>
</div>
</div>
</div>
<script src="./llqrcode.js"></script>
<script src="./variable.js"></script>
<script src="./methods.js"></script>
<script>
qrcodeScanLoad(320.400);
setMask();
// Display my QR Code location
if (document.body.clientWidth < 1025) {
document.getElementById("scancode-tips-group").style.top =
(document.body.clientHeight - document.body.clientWidth) / 2 +
document.body.clientWidth * 0.9 -
10 +
"px";
} else {
document.getElementById("scancode-tips-group").style.top = "720px";
}
</script>
</body>
Copy the code
The canvas width is set to 1024 when it exceeds 1024. The details are commented in the code.
More recommended
Advanced_front_end
Daily question
Webpack4 Build Vue application (createVue)