mirror of
https://github.com/nimiq/qr-scanner.git
synced 2026-07-27 19:56:28 +00:00
Most hacky prototype
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
tmp
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>HTML5 Camera QR UI</title>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="theme-color" content="#4285f4">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimal-ui">
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body {
|
||||
background: black;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
video {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
x-qr-code-scanner {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -550px;
|
||||
margin-top: -550px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
border: black solid 400px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top: 3px solid #00f700;
|
||||
opacity: 0.5;
|
||||
box-sizing: border-box;
|
||||
animation: moveDown 2s infinite alternate ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes moveDown {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
}
|
||||
to {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
video {
|
||||
transform: scale(-1.1, 1.1);
|
||||
/* hack to flip the camera of desktops; less confusion for the user to position the phone */
|
||||
}
|
||||
}
|
||||
|
||||
#qr-canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
max-width: 320px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 24px;
|
||||
background: white;
|
||||
opacity: 0;
|
||||
word-break: break-all;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.label-active {
|
||||
transform: scale(1);
|
||||
animation: fadeInFadeOut 7s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeInFadeOut {
|
||||
0% {
|
||||
opacity: 0.3;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
5% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
70% {
|
||||
opacity: 0.9;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
}
|
||||
|
||||
a:not([href]) {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<x-qr-scanner>
|
||||
<video muted autoplay playsinline></video>
|
||||
<div class="overlay">
|
||||
<!-- <div class="indicator"></div> -->
|
||||
</div>
|
||||
<canvas id="qr-canvas" width="320" height="320"></canvas>
|
||||
</x-qr-scanner>
|
||||
<a class="label">Test</a>
|
||||
</body>
|
||||
<script src="jsqrcode.min.js"></script>
|
||||
<script src="/x-element/x-element.js"></script>
|
||||
<script src="qr-scanner.js"></script>
|
||||
<script>
|
||||
var label = document.querySelector('.label');
|
||||
|
||||
const scanner = new QrScanner();
|
||||
|
||||
scanner.$el.addEventListener('x-decoded', (e) => {
|
||||
const decoded = e.detail;
|
||||
setLabel(decoded);
|
||||
resetClass(label, 'label-active', decoded);
|
||||
});
|
||||
|
||||
function setLabel(decoded) {
|
||||
if (qrscanner.isUrl(decoded)) {
|
||||
label.href = decoded;
|
||||
} else {
|
||||
label.removeAttribute('href');
|
||||
}
|
||||
label.textContent = decoded;
|
||||
}
|
||||
|
||||
var lastDecoded;
|
||||
var lastDecodedTimer;
|
||||
|
||||
function resetClass(el, className, decoded) {
|
||||
if (decoded == lastDecoded) return;
|
||||
clearTimeout(lastDecodedTimer);
|
||||
lastDecodedTimer = setTimeout(() => lastDecoded = false, 3000);
|
||||
lastDecoded = decoded;
|
||||
label.classList.remove(className);
|
||||
requestAnimationFrame(_ => label.classList.add(className))
|
||||
}
|
||||
</script>
|
||||
|
||||
</html>
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,30 @@
|
||||
class QrScanner extends XElement {
|
||||
onCreate() {
|
||||
console.log('scanner init',this)
|
||||
this.$video = this.$('video');
|
||||
this.$canvas = this.$('canvas');
|
||||
this.$context = this.$canvas.getContext('2d');
|
||||
this.$video.addEventListener('play', () => this._drawOnCanvas(), false);
|
||||
navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
|
||||
.then(stream => this.$video.srcObject = stream)
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
_drawOnCanvas() {
|
||||
if (this.$video.paused || this.$video.ended) return false;
|
||||
this.$context.drawImage(this.$video, -(this.$video.clientWidth - 320) / 2, -(this.$video.clientHeight - 320) / 2);
|
||||
this._decode();
|
||||
requestAnimationFrame(() => this._drawOnCanvas());
|
||||
}
|
||||
|
||||
_decode() {
|
||||
try {
|
||||
var decoded = qrscanner.decode();
|
||||
this.fire('x-decoded', decoded);
|
||||
// console.log(decoded);
|
||||
} catch (e) {
|
||||
// no qr-code in this frame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user