live_w_locator.js 12 KB

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