diff --git a/index.html b/index.html
index 5c58a80..fed8caa 100644
--- a/index.html
+++ b/index.html
@@ -154,7 +154,7 @@
margin: 0 0.2vw;
}
- #card_template, #svg_card_template {
+ #card_template, #svg_card_template, #svg_barcode_template {
display: none;
}
@@ -253,6 +253,10 @@
@@ -299,6 +303,10 @@
Batch Card Printer
+
+
@@ -1346,11 +1354,13 @@
Batch Card Printer
}
let random_batch_button = document.getElementById('random_batch_button');
random_batch_button.onclick = ()=>{
- this.random_batch();
+ let barcode = document.getElementById('Batch_Option_Barcode');
+ barcode.checked ? this.random_batch_with_barcode() : this.random_batch();
}
let unique_batch_button = document.getElementById('unique_batch_button');
unique_batch_button.onclick = ()=>{
- this.unique_batch();
+ let barcode = document.getElementById('Batch_Option_Barcode');
+ barcode.checked ? this.unique_batch_with_barcode() : this.unique_batch();
}
}
@@ -1367,6 +1377,18 @@
Batch Card Printer
this.print_batch(cards);
}
+ random_batch_with_barcode(){
+ let batcher = new this.Batcher(this.bingo);
+ let cards = batcher.generate(parseInt(document.getElementById('batch_amount').value));
+ this.print_batch_with_barcode(cards);
+ }
+
+ unique_batch_with_barcode(){
+ let batcher = new this.Batcher(this.bingo);
+ let cards = batcher.generate_unique_winners(parseInt(document.getElementById('batch_amount').value));
+ this.print_batch_with_barcode(cards);
+ }
+
print_batch(cards){
let batch_cards = [];
for (let card of cards){
@@ -1394,6 +1416,49 @@
Batch Card Printer
a.print();
}
+ print_batch_with_barcode(cards){
+ let batch_cards = [];
+ for (let card of cards){
+ let {numbers, card_id} = card;
+ this.load([card_id, this.bingo.cards.arr_2d_to_3d(numbers.slice(0,25), 5)]);
+ let printer_card = document.getElementById("printer_card").cloneNode(true);
+ printer_card.style.display = "flex";
+ printer_card.style['place-content'] = "";
+
+ let card_div = printer_card.children[1].children[0];
+ card_div.style.width = '80vw';
+ card_div.style.height = '98vh';
+ card_div.style.display='table';
+ card_div.style['table-layout'] = 'fixed';
+
+ let div = document.createElement('div');
+ div.style.position = 'relative';
+ div.style.width = '0';
+ div.style.height = '0';
+ div.style.top = '98vh';
+ div.style.rotate = '-90deg';
+
+ let bcode = new Barcode();
+ let svg = bcode.dashArrayToSVG(bcode.textToCode128B(card_id));
+ svg.setAttribute('viewBox', '0 0 320 50');
+ svg.style.width = '94vh';
+ div.appendChild(svg);
+
+ let card_id_element = printer_card.children[0];
+ card_id_element.style['font-size'] = '12vh';
+ card_id_element.style.width = '97vh';
+ card_id_element.remove();
+ div.appendChild(card_id_element);
+
+ printer_card.appendChild(div);
+ batch_cards.push(printer_card.outerHTML);
+ }
+ var a = window.open('', '', 'height=500, width=500');
+ a.document.write(''+batch_cards.join('
')+'');
+ a.document.close();
+ a.print();
+ }
+
print(){
var divContents = document.getElementById("printer_card").outerHTML;
var a = window.open('', '', 'height=500, width=500');
@@ -1473,6 +1538,269 @@
Batch Card Printer
}
+ class Barcode{
+ // start/stop: "100101101101"
+ code39 = {}
+
+ code39_raw = [
+ [" ", "100110101101"],
+ ["$", "100100100101"],
+ ["%", "101001001001"],
+ ["+", "100101001001"],
+ ["-", "100101011011"],
+ ["/", "100100101001"],
+ [".", "110010101101"],
+ ["0", "101001101101"],
+ ["1", "110100101011"],
+ ["2", "101100101011"],
+ ["3", "110110010101"],
+ ["4", "101001101011"],
+ ["5", "110100110101"],
+ ["6", "101100110101"],
+ ["7", "101001011011"],
+ ["8", "110100101101"],
+ ["9", "101100101101"],
+ ["A", "110101001011"],
+ ["B", "101101001011"],
+ ["C", "110110100101"],
+ ["D", "101011001011"],
+ ["E", "110101100101"],
+ ["F", "101101100101"],
+ ["G", "101010011011"],
+ ["H", "110101001101"],
+ ["I", "101101001101"],
+ ["J", "101011001101"],
+ ["K", "110101010011"],
+ ["L", "101101010011"],
+ ["M", "110110101001"],
+ ["N", "101011010011"],
+ ["O", "110101101001"],
+ ["P", "101101101001"],
+ ["Q", "101010110011"],
+ ["R", "110101011001"],
+ ["S", "101101011001"],
+ ["T", "101011011001"],
+ ["U", "110010101011"],
+ ["V", "100110101011"],
+ ["W", "110011010101"],
+ ["X", "100101101011"],
+ ["Y", "110010110101"],
+ ["Z", "100110110101"],
+ ]
+
+ code128 = {
+ "a": {},
+ "b": {},
+ "c": {},
+ // for reversing the pattern to it's value/index and back
+ "p_i": {},
+ "i_p": {}
+ }
+
+ code128_raw = [
+ [[" ", " ", "00"], "11011001100"],
+ [["!", "!", "01"], "11001101100"],
+ [["\"", "\"", "02"], "11001100110"],
+ [["#", "#", "03"], "10010011000"],
+ [["$", "$", "04"], "10010001100"],
+ [["%", "%", "05"], "10001001100"],
+ [["&", "&", "06"], "10011001000"],
+ [["'", "'", "07"], "10011000100"],
+ [["(", "(", "08"], "10001100100"],
+ [[")", ")", "09"], "11001001000"],
+ [["*", "*", "10"], "11001000100"],
+ [["+", "+", "11"], "11000100100"],
+ [[", ", ", ", "12"], "10110011100"],
+ [["-", "-", "13"], "10011011100"],
+ [[".", ".", "14"], "10011001110"],
+ [["/", "/", "15"], "10111001100"],
+ [["0", "0", "16"], "10011101100"],
+ [["1", "1", "17"], "10011100110"],
+ [["2", "2", "18"], "11001110010"],
+ [["3", "3", "19"], "11001011100"],
+ [["4", "4", "20"], "11001001110"],
+ [["5", "5", "21"], "11011100100"],
+ [["6", "6", "22"], "11001110100"],
+ [["7", "7", "23"], "11101101110"],
+ [["8", "8", "24"], "11101001100"],
+ [["9", "9", "25"], "11100101100"],
+ [[":", ":", "26"], "11100100110"],
+ [[";", ";", "27"], "11101100100"],
+ [["<", "<", "28"], "11100110100"],
+ [["=", "=", "29"], "11100110010"],
+ [[">", ">", "30"], "11011011000"],
+ [["?", "?", "31"], "11011000110"],
+ [["@", "@", "32"], "11000110110"],
+ [["A", "A", "33"], "10100011000"],
+ [["B", "B", "34"], "10001011000"],
+ [["C", "C", "35"], "10001000110"],
+ [["D", "D", "36"], "10110001000"],
+ [["E", "E", "37"], "10001101000"],
+ [["F", "F", "38"], "10001100010"],
+ [["G", "G", "39"], "11010001000"],
+ [["H", "H", "40"], "11000101000"],
+ [["I", "I", "41"], "11000100010"],
+ [["J", "J", "42"], "10110111000"],
+ [["K", "K", "43"], "10110001110"],
+ [["L", "L", "44"], "10001101110"],
+ [["M", "M", "45"], "10111011000"],
+ [["N", "N", "46"], "10111000110"],
+ [["O", "O", "47"], "10001110110"],
+ [["P", "P", "48"], "11101110110"],
+ [["Q", "Q", "49"], "11010001110"],
+ [["R", "R", "50"], "11000101110"],
+ [["S", "S", "51"], "11011101000"],
+ [["T", "T", "52"], "11011100010"],
+ [["U", "U", "53"], "11011101110"],
+ [["V", "V", "54"], "11101011000"],
+ [["W", "W", "55"], "11101000110"],
+ [["X", "X", "56"], "11100010110"],
+ [["Y", "Y", "57"], "11101101000"],
+ [["Z", "Z", "58"], "11101100010"],
+ [["[", "[", "59"], "11100011010"],
+ [["\\", "\\", "60"], "11101111010"],
+ [["]", "]", "61"], "11001000010"],
+ [["^", "^", "62"], "11110001010"],
+ [["_", "_", "63"], "10100110000"],
+ [[String.fromCharCode(0), "", "64"], "10100001100"],
+ [[String.fromCharCode(1), "a", "65"], "10010110000"],
+ [[String.fromCharCode(2), "b", "66"], "10010000110"],
+ [[String.fromCharCode(3), "c", "67"], "10000101100"],
+ [[String.fromCharCode(4), "d", "68"], "10000100110"],
+ [[String.fromCharCode(5), "e", "69"], "10110010000"],
+ [[String.fromCharCode(6), "f", "70"], "10110000100"],
+ [[String.fromCharCode(7), "g", "71"], "10011010000"],
+ [[String.fromCharCode(8), "h", "72"], "10011000010"],
+ [[String.fromCharCode(9), "i", "73"], "10000110100"],
+ [[String.fromCharCode(10), "j", "74"], "10000110010"],
+ [[String.fromCharCode(11), "k", "75"], "11000010010"],
+ [[String.fromCharCode(12), "l", "76"], "11001010000"],
+ [[String.fromCharCode(13), "m", "77"], "11110111010"],
+ [[String.fromCharCode(14), "n", "78"], "11000010100"],
+ [[String.fromCharCode(15), "o", "79"], "10001111010"],
+ [[String.fromCharCode(16), "p", "80"], "10100111100"],
+ [[String.fromCharCode(17), "q", "81"], "10010111100"],
+ [[String.fromCharCode(18), "r", "82"], "10010011110"],
+ [[String.fromCharCode(19), "s", "83"], "10111100100"],
+ [[String.fromCharCode(20), "t", "84"], "10011110100"],
+ [[String.fromCharCode(21), "u", "85"], "10011110010"],
+ [[String.fromCharCode(22), "v", "86"], "11110100100"],
+ [[String.fromCharCode(23), "w", "87"], "11110010100"],
+ [[String.fromCharCode(24), "x", "88"], "11110010010"],
+ [[String.fromCharCode(25), "y", "89"], "11011011110"],
+ [[String.fromCharCode(26), "z", "90"], "11011110110"],
+ [[String.fromCharCode(27), "{", "91"], "11110110110"],
+ [[String.fromCharCode(28), "|", "92"], "10101111000"],
+ [[String.fromCharCode(29), "}", "93"], "10100011110"],
+ [[String.fromCharCode(30), "~", "94"], "10001011110"],
+ [[String.fromCharCode(31), "", "95"], "10111101000"],
+
+ // Control pattern onwards
+ // not really intend for use in this webapp
+ // but included for completeness
+
+ // FNC3
+ [[96, 96, "96"], "10111100010"],
+ // FNC2
+ [[97, 97, "97"], "11110101000"],
+ // SHIFT B, Shift A
+ [[98, 98, "98"], "11110100010"],
+ // Code C
+ [[99, 99, "99"], "10111011110"],
+ // Code B, FNC 4, Code B
+ [[100, 100, 100], "10111101110"],
+ // FNC 4, Code A, Code A
+ [[101, 101, 101], "11101011110"],
+ // FNC 1
+ [[102, 102, 102], "11110101110"],
+ // Start Code A
+ [[103, 103, 103], "11010000100"],
+ // Start Code B
+ [[104, 104, 104], "11010010000"],
+ // Start Code C
+ [[105, 105, 105], "11010011100"],
+ // Stop
+ [[106, 106, 106], "11000111010"],
+ // Reverse Stop
+ [[107, 107, 107], "11010111000"],
+ // Stop pattern (7 bars/spaces)
+ [[108, 108, 108], "1100011101011"],
+ ]
+
+ constructor(){
+ // code39 characters are separated by an additional narrow space.
+ this.code39_raw.forEach((set)=>{
+ let [code, pattern] = set;
+ if (!pattern.endsWith('1')){throw new Error('Code39 data pattern error')}
+ this.code39[code] = pattern + "0"
+ })
+
+ this.code128_raw.forEach((set, i)=>{
+ let [[a,b,c], p] = set;
+ this.code128.a[a] = p;
+ this.code128.b[b] = p;
+ this.code128.c[c] = p;
+ this.code128.p_i[p] = i;
+ this.code128.i_p[i] = p;
+ })
+ }
+
+ patternToWidth(pattern){
+ return pattern.match(/(.)\1*/g).map((x)=>x.length).join(' ')
+ }
+
+ charToWidth(cha, codeset){
+ if (codeset == undefined){
+ cha = cha.toUpperCase();
+ codeset = this.code39;
+ }
+
+ if (cha in codeset === false){
+ throw new Error(`character '${cha}' not in selected codeset!`);
+ }
+ return this.patternToWidth(codeset[cha]);
+ }
+
+ textToWidth(text, codeset){
+ return text.split('').map((x)=>this.charToWidth(x, codeset)).join(' ');
+ }
+
+ textToCode128B(text){
+ if (!/[\x20-\x7F\xC8-\xCF]/.test(text)){
+ throw new Error(`text '${text}' is not encodable to code128b`);
+ }
+
+ // start with 104, the start code of 128b
+ let check_total = text.split("").reduce((p, x, i)=>p+this.code128.p_i[this.code128.b[x]]*(i+1), 104);
+
+ return [this.patternToWidth(this.code128.b[104]),
+ this.textToWidth(text, this.code128.b),
+ this.patternToWidth(this.code128.i_p[check_total%103]),
+ this.patternToWidth(this.code128.b[108])].join(' ')
+ }
+
+ textToCode39(text){
+ if (/[^0-9A-Z\-\.\ \$\/\+\%]/.test(text)){
+ throw new Error(`text '${text}' is not encodable to code39`);
+ }
+
+ let s = this.patternToWidth('1001011011010');
+ return [s, this.textToWidth(text, this.code39), s].join(' ')
+ }
+
+ dashArrayToSVG(dasharray){
+ let len = dasharray.split(' ').reduce((p,x)=>p+parseInt(x),0);
+
+ let svg = document.getElementById('svg_barcode_template').cloneNode(true);
+ svg.removeAttribute('id');
+ let line = svg.children[0];
+ line.setAttribute('x2', len);
+ line.setAttribute('transform',`matrix(${320/len} 0 0 100 0 0)`);
+ line.setAttribute('stroke-dasharray', dasharray);
+ return svg
+ }
+ }
+
class Loader{
constructor(bingo){
this.bingo = bingo;