mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-13 05:31:37 +08:00
Started working on sandbox
This commit is contained in:
Vendored
+598
-433
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+4
-4
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["transform-class-properties"],
|
||||||
|
"presets": ["es2015-webpack", "stage-0", "react"]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
static/*.js*
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Quagga meets React
|
||||||
|
|
||||||
|
This example uses webpack & babel to transpile/bundle the required files.
|
||||||
|
|
||||||
|
## How to run the example
|
||||||
|
|
||||||
|
```console
|
||||||
|
> npm install && webpack
|
||||||
|
```
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
|
||||||
|
<title>index</title>
|
||||||
|
<meta name="description" content="" />
|
||||||
|
<meta name="author" content="Christoph Oberhofer" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="static/style.css" />
|
||||||
|
<meta name="viewport" content="width=device-width; initial-scale=1.0" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="margin: 0">
|
||||||
|
<div id="react"></div>
|
||||||
|
<script src="static/bundle.js" type="text/javascript"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "quagga-react",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Christoph Oberhofer <ch.oberhofer@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.9.0",
|
||||||
|
"babel-loader": "^6.2.4",
|
||||||
|
"babel-plugin-transform-class-properties": "^6.9.0",
|
||||||
|
"babel-preset-es2015-webpack": "^6.4.1",
|
||||||
|
"babel-preset-react": "^6.5.0",
|
||||||
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
|
"webpack": "^2.1.0-beta.7"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"material-ui": "^0.15.0",
|
||||||
|
"react": "^15.1.0",
|
||||||
|
"react-dom": "^15.1.0",
|
||||||
|
"react-tap-event-plugin": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import AppBar from 'material-ui/AppBar';
|
||||||
|
import Drawer from 'material-ui/Drawer';
|
||||||
|
import MenuItem from 'material-ui/MenuItem';
|
||||||
|
import Paper from 'material-ui/Paper';
|
||||||
|
import FloatingActionButton from 'material-ui/FloatingActionButton';
|
||||||
|
import ContentAdd from 'material-ui/svg-icons/content/add';
|
||||||
|
import Dialog from 'material-ui/Dialog';
|
||||||
|
import FlatButton from 'material-ui/FlatButton';
|
||||||
|
import {Card, CardTitle, CardText} from 'material-ui/Card';
|
||||||
|
|
||||||
|
import Scanner from './Scanner';
|
||||||
|
import ScanIcon from './ScanIcon';
|
||||||
|
|
||||||
|
export default class App extends React.Component {
|
||||||
|
state = {
|
||||||
|
drawerOpen: false,
|
||||||
|
scanning: false,
|
||||||
|
scannedCodes: [{
|
||||||
|
codeResult: {
|
||||||
|
code: "FANAVF1461710",
|
||||||
|
format: "code_128"
|
||||||
|
},
|
||||||
|
timestamp: new Date()
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleClose = () => this.setState({drawerOpen: false});
|
||||||
|
_handleOpen = () => this.setState({drawerOpen: true});
|
||||||
|
_handleOpenChange = () => (drawerOpen) => this.setState({drawerOpen});
|
||||||
|
|
||||||
|
_startScanning = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!this.state.scanning) {
|
||||||
|
this.setState({scanning: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_stopScanning = () => {
|
||||||
|
this.setState({scanning: false});
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleResult = (result) => {
|
||||||
|
this._stopScanning();
|
||||||
|
this.setState({
|
||||||
|
scannedCodes: [{...result, timestamp: new Date()}]
|
||||||
|
.concat(this.state.scannedCodes)});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Drawer
|
||||||
|
docked={false}
|
||||||
|
width={200}
|
||||||
|
open={this.state.drawerOpen}
|
||||||
|
onRequestChange={this._handleOpenChange}
|
||||||
|
>
|
||||||
|
<MenuItem onTouchTap={this._handleClose}>Menu Item</MenuItem>
|
||||||
|
<MenuItem onTouchTap={this._handleClose}>Menu Item 2</MenuItem>
|
||||||
|
</Drawer>
|
||||||
|
<AppBar
|
||||||
|
style={{position: 'fixed', top: '0px'}}
|
||||||
|
title="QuaggaJS"
|
||||||
|
iconClassNameRight="muidocs-icon-navigation-expand-more"
|
||||||
|
onLeftIconButtonTouchTap={this._handleOpen}
|
||||||
|
/>
|
||||||
|
<FloatingActionButton
|
||||||
|
secondary={true}
|
||||||
|
onMouseDown={this._startScanning}
|
||||||
|
style={{position: 'fixed', right: 0, bottom: 0, margin: '0 1em 1em 0'}}
|
||||||
|
>
|
||||||
|
<ScanIcon />
|
||||||
|
</FloatingActionButton>
|
||||||
|
<Dialog
|
||||||
|
style={{paddingTop: '0px'}}
|
||||||
|
bodyStyle={{padding: '0.5rem'}}
|
||||||
|
repositionOnUpdate={false}
|
||||||
|
actions={[
|
||||||
|
<FlatButton
|
||||||
|
label="Cancel"
|
||||||
|
primary={true}
|
||||||
|
onTouchTap={this._stopScanning}/>
|
||||||
|
]}
|
||||||
|
modal={true}
|
||||||
|
contentStyle={{width: '95%', maxWidth: '95%', height: '95%', maxHeight: '95%'}}
|
||||||
|
open={this.state.scanning}
|
||||||
|
>
|
||||||
|
<Scanner onDetected={this._handleResult} onCancel={this._stopScanning} />
|
||||||
|
</Dialog>
|
||||||
|
<div style={{paddingTop: '64px'}}>
|
||||||
|
{this.state.scannedCodes.map((scannedCode, i) => (
|
||||||
|
<Card key={i} style={{margin: '0.5em 0.25em 0em'}}>
|
||||||
|
<CardTitle
|
||||||
|
titleStyle={{textOverflow: 'ellipsis', overflow: 'hidden'}}
|
||||||
|
title={scannedCode.codeResult.code}
|
||||||
|
subtitle={scannedCode.codeResult.format}
|
||||||
|
/>
|
||||||
|
<CardText>
|
||||||
|
Scanned on {scannedCode.timestamp.toLocaleString()}
|
||||||
|
</CardText>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import pure from 'recompose/pure';
|
||||||
|
import SvgIcon from 'material-ui/SvgIcon';
|
||||||
|
|
||||||
|
let ActionScanBarcode = (props) => (
|
||||||
|
<SvgIcon {...props}>
|
||||||
|
<path d="M0 4h4v20h-4zM6 4h2v20h-2zM10 4h2v20h-2zM16 4h2v20h-2zM24 4h2v20h-2zM30 4h2v20h-2zM20 4h1v20h-1zM14 4h1v20h-1zM27 4h1v20h-1zM0 26h2v2h-2zM6 26h2v2h-2zM10 26h2v2h-2zM20 26h2v2h-2zM30 26h2v2h-2zM24 26h4v2h-4zM14 26h4v2h-4z"/>
|
||||||
|
</SvgIcon>
|
||||||
|
);
|
||||||
|
|
||||||
|
ActionScanBarcode = pure(ActionScanBarcode);
|
||||||
|
ActionScanBarcode.displayName = 'ActionAccessibility';
|
||||||
|
ActionScanBarcode.muiName = 'SvgIcon';
|
||||||
|
|
||||||
|
export default ActionScanBarcode;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Quagga from '../../../../dist/quagga';
|
||||||
|
|
||||||
|
export default class Scanner extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this._scanner = Quagga
|
||||||
|
.decoder({readers: ['code_128_reader']})
|
||||||
|
.locator({patchSize: 'medium'})
|
||||||
|
.throttle(500)
|
||||||
|
.fromSource({
|
||||||
|
target: '.overlay__content',
|
||||||
|
constraints: {
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
facingMode: "environment"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._onCancel = this._onCancel.bind(this);
|
||||||
|
}
|
||||||
|
_onCancel(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (this._scanUntilResult) {
|
||||||
|
this._scanUntilResult.cancel();
|
||||||
|
this._scanUntilResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="overlay__content">
|
||||||
|
<div className="overlay__close" onClick={this._onCancel}>X</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
this._scanUntilResult = this._scanner.toPromise();
|
||||||
|
this._scanUntilResult.promise
|
||||||
|
.then(this.props.onDetected)
|
||||||
|
.catch(this.props.onCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._scanner
|
||||||
|
.removeEventListener('detected', this.props.onDetected)
|
||||||
|
.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './components/App';
|
||||||
|
import getMuiTheme from 'material-ui/styles/getMuiTheme';
|
||||||
|
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
||||||
|
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
|
|
||||||
|
injectTapEventPlugin();
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<MuiThemeProvider muiTheme={getMuiTheme()}>
|
||||||
|
<App />
|
||||||
|
</MuiThemeProvider>,
|
||||||
|
document.getElementById('react')
|
||||||
|
);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
module.exports = {
|
||||||
|
entry: [
|
||||||
|
'./src/index.js'
|
||||||
|
],
|
||||||
|
devtool: 'source-map',
|
||||||
|
module: {
|
||||||
|
loaders: [{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /(node_modules|quagga\.js)/,
|
||||||
|
loader: 'babel-loader'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
modules: [
|
||||||
|
'node_modules'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: __dirname + '/static',
|
||||||
|
publicPath: '/',
|
||||||
|
filename: 'bundle.js'
|
||||||
|
}
|
||||||
|
};
|
||||||
+601
-424
File diff suppressed because it is too large
Load Diff
+1
-1
File diff suppressed because one or more lines are too long
+36
-8
@@ -35,15 +35,40 @@ function fromSource(config, source, inputConfig = {}) {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
toPromise() {
|
toPromise() {
|
||||||
// how to cancel?? timeout!
|
if (config.inputStream.type === 'LiveStream'
|
||||||
return new Promise((resolve, reject) => {
|
|| config.inputStream.type === 'VideoStream') {
|
||||||
scanner.decodeSingle(config, (result) => {
|
let cancelRequested = false;
|
||||||
if (result && result.codeResult && result.codeResult.code) {
|
return {
|
||||||
return resolve(result);
|
cancel() {
|
||||||
}
|
cancelRequested = true;
|
||||||
return reject(result);
|
},
|
||||||
|
promise: new Promise((resolve, reject) => {
|
||||||
|
function onProcessed(result) {
|
||||||
|
if (result && result.codeResult && result.codeResult.code) {
|
||||||
|
scanner.stop();
|
||||||
|
scanner.unsubscribe("processed", onProcessed);
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
if (cancelRequested) {
|
||||||
|
scanner.stop();
|
||||||
|
scanner.unsubscribe("processed", onProcessed);
|
||||||
|
reject("cancelled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scanner.subscribe("processed", onProcessed);
|
||||||
|
this.start();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
scanner.decodeSingle(config, (result) => {
|
||||||
|
if (result && result.codeResult && result.codeResult.code) {
|
||||||
|
return resolve(result);
|
||||||
|
}
|
||||||
|
return reject(result);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -66,6 +91,9 @@ function createApi(configuration = Config) {
|
|||||||
locator(conf) {
|
locator(conf) {
|
||||||
return setConfig(configuration, "locator", conf);
|
return setConfig(configuration, "locator", conf);
|
||||||
},
|
},
|
||||||
|
throttle(timeInMs) {
|
||||||
|
return setConfig(configuration, "frequency", 1000 / parseInt(timeInMs));
|
||||||
|
},
|
||||||
config(conf) {
|
config(conf) {
|
||||||
return createApi(merge({}, configuration, conf));
|
return createApi(merge({}, configuration, conf));
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user