Open ravimantra opened 5 years ago
use setTimeout
I have absolutely no idea if there's any access to focus capabilities in the media api, but if you do find something, let me know. or are you asking about how to get quagga to read from a certain area? because that's in the quagga options.
setTimeout helps only to hide the canvas, if it does not read within 5 secs. But i want it within "Quagga.onDetected" or "Quagga.onProcessed", if it does not detect.
Alright, i can go with the option, if Quagga has an option to read from certain area. Please help me out on it, as it is very important for me. I tried with rectangle overlay, but didn't work for me.
To turn off auto-location, specify locate: false, and then area. Area uses CSS like percentages
locate: false,
area: {
top: '25%',
right: '0%',
left: '0%',
bottom: '25%',
},
... Use a setTimeout() in the callback to Quagga.init(), and when the time has passed, do whatever you need to do when there's been no read. You're not going to get a callback to onDetected or onProcessed if there's nothing to process or detect.
@ericblade, thanks. I'll use setTimeout in "Quagga.init()" but the area just not seems to work in my case. I'm not able to see some rectangle box within for that particular area.
You'll need to draw an outline for it, if that's what you want to do also
Didn't work, even i drew an outline :(
Quagga.init({
inputStream: {
name: 'Live',
type: 'LiveStream',
constraints: {
width: 640,
height: 480,
aspectRatio: 1 / 1
},
locate: false,
area: { // defines rectangle of the detection/localization area
top: '25%',
right: '0%',
left: '0%',
bottom: '25%'
},
singleChannel: false
},
debug: true,
numOfWorkers: navigator.hardwareConcurrency,
locate: true,
locator: {
patchSize: 'x-large',
halfSample: true
},
decoder: {
readers: [
'ean_reader',
'ean_8_reader'
],
debug: {
drawBoundingBox: true,
drawScanline: true
},
multiple: false
}
}, () => {
Quagga.start();
});
Quagga.onDetected(this.onDetected);
Quagga.onProcessed((result) => {
const drawingCtx = Quagga.canvas.ctx.overlay;
const drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute('width')), parseInt(drawingCanvas.getAttribute('height'))); //eslint-disable-line
result.boxes.filter(function (box) { //eslint-disable-line
return box !== result.box;
}).forEach(function (box) { //eslint-disable-line
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2}); //eslint-disable-line
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: '#00F', lineWidth: 2 });
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
}
}
});
i'm a bit busy to deconstruct the scanner that I use, but i'll provide the code .. js and css
import React from 'react';
import { connect } from 'react-redux';
import validateBarcode from './BarcodeValidator';
import { Link } from 'react-router-dom';
import Quagga from 'quagga';
import css from './Scanner.module.less';
import * as SettingSelector from '../store/reducers/settings';
import { doCameraScanNotify, enableTorch, disableTorch, lockOrientation } from '../store/actions';
class Scanner extends React.Component {
state = {
torch: false,
}
toggleTorch = () => {
this.setState((prevState) => {
const torch = !prevState.torch;
if (torch) {
this.props.torchOn();
} else {
this.props.torchOff();
}
return { torch };
});
}
startQuagga() {
const constraints = {
width: {
min: 640,
},
height: {
min: 480,
},
aspectRatio: {
min: 1,
max: 2,
},
focusMode: 'continuous',
...(!this.props.cameraId && { facingMode: 'environment' }),
...(this.props.cameraId && { deviceId: this.props.cameraId }),
};
Quagga.init({
inputStream: {
type: 'LiveStream',
target: document.querySelector('#scannerViewport'),
constraints,
},
locator: {
patchSize: 'medium',
halfSample: true,
},
numOfWorkers: window.navigator.hardwareConcurrency || 2,
decoder: {
readers: ['upc_reader', 'ean_reader'],
},
locate: this.props.camScanLocate,
area: {
top: '25%',
right: '0%',
left: '0%',
bottom: '25%',
},
}, (err) => {
if (err) {
console.error('*** QUAGGA ERROR', err);
console.error('*** If you were not in the Scanner, then this error is meaningless.');
return;
}
Quagga.onProcessed((result) => {
const drawingCtx = Quagga.canvas.ctx.overlay;
const drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
// console.warn('* quagga onProcessed', result);
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute('width')), parseInt(drawingCanvas.getAttribute('height')));
result.boxes.filter((box) => box !== result.box).forEach((box) => {
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: 'purple', lineWidth: 2 });
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: 'blue', lineWidth: 2 });
}
if (result.codeResult && result.codeResult.code) {
const validated = validateBarcode(result.codeResult.code);
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: validated ? 'green' : 'red', lineWidth: 3 });
drawingCtx.font = "24px Arial";
drawingCtx.fillStyle = validated ? 'green' : 'red';
drawingCtx.fillText(`${validated} ${result.codeResult.code}`, 10, 50);
}
}
});
if (this.props.onDetected) {
Quagga.onDetected(this.props.onDetected);
} else {
console.warn('* Quagga initialized, but no onDetected given');
}
Quagga.start();
});
}
componentDidMount() {
console.warn('*********** Scanner componentDidMount props', this.props);
console.warn('* fullscreenEnabled', document.fullscreenEnabled);
window.Quagga = Quagga;
const element = document.querySelector('#scannerViewportContainer');
console.warn('**** scanner container = ', element, element.requestFullscreen);
if (element && element.requestFullscreen) {
element.requestFullscreen()
.then(() => {
this.props.setOrientationLock(true);
this.startQuagga();
})
.catch((err) => {
console.warn('*** error getting fullscreen', err);
this.startQuagga();
})
} else {
this.startQuagga();
}
}
componentWillUnmount() {
// document.exitFullscreen(); // running this here results in "Document not active". weird.
this.props.setOrientationLock(false);
Quagga.offDetected(this.props.onDetected);
Quagga.stop();
}
render() {
return (
<div id="scannerViewportContainer">
<div id="scannerViewport" className={css.scannerViewport}/>
<Link href to="/lookup">
<button className={css.backButton}>
Return to lookup
</button>
</Link>
<button onClick={this.toggleTorch} className={css.torchButton}>
{this.state.torch ? 'Light On' : 'Light Off'}
</button>
{
!this.props.camScanLocate ?
<div style={{ background: 'transparent', border: '1px solid yellow', position: 'absolute', top: '25%', left: '0%', right: '0%', bottom: '25%' }}>place barcode here</div>
:
null
}
</div>
)
}
}
class ScannerContainerBase extends React.Component {
// https://github.com/serratus/quaggaJS/issues/237#issuecomment-389667599
static getMedian(arr) {
arr.sort((a, b) => a - b);
const half = Math.floor(arr.length / 2);
if (arr.length % 2 === 1) {
return arr[half];
}
return (arr[half - 1] + arr[half]) / 2;
}
// TODO: setup an action to begin the download of data immediately from here,
// we do *not* need to wait for the lookup page to get loaded!!! this will require
// moving source of UPC to somewhere other than the URL, and may end up being difficult,
// but the time savings will be useful.
onSuccessScan = (result) => {
try {
document.exitFullscreen();
} catch (err) {
console.warn('**** error exiting fullscreen', err);
}
this.props.notifyScan();
Quagga.offDetected(this.props.onDetected);
this.props.torchOff();
Quagga.stop();
setTimeout(() => {
// this.props.history.push(`/lookup?upc=${result.codeResult.code}`);
this.props.history.push(`/lookup?upc=${result}`);
}, 10);
}
onScan = (result) => {
// TODO: NO FILTER THEN MAP.. USE A REDUCE.
const errors = result.codeResult.decodedCodes.filter(x => x.error !== undefined).map(x => x.error);
const median = ScannerContainerBase.getMedian(errors);
if (median < 0.10) {
if (validateBarcode(result.codeResult.code)) {
this.onSuccessScan(result.codeResult.code);
}
}
}
render() {
return (
<div className={css.scanner}>
{/* <button onClick={this.toggleScanning}>
{ this.state.scanning ? 'Stop' : 'Start'}
</button> */}
{/* { this.state.scanning ? <Scanner onDetected={this.onScan} cameraId={this.props.defaultCamera} /> : null } */}
<Scanner onDetected={this.onScan} cameraId={this.props.defaultCamera} torchOn={this.props.torchOn} torchOff={this.props.torchOff} camScanLocate={this.props.camScanLocate} setOrientationLock={this.props.setOrientationLock}/>
</div>
)
}
}
const mapStateToProps = (state) => ({
defaultCamera: SettingSelector.selectedCamera(state),
camScanLocate: SettingSelector.camScanLocate(state),
});
const mapDispatchToProps = (dispatch) => ({
notifyScan: () => dispatch(doCameraScanNotify()),
torchOn: () => dispatch(enableTorch()),
torchOff: () => dispatch(disableTorch()),
setOrientationLock: (on) => dispatch(lockOrientation(on)),
});
const ScannerContainer = connect(mapStateToProps, mapDispatchToProps)(ScannerContainerBase);
export default ScannerContainer;
.scanner {
border: 1px solid red;
}
.scannerViewport {
border: 1px solid green;
}
/* .scannerViewport video {
position: relative;
left: -25%;
border: 1px solid blue;
} */
.scannerViewport video,canvas {
position: relative;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
.scannerViewport canvas {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
border: 3px solid black;
}
.backButton {
position: absolute;
top: 0px;
left: 0px;
margin-left: 2px;
margin-top: 2px;
z-index: 9999 !important;
}
.torchButton {
position: absolute;
top: 0px;
right: 0px;
margin-right: 2px;
margin-top: 2px;
z-index: 9999 !important;
}
Can We handle a time out, if it does not scan with 5 or 8 seconds ? I need to pass a message "Not able to read barcode", if it does not read the barcode for 5 seconds.
The scanning focus is not proper, sometimes it remains within barcode width or sometimes out of it. How can we customize it ?