QuaggaJS Barcode Scanner Setting EAN13 Code128

Today is very important the use of smartphone / table for work. 
And in many case is important to read barcode or qrcode.

For that, now i want to speak about QuaggaJS a javascript library for reading barcode.
I have used it and setting up for a correct mobile resize of video stream, and for reading code128 and ean13.

At first we must to download it from the website: https://serratus.github.io/quaggaJS/

Install

  1. At first we must to download it from the website: https://serratus.github.io/quaggaJS/
  2. Read the guide about installation https://serratus.github.io/quaggaJS/#installing

Example Page

CSS responsive

#interactive.viewport {
    position: relative;
}

#interactive.viewport > canvas, #interactive.viewport > video {
    max-width: 100%;
    width: 100%;
}

canvas.drawing, canvas.drawingBuffer {
    position: absolute;
    left: 0;
    top: 0;
}
  
@media (max-width: 603px) {

  .reader-config-group {
    width: 100%;
  }

  .reader-config-group label > span {
      width: 50%;
  }

  .reader-config-group label > select, .reader-config-group label > input {
      max-width: calc(50% - 2px);
  }

  #interactive.viewport {
    width: 100%;
    height: auto;
    overflow: hidden;
  }
}

HTML

<div class="card">
    <div class="card-body">
        <div class="row">
          <div class="col-xs-12 col-sm-12 col-md-6">
            <div id="interactive" class="viewport"></div>
          </div>
          <div class="col-xs-12 col-sm-12 col-md-6">
            <div id="result_strip">
          </div>
         </div>
        </div>
    </div>
  </div>

JAVASCRIPT

var AppQuagga = {
    init: function() {
        var self = this;

        Quagga.init(this.state, function(err) {
            if (err) {
                return self.handleError(err);
            }
            //Quagga.registerResultCollector(resultCollector);
            Quagga.start();

            Quagga.onProcessed(function(result) {
                var drawingCtx = Quagga.canvas.ctx.overlay,
                    drawingCanvas = Quagga.canvas.dom.overlay;

                if (result) {
                    if (result.boxes) {
                        drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
                        result.boxes.filter(function (box) {
                            return box !== result.box;
                        }).forEach(function (box) {
                            Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
                        });
                    }

                    if (result.box) {
                        Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
                    }

                    if (result.codeResult &amp;&amp; result.codeResult.code) {
                        Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
                    }
                }
            });

            setTimeout(function() {
              var track = Quagga.CameraAccess.getActiveTrack();
              var capabilities = {};
              if (typeof track.getCapabilities === 'function') {
                try
                  {
                 capabilities = track.getCapabilities(); 
                 track.applyConstraints({advanced: [{zoom: 2.5}]});
                  } catch(e) {}
              }
            }, 500);
        });
    },
    handleError: function(err) {
        console.log(err);
    },
    state: {
        inputStream: {
            type : "LiveStream",
            constraints: {
                facingMode: "environment"
            }
        },
        locator: {
            patchSize: "medium",
            halfSample: true
        },
        numOfWorkers: (navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4),
        frequency: 20,
        decoder: {
            readers : [{
                format: "code_128_reader",
                config: {}
            }, {
                format: "ean_reader",
                config: {
                }
            }, {
                format: "code_39_reader",
                config: {}
            }, {
                format: "code_93_reader",
                config: {}
            }]
        },
        locate: true
    },
    lastResult : null
};



AppQuagga.init();
      
Quagga.onDetected(function(result) {
	var code = result.codeResult.code;

	if(code != null) {
		if (AppQuagga.lastResult !== code) {
			AppQuagga.lastResult = code;

			var $node = null;
			$node = $('<p>Read: '+code+'</p>');
			$("#result_strip").prepend($node);
		}
	}
});

This piece of code is for zoom, and the timeout attend that the videocamera open itself.
For the zoom you can set the max with: capabilities.zoom.max

setTimeout(function() {
  var track = Quagga.CameraAccess.getActiveTrack();
  var capabilities = {};
  if (typeof track.getCapabilities === 'function') {
	try
	  {
	 capabilities = track.getCapabilities(); 
	 track.applyConstraints({advanced: [{zoom: 2.5}]});
	  } catch(e) {}
  }
}, 500);

Javascript Global Error Handler

Today i’have created a simple class to log in the backend the javascript error, so i can have a real time monitoring of how error appear to the users.

We can use a window.onerror and the addEventListener rewrite.

Window.onerror has been available in most browser, but the argument that are passed on each browser are different:

BrowserMessageURLlineNocolNoerrorObj
Firefox
Chrome
Edge
IE 11
IE 10
IE 9, 8
Safari 10 and up
Safari 9
Android Browser 4.4

This is my class with a _wrap function, and a SendError that trasmit the data on the backend

class ErrorHandler {

	constructor() {
		let $this = this;
		$this._prototypeInit();

		window.onerror = function (message, file, line, col, error) {
			let data = message+" from "+error.stack;
			$this.SendError(data);
		};
	}

	_prototypeInit() {
		let $this = this;
		var addEventListener = window.EventTarget.prototype.addEventListener;
		window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
			addEventListener.call(this, event, $this._wrap(callback), bubble);
		}
		var removeEventListener = window.EventTarget.prototype.removeEventListener;
		window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
			removeEventListener.call(this, event, callback._wrapped || callback, bubble);
		}
	}

	_wrap(func) {
		let $this = this;
		if (!func._wrapped) {
			func._wrapped = function () {
				try {
					func.apply(this, arguments);
				} catch (e) {
					let data = e.message+" from "+e.stack;
					$this.SendError(data);
					throw e;
				}
			}
		}
		return func._wrapped;
	}

	SendError(message) {
		let $this = this;
		fetch('/ErrorHandler/WriteLog', {
			method: 'POST',
			body: JSON.stringify({ message: message }),
			headers: {
				'Content-Type': 'application/json'
			}
		}).then(res => res.json()).catch(error => console.error('Error:', error));
	}
}

In the message we put the stacktrace.
To use it at the init of your application:
let handlerError = new HandlerError();

Write to me if you have some suggestion to improve it.