Last active
April 6, 2017 10:28
-
-
Save yuanoook/69ef0d81d107c3d06d8d7c891b5fdef4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
<style> | |
.app__layout { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
-webkit-overflow-scrolling: touch; | |
overflow: hidden; | |
} | |
.app__layout-content { | |
height: inherit; | |
margin-top: 56px; | |
} | |
.custom-btn { | |
position: fixed; | |
right: 26px; | |
bottom: 26px; | |
background: #448aff; | |
border-radius: 50%; | |
border: none; | |
width: 56px; | |
height: 56px; | |
outline: none; | |
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); | |
} | |
.custom-btn:active { | |
box-shadow: none; | |
} | |
.custom-msg { | |
text-align: center; | |
width: 90%; | |
height: 50%; | |
overflow: auto; | |
margin: auto; | |
position: absolute; | |
top: 0; | |
left: 0; | |
bottom: 0; | |
right: 0; | |
font-size: 16px; | |
} | |
.custom-fab-icon { | |
color: #fff; | |
font-size: 30px; | |
margin-top: 2px; | |
user-select: none; | |
} | |
video { | |
transform: translateX(-50%) translateY(-50%); | |
top: 50%; | |
left: 50%; | |
min-width: 100%; | |
min-height: 100%; | |
width: auto; | |
height: auto; | |
position: absolute; | |
} | |
#list li { | |
list-style-type: none; | |
text-decoration: underline; | |
color: #00F; | |
} | |
.custom-copy-btn { | |
opacity: 0; | |
} | |
.hide { | |
display: none; | |
} | |
@-webkit-keyframes scanner { | |
0% { | |
bottom: 95%; | |
} | |
50% { | |
bottom: 5%; | |
} | |
100% { | |
bottom: 95%; | |
} | |
} | |
@-moz-keyframes scanner { | |
0% { | |
bottom: 90%; | |
} | |
50% { | |
bottom: 15%; | |
} | |
100% { | |
bottom: 90%; | |
} | |
} | |
@-o-keyframes scanner { | |
0% { | |
bottom: 90%; | |
} | |
50% { | |
bottom: 15%; | |
} | |
100% { | |
bottom: 90%; | |
} | |
} | |
@keyframes scanner { | |
0% { | |
bottom: 90%; | |
} | |
50% { | |
bottom: 15%; | |
} | |
100% { | |
bottom: 90%; | |
} | |
} | |
.custom-scanner { | |
width: 100%; | |
height: 2px; | |
background: #4CAF50; | |
position: absolute; | |
-webkit-transition: all 200ms linear; | |
-moz-transition: all 200ms linear; | |
transition: all 200ms linear; | |
-webkit-animation: scanner 3s infinite linear; | |
-moz-animation: scanner 3s infinite linear; | |
-o-animation: scanner 3s infinite linear; | |
animation: scanner 3s infinite linear; | |
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.4); | |
display: none; | |
} | |
#camera { | |
opacity: 0; | |
} | |
#frame { | |
width: 100%; | |
max-width: 100%; | |
} | |
.no-support { | |
font-size: 20px; | |
text-align: center; | |
} | |
.menu { | |
width: 280px; | |
height: 100%; | |
background: #fff; | |
position: fixed; | |
top: 0; | |
bottom: 0; | |
box-shadow: 0px 0px 11px 0px rgba(0, 0, 0, 0.4); | |
z-index: 1; | |
-webkit-transition: all 200ms cubic-bezier(0, 0, 0.30, 1); | |
transition: all 200ms cubic-bezier(0, 0, 0.30, 1); | |
-webkit-transform: translateX(-101%); | |
transform: translateX(-101%); | |
will-change: transform; | |
z-index: 11; | |
} | |
.app__snackbar { | |
position: fixed; | |
bottom: 20px; | |
left: 20px; | |
pointer-events: none; | |
} | |
.app__snackbar-msg { | |
width: 250px; | |
min-height: 50px; | |
background: rgba(0, 0, 0, 0.99); | |
color: #fff; | |
display: -webkit-box; | |
display: -ms-flexbox; | |
display: flex; | |
-webkit-box-align: center; | |
-ms-flex-align: center; | |
align-items: center; | |
-webkit-box-pack: justify; | |
-ms-flex-pack: justify; | |
justify-content: space-between; | |
font-size: 14px; | |
font-weight: 500; | |
padding-left: 15px; | |
padding-right: 10px; | |
word-break: break-all; | |
-webkit-transition: opacity 3s cubic-bezier(0, 0, 0.30, 1) 0; | |
transition: opacity 0.30s cubic-bezier(0, 0, 0.30, 1) 0; | |
text-transform: initial; | |
margin-bottom: 10px; | |
border-radius: 2px; | |
} | |
.app__snackbar--hide { | |
opacity: 0; | |
} | |
.app__dialog { | |
z-index: 12; | |
background-color: #fff; | |
width: 290px; | |
height: 180px; | |
border-radius: 2px; | |
display: flex; | |
position: absolute; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
top: 0; | |
margin: auto; | |
box-shadow: 0 9px 46px 8px rgba(0,0,0,.14), 0 11px 15px -7px rgba(0,0,0,.12), 0 24px 38px 3px rgba(0,0,0,.2); | |
} | |
.app__dialog h5 { | |
margin-top: 20px; | |
margin-left: 18px; | |
font-weight: 500; | |
} | |
.app__dialog input { | |
width: 250px; | |
margin: 20px; | |
height: 30px; | |
border: none; | |
border-bottom: 1px solid rgba(0,0,0,.12); | |
outline: none; | |
font-size: 15px; | |
margin-top: 25px; | |
color: rgba(0,0,0,.54); | |
font-weight: 500; | |
} | |
.app__dialog-actions { | |
display: block; | |
position: absolute; | |
bottom: 13px; | |
right: 20px; | |
} | |
.app__dialog-open, | |
.app__dialog-close { | |
border: 0; | |
height: 35px; | |
width: 70px; | |
font-size: 15px; | |
background: transparent; | |
font-weight: 500; | |
outline: none; | |
cursor: pointer; | |
} | |
.app__dialog-open { | |
display: none; | |
} | |
.app__dialog-open:active, | |
.app__dialog-close:active { | |
opacity: 0.9; | |
} | |
.app__dialog--hide { | |
display: none; | |
}</style></head> | |
<body> | |
<div class="app__layout"> | |
<main class="app__layout-content"> | |
<video autoplay></video> | |
<!-- Scanner animation --> | |
<div class="custom-scanner"></div> | |
<!-- Scan button --> | |
<button class="custom-btn">Scan</button> | |
<!-- Dialog --> | |
<div class="app__dialog app__dialog--hide"> | |
<div class="app__dialog-content"> | |
<h5>QR Code</h5> | |
<input type="text" id="result"> | |
</div> | |
<div class="app__dialog-actions"> | |
<button type="button" class="app__dialog-open">Open</button> | |
<button type="button" class="app__dialog-close">Close</button> | |
</div> | |
</div> | |
<!-- Snackbar --> | |
<div class="app__snackbar"></div> | |
</main> | |
</div> | |
<script type="text/javascript"> | |
var snackbar = {}; | |
var snackBarElement = document.querySelector('.app__snackbar'); | |
var snackbarMsg = null; | |
//To show notification | |
snackbar.show = (msg, options=4000) => { | |
if (!msg) return; | |
if (snackbarMsg) { | |
snackbarMsg.remove(); | |
} | |
snackbarMsg = document.createElement('div'); | |
snackbarMsg.className = 'app__snackbar-msg'; | |
snackbarMsg.textContent = msg; | |
snackBarElement.appendChild(snackbarMsg); | |
//Show toast for 3secs and hide it | |
setTimeout(() => { | |
snackbarMsg.remove(); | |
}, options); | |
}; | |
//------------------------------------------------------------------------------------------------------------------------------ | |
var QRReader = {}; | |
QRReader.active = false; | |
QRReader.webcam = null; | |
QRReader.canvas = null; | |
QRReader.ctx = null; | |
QRReader.decoder = null; | |
QRReader.setCanvas = () => { | |
QRReader.canvas = document.createElement("canvas"); | |
QRReader.ctx = QRReader.canvas.getContext("2d"); | |
} | |
QRReader.init = () => { | |
var decoder_worker_url = "//fly.yuanoook.com/file?hash=e69d4d973eea2229c7ba134d005f103d"; | |
var streaming = false; | |
// Init Webcam + Canvas | |
if (!window.iOS) { | |
QRReader.webcam = document.querySelector("video"); | |
} | |
else { | |
QRReader.webcam = document.querySelector("img"); | |
} | |
QRReader.setCanvas(); | |
QRReader.decoder = new Worker(decoder_worker_url); | |
if (!window.iOS) { | |
// Resize webcam according to input | |
QRReader.webcam.addEventListener("play", function (ev) { | |
if (!streaming) { | |
setCanvasProperties(); | |
streaming = true; | |
} | |
}, false); | |
} | |
else { | |
setCanvasProperties(); | |
} | |
function setCanvasProperties() { | |
QRReader.canvas.width = window.innerWidth; | |
QRReader.canvas.height = window.innerHeight; | |
} | |
function startCapture(constraints) { | |
navigator.mediaDevices.getUserMedia(constraints) | |
.then(function (stream) { | |
QRReader.webcam.srcObject = stream; | |
}) | |
.catch(function(err) { | |
console.log("Error occurred ", err); | |
showErrorMsg(); | |
}); | |
} | |
if (!window.iOS) { | |
navigator.mediaDevices.enumerateDevices() | |
.then(function (devices) { | |
var device = devices.filter(function(device) { | |
var deviceLabel = device.label.split(',')[1]; | |
if (device.kind == "videoinput") { | |
return device; | |
} | |
}); | |
if (device.length > 1) { | |
var constraints = { | |
video: { | |
mandatory: { | |
sourceId: device[1].deviceId ? device[1].deviceId : null | |
} | |
}, | |
audio: false | |
}; | |
startCapture(constraints); | |
} | |
else if (device.length) { | |
var constraints = { | |
video: { | |
mandatory: { | |
sourceId: device[0].deviceId ? device[0].deviceId : null | |
} | |
}, | |
audio: false | |
}; | |
startCapture(constraints); | |
} | |
else { | |
startCapture({video:true}); | |
} | |
}) | |
.catch(function (error) { | |
showErrorMsg(); | |
console.error("Error occurred : ", error); | |
}); | |
} | |
function showErrorMsg() { | |
document.querySelector('.custom-btn').style.display = "none"; //Hide scan button, if error | |
snackbar.show('Unable to open the camera, provide permission to access the camera', 5000); | |
} | |
} | |
/** | |
* \brief QRReader Scan Action | |
* Call this to start scanning for QR codes. | |
* | |
* \param A function(scan_result) | |
*/ | |
QRReader.scan = function (callback) { | |
QRReader.active = true | |
QRReader.setCanvas(); | |
function onDecoderMessage(event) { | |
if (event.data.length > 0) { | |
var qrid = event.data[0][2]; | |
QRReader.active = false | |
callback(qrid); | |
} | |
setTimeout(newDecoderFrame, 0); | |
} | |
QRReader.decoder.onmessage = onDecoderMessage; | |
// Start QR-decoder | |
function newDecoderFrame() { | |
if (!QRReader.active) return; | |
try { | |
QRReader.ctx.drawImage(QRReader.webcam, 0, 0, | |
QRReader.canvas.width, QRReader.canvas.height); | |
var imgData = QRReader.ctx.getImageData(0, 0, QRReader.canvas.width, | |
QRReader.canvas.height); | |
if (imgData.data) { | |
QRReader.decoder.postMessage(imgData); | |
} | |
} catch(e) { | |
// Try-Catch to circumvent Firefox Bug #879717 | |
if (e.name == "NS_ERROR_NOT_AVAILABLE") setTimeout(newDecoderFrame, 0); | |
} | |
} | |
newDecoderFrame(); | |
} | |
//------------------------------------------------------------------------------------------------------------------------------ | |
function isURL(string){ | |
return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(string); | |
} | |
//------------------------------------------------------------------------------------------------------------------------------ | |
window.addEventListener("DOMContentLoaded", () => { | |
//To check the device and add iOS support | |
window.iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; | |
var copiedText = null; | |
var scanBtnElement = document.querySelector('.custom-btn'); | |
var dialogElement = document.querySelector('.app__dialog'); | |
var dialogOpenBtnElement = document.querySelector('.app__dialog-open'); | |
var dialogCloseBtnElement = document.querySelector('.app__dialog-close'); | |
var scanningEle = document.querySelector('.custom-scanner'); | |
var textBoxEle = document.querySelector('#result'); | |
var frame = document.createElement('img'); | |
frame.src = ''; | |
frame.id = 'frame'; | |
//Dialog close btn event | |
dialogCloseBtnElement.addEventListener('click', hideDialog, false); | |
dialogOpenBtnElement.addEventListener('click', openInBrowser, false); | |
//To open result in browser | |
function openInBrowser() { | |
console.log('Result: ', copiedText); | |
window.open(copiedText, '_blank', 'toolbar=0,location=0,menubar=0'); | |
copiedText = null; | |
} | |
//Add scan funz to fab button, if its other iOS | |
if (!window.iOS) { | |
//Fab btn to scan | |
scanBtnElement.addEventListener('click', () => { | |
snackbar.show('Scanning please wait...', 2000); | |
scanningEle.style.display = 'block'; | |
scan(); | |
}); | |
} | |
//Scan | |
function scan() { | |
QRReader.scan((result) => { | |
copiedText = result; | |
textBoxEle.value = result; | |
textBoxEle.select(); | |
scanningEle.style.display = 'none'; | |
if (isURL(result)) { | |
dialogOpenBtnElement.style.display = 'inline-block'; | |
} | |
dialogElement.classList.remove('app__dialog--hide'); | |
}); | |
} | |
//Hide dialog | |
function hideDialog() { | |
copiedText = null; | |
textBoxEle.value = ""; | |
frame.src = ""; | |
dialogElement.classList.add('app__dialog--hide'); | |
} | |
//If its iOS, then remove the video element and camera element. | |
if (window.iOS) { | |
document.querySelector('video').remove(); //removing the video element | |
//Creating the camera element | |
var camera = document.createElement('input'); | |
camera.setAttribute('type', 'file'); | |
camera.setAttribute('capture', 'camera'); | |
camera.id = 'camera'; | |
var iconElement = document.createElement('i'); | |
iconElement.className = 'material-icons custom-fab-icon'; | |
iconElement.textContent = 'camera_enhance'; | |
var noSupportText = document.createElement('h2'); | |
noSupportText.className = "no-support"; | |
noSupportText.textContent = "Press the camera icon below." | |
//Add the camera and img element to DOM | |
var pageContentElement = document.querySelector('.app__layout-content'); | |
var fabElement = document.querySelector('.custom-btn'); | |
var fabIconElement = document.querySelector('.custom-fab-icon'); | |
pageContentElement.appendChild(camera); | |
pageContentElement.appendChild(frame); | |
pageContentElement.appendChild(noSupportText); | |
fabElement.removeChild(fabIconElement); | |
fabElement.appendChild(iconElement); | |
//On camera change | |
camera.addEventListener('change', (event) => { | |
if (event.target && event.target.files.length > 0) { | |
frame.src = URL.createObjectURL(event.target.files[0]); | |
snackbar.show('Scanning please wait...', 2000); | |
scanningEle.style.display = 'block'; | |
scan(); | |
} | |
}); | |
//Click of camera fab icon | |
fabElement.addEventListener('click', () => { | |
scanningEle.style.display = 'none'; | |
document.querySelector("#camera").click(); | |
}); | |
} | |
}); | |
//Initializing qr scanner | |
window.addEventListener('load', (event) => { | |
QRReader.init(); //To initialize QR Scanner | |
}); | |
</script></body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment