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;
|
||||
},
|
||||
toPromise() {
|
||||
// how to cancel?? timeout!
|
||||
return new Promise((resolve, reject) => {
|
||||
scanner.decodeSingle(config, (result) => {
|
||||
if (result && result.codeResult && result.codeResult.code) {
|
||||
return resolve(result);
|
||||
}
|
||||
return reject(result);
|
||||
if (config.inputStream.type === 'LiveStream'
|
||||
|| config.inputStream.type === 'VideoStream') {
|
||||
let cancelRequested = false;
|
||||
return {
|
||||
cancel() {
|
||||
cancelRequested = true;
|
||||
},
|
||||
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) {
|
||||
return setConfig(configuration, "locator", conf);
|
||||
},
|
||||
throttle(timeInMs) {
|
||||
return setConfig(configuration, "frequency", 1000 / parseInt(timeInMs));
|
||||
},
|
||||
config(conf) {
|
||||
return createApi(merge({}, configuration, conf));
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user