live_w_locator.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. $(function() {
  2. var App = {
  3. init : function() {
  4. Quagga.init(this.state, function(err) {
  5. if (err) {
  6. console.log(err);
  7. return;
  8. }
  9. App.attachListeners();
  10. App.checkCapabilities();
  11. Quagga.start();
  12. });
  13. },
  14. checkCapabilities: function() {
  15. var track = Quagga.CameraAccess.getActiveTrack();
  16. var capabilities = {};
  17. if (typeof track.getCapabilities === 'function') {
  18. capabilities = track.getCapabilities();
  19. }
  20. this.applySettingsVisibility('zoom', capabilities.zoom);
  21. this.applySettingsVisibility('torch', capabilities.torch);
  22. },
  23. updateOptionsForMediaRange: function(node, range) {
  24. console.log('updateOptionsForMediaRange', node, range);
  25. var NUM_STEPS = 6;
  26. var stepSize = (range.max - range.min) / NUM_STEPS;
  27. var option;
  28. var value;
  29. while (node.firstChild) {
  30. node.removeChild(node.firstChild);
  31. }
  32. for (var i = 0; i <= NUM_STEPS; i++) {
  33. value = range.min + (stepSize * i);
  34. option = document.createElement('option');
  35. option.value = value;
  36. option.innerHTML = value;
  37. node.appendChild(option);
  38. }
  39. },
  40. applySettingsVisibility: function(setting, capability) {
  41. // depending on type of capability
  42. if (typeof capability === 'boolean') {
  43. var node = document.querySelector('input[name="settings_' + setting + '"]');
  44. if (node) {
  45. node.parentNode.style.display = capability ? 'block' : 'none';
  46. }
  47. return;
  48. }
  49. if (window.MediaSettingsRange && capability instanceof window.MediaSettingsRange) {
  50. var node = document.querySelector('select[name="settings_' + setting + '"]');
  51. if (node) {
  52. this.updateOptionsForMediaRange(node, capability);
  53. node.parentNode.style.display = 'block';
  54. }
  55. return;
  56. }
  57. },
  58. initCameraSelection: function(){
  59. var streamLabel = Quagga.CameraAccess.getActiveStreamLabel();
  60. return Quagga.CameraAccess.enumerateVideoDevices()
  61. .then(function(devices) {
  62. function pruneText(text) {
  63. return text.length > 30 ? text.substr(0, 30) : text;
  64. }
  65. var $deviceSelection = document.getElementById("deviceSelection");
  66. while ($deviceSelection.firstChild) {
  67. $deviceSelection.removeChild($deviceSelection.firstChild);
  68. }
  69. devices.forEach(function(device) {
  70. var $option = document.createElement("option");
  71. $option.value = device.deviceId || device.id;
  72. $option.appendChild(document.createTextNode(pruneText(device.label || device.deviceId || device.id)));
  73. $option.selected = streamLabel === device.label;
  74. $deviceSelection.appendChild($option);
  75. });
  76. });
  77. },
  78. attachListeners: function() {
  79. var self = this;
  80. self.initCameraSelection();
  81. $(".controls").on("click", "button.stop", function(e) {
  82. e.preventDefault();
  83. Quagga.stop();
  84. });
  85. $(".controls .reader-config-group").on("change", "input, select", function(e) {
  86. e.preventDefault();
  87. var $target = $(e.target),
  88. value = $target.attr("type") === "checkbox" ? $target.prop("checked") : $target.val(),
  89. name = $target.attr("name"),
  90. state = self._convertNameToState(name);
  91. console.log("Value of "+ state + " changed to " + value);
  92. self.setState(state, value);
  93. });
  94. },
  95. _accessByPath: function(obj, path, val) {
  96. var parts = path.split('.'),
  97. depth = parts.length,
  98. setter = (typeof val !== "undefined") ? true : false;
  99. return parts.reduce(function(o, key, i) {
  100. if (setter && (i + 1) === depth) {
  101. if (typeof o[key] === "object" && typeof val === "object") {
  102. Object.assign(o[key], val);
  103. } else {
  104. o[key] = val;
  105. }
  106. }
  107. return key in o ? o[key] : {};
  108. }, obj);
  109. },
  110. _convertNameToState: function(name) {
  111. return name.replace("_", ".").split("-").reduce(function(result, value) {
  112. return result + value.charAt(0).toUpperCase() + value.substring(1);
  113. });
  114. },
  115. detachListeners: function() {
  116. $(".controls").off("click", "button.stop");
  117. $(".controls .reader-config-group").off("change", "input, select");
  118. },
  119. applySetting: function(setting, value) {
  120. var track = Quagga.CameraAccess.getActiveTrack();
  121. if (track && typeof track.getCapabilities === 'function') {
  122. switch (setting) {
  123. case 'zoom':
  124. return track.applyConstraints({advanced: [{zoom: parseFloat(value)}]});
  125. case 'torch':
  126. return track.applyConstraints({advanced: [{torch: !!value}]});
  127. }
  128. }
  129. },
  130. setState: function(path, value) {
  131. var self = this;
  132. if (typeof self._accessByPath(self.inputMapper, path) === "function") {
  133. value = self._accessByPath(self.inputMapper, path)(value);
  134. }
  135. if (path.startsWith('settings.')) {
  136. var setting = path.substring(9);
  137. return self.applySetting(setting, value);
  138. }
  139. self._accessByPath(self.state, path, value);
  140. console.log(JSON.stringify(self.state));
  141. App.detachListeners();
  142. Quagga.stop();
  143. App.init();
  144. },
  145. addCode: function(code) {
  146. if (code.match(/^\d\d\d\.\d\d\d$/)) {
  147. code = code.replace('.', '-');
  148. }
  149. if (!App.results.includes(code) && code.match(/^\d\d\d\-\d\d\d$/)) {
  150. App.results.push(code);
  151. var $node = null, canvas = Quagga.canvas.dom.image;
  152. $node = $('<li><div class="thumbnail"><div class="imgWrapper"><img /></div>' +
  153. '<div class="caption"><h4 class="code"></h4></div>' +
  154. '<div class="price"><input type="number" size="5"/></div>' +
  155. '</div></li>');
  156. $node.find("img").attr("src", canvas.toDataURL());
  157. $node.find("h4.code").html(code);
  158. $node.find("input").attr("name", code);
  159. $("#result_strip ul.thumbnails").append($node);
  160. $node.find("input").focus();
  161. }
  162. },
  163. inputMapper: {
  164. inputStream: {
  165. constraints: function(value){
  166. if (/^(\d+)x(\d+)$/.test(value)) {
  167. var values = value.split('x');
  168. return {
  169. width: {min: parseInt(values[0])},
  170. height: {min: parseInt(values[1])}
  171. };
  172. }
  173. return {
  174. deviceId: value
  175. };
  176. }
  177. },
  178. numOfWorkers: function(value) {
  179. return parseInt(value);
  180. },
  181. decoder: {
  182. readers: function(value) {
  183. if (value === 'ean_extended') {
  184. return [{
  185. format: "ean_reader",
  186. config: {
  187. supplements: [
  188. 'ean_5_reader', 'ean_2_reader'
  189. ]
  190. }
  191. }];
  192. }
  193. return [{
  194. format: value + "_reader",
  195. config: {}
  196. }];
  197. }
  198. }
  199. },
  200. state: {
  201. inputStream: {
  202. type : "LiveStream",
  203. constraints: {
  204. width: 640, //{min: 640, max: 640},
  205. height: 480, // {min: 480, max: 480},
  206. aspectRatio: 1, // min: 1, max: 50,
  207. facingMode: "environment" // "environment" // or user
  208. }
  209. },
  210. locator: {
  211. patchSize: "medium",
  212. halfSample: true
  213. },
  214. numOfWorkers: 2,
  215. frequency: 10,
  216. decoder: {
  217. readers : [{
  218. format: "code_128_reader",
  219. config: {}
  220. }]
  221. },
  222. locate: true
  223. },
  224. lastResult : null,
  225. results: []
  226. };
  227. App.init();
  228. Quagga.onProcessed(function(result) {
  229. var drawingCtx = Quagga.canvas.ctx.overlay,
  230. drawingCanvas = Quagga.canvas.dom.overlay;
  231. if (result) {
  232. if (result.boxes) {
  233. drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
  234. result.boxes.filter(function (box) {
  235. return box !== result.box;
  236. }).forEach(function (box) {
  237. Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
  238. });
  239. }
  240. if (result.box) {
  241. Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
  242. }
  243. if (result.codeResult && result.codeResult.code) {
  244. Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
  245. }
  246. }
  247. });
  248. Quagga.onDetected(function(result) {
  249. App.addCode(result.codeResult.code)
  250. });
  251. });