Last active
October 30, 2025 07:53
-
-
Save idettman/450524697c99350063a0e1c594239b62 to your computer and use it in GitHub Desktop.
Dynamically generated barcode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Dynamically generated barcode | |
| Author: Isaac A. Dettman | |
| */ | |
| var BarCodeGenerator = (function(window, document) { | |
| var UPC_TO_BARCODE_MAP = [ | |
| [3, 2, 1, 1], | |
| [2, 2, 2, 1], | |
| [2, 1, 2, 2], | |
| [1, 4, 1, 1], | |
| [1, 1, 3, 2], | |
| [1, 2, 3, 1], | |
| [1, 1, 1, 4], | |
| [1, 3, 1, 2], | |
| [1, 2, 1, 3], | |
| [3, 2, 1, 1] | |
| ], | |
| WIDTH = 294, | |
| HEIGHT = 141, | |
| COLOR = 'rgb(172,22,22)', | |
| FONT_SIZE = 34, | |
| FONT = FONT_SIZE + 'px Courier', | |
| REG_BARS_WIDTH = 12, | |
| SUBTRACT_FROM_ALL_BAR_WIDTHS = 0, | |
| SUBTRACT_FROM_BAR_MULTIPLE_1 = 0, | |
| SUBTRACT_FROM_BAR_MULTIPLE_2 = 0, | |
| SUBTRACT_FROM_BAR_MULTIPLE_3 = 0, | |
| SUBTRACT_FROM_BAR_MULTIPLE_4 = 0, | |
| OFFSET_X_FROM_UPC_SEQUENCE_1 = -2, | |
| OFFSET_X_FROM_UPC_SEQUENCE_2 = -2, | |
| OFFSET_Y_FROM_UPC_TEXT = -2, | |
| OFFSET_Y_FROM_REGISTRATION_BARS = 6, | |
| debugMode = false; | |
| var component = function () { | |
| this.init(); | |
| }; | |
| component.prototype = { | |
| constructor: component, | |
| upc: null, | |
| width: 0, | |
| height: 0, | |
| ctx: null, | |
| canvas: null, | |
| extCanvas: null, | |
| barcodeRect: null, | |
| barcodeLeadRect: null, | |
| barcodeTailRect: null, | |
| firstBarSequence: null, | |
| lastBarSequence: null, | |
| init: function () { | |
| this.initCanvas(); | |
| this.drawUpc(); | |
| this.drawBarcode(); | |
| }, | |
| initCanvas: function() { | |
| this.canvas = document.createElement('canvas'); | |
| this.ctx = this.canvas.getContext('2d'); | |
| this.canvas.width = WIDTH; | |
| this.canvas.height = HEIGHT; | |
| this.ctx.font = FONT; | |
| this.ctx.fillStyle = COLOR; | |
| this.width = WIDTH; | |
| this.height = HEIGHT; | |
| if (debugMode) { | |
| this.ctx.fillStyle = 'rgba(150,150,150,0.2)'; | |
| this.ctx.fillRect(0, 0, this.width, this.height); | |
| } | |
| this.ctx.fillStyle = COLOR; | |
| }, | |
| drawUpc: function() { | |
| this.upc = new UPC(); | |
| // Create the lead, middle, and tail registration bars | |
| var firstCharacterWidth = this.ctx.measureText(this.upc.firstCharacter).width; | |
| this.barcodeRect = new Rectangle(firstCharacterWidth, 0, this.width - firstCharacterWidth, this.height); | |
| this.barcodeLeadRect = new RegistrationBars(this.barcodeRect.x, 0, REG_BARS_WIDTH, this.height-FONT_SIZE/2); | |
| this.barcodeLeadRect.drawBars(this.ctx); | |
| this.barcodeTailRect = new RegistrationBars(this.barcodeRect.right-REG_BARS_WIDTH, 0, REG_BARS_WIDTH, this.height-FONT_SIZE/2); | |
| this.barcodeTailRect.drawBars(this.ctx); | |
| this.barcodeMiddleRect = new RegistrationBars(this.barcodeRect.middle - (REG_BARS_WIDTH / 2), 0, REG_BARS_WIDTH, this.height - FONT_SIZE / 2); | |
| this.barcodeMiddleRect.drawBars(this.ctx); | |
| // Draw the lead upc character | |
| this.ctx.fillText(this.upc.firstCharacter, 0, HEIGHT+OFFSET_Y_FROM_UPC_TEXT); | |
| // Draw the first upc sequence | |
| var firstSequenceWidth = this.ctx.measureText(this.upc.firstSequence).width; | |
| var firstSequenceContainerWidth = this.barcodeMiddleRect.x - this.barcodeLeadRect.right; | |
| var firstSequenceX = Math.round(this.barcodeLeadRect.right + (firstSequenceContainerWidth / 2) - (firstSequenceWidth / 2)); | |
| this.ctx.fillText(this.upc.firstSequence, firstSequenceX + OFFSET_X_FROM_UPC_SEQUENCE_1, this.height+OFFSET_Y_FROM_UPC_TEXT); | |
| // Draw the last upc sequence | |
| var lastSequenceWidth = this.ctx.measureText(this.upc.lastSequence).width; | |
| var lastSequenceContainerWidth = this.barcodeTailRect.x - this.barcodeMiddleRect.right; | |
| var lastSequenceX = Math.round(this.barcodeMiddleRect.right + (lastSequenceContainerWidth / 2) - (lastSequenceWidth / 2)); | |
| this.ctx.fillText(this.upc.lastSequence, lastSequenceX + OFFSET_X_FROM_UPC_SEQUENCE_2, this.height+OFFSET_Y_FROM_UPC_TEXT); | |
| }, | |
| drawBarcode: function() { | |
| this.firstBarSequence = new BarSequence(this.barcodeLeadRect.right, 0, this.barcodeMiddleRect.x - this.barcodeLeadRect.right, this.height-FONT_SIZE+OFFSET_Y_FROM_REGISTRATION_BARS); | |
| this.firstBarSequence.drawBarsForUPC(this.ctx, this.upc.firstSequence, UPC_TO_BARCODE_MAP); | |
| this.lastBarSequence = new BarSequence(this.barcodeMiddleRect.right, 0, this.barcodeTailRect.x - this.barcodeMiddleRect.right, this.height-FONT_SIZE+OFFSET_Y_FROM_REGISTRATION_BARS); | |
| this.lastBarSequence.drawBarsForUPC(this.ctx, this.upc.lastSequence, UPC_TO_BARCODE_MAP); | |
| } | |
| }; | |
| var Rectangle = function (x, y, width, height) { | |
| this.init(x | 0, y | 0, width | 0, height | 0); | |
| }; | |
| Rectangle.prototype = { | |
| x: 0, | |
| y: 0, | |
| width: 0, | |
| height: 0, | |
| right: 0, | |
| middle:0, | |
| bottom: 0, | |
| init: function(x, y, width, height) { | |
| this.x = x; | |
| this.y = y; | |
| this.width = width; | |
| this.height = height; | |
| this.right = this.x + this.width; | |
| this.middle = this.x + this.width / 2; | |
| this.bottom = this.y + this.height; | |
| }, | |
| contains: function(x, y) { | |
| x -= this.x; | |
| if (this.width >= 0) { | |
| if (x < 0 || x > this.width) { | |
| return false; | |
| } | |
| } | |
| else if (x > 0 || x < this.width) { | |
| return false; | |
| } | |
| y -= this.y; | |
| if (this.height >= 0) { | |
| if (y < 0 || y > this.height) { | |
| return false; | |
| } | |
| } | |
| else if (y > 0 || y < this.height) { | |
| return false; | |
| } | |
| return true; | |
| }, | |
| drawToCanvas: function(ctx, color) { | |
| var previousFillStyle = ctx.fillStyle; | |
| ctx.fillStyle = color; | |
| ctx.fillRect(this.x, this.y, this.width, this.height); | |
| ctx.fillStyle = previousFillStyle; | |
| } | |
| }; | |
| // Extend Rectangle | |
| var RegistrationBars = function(x, y, width, height) { | |
| Rectangle.apply(this, arguments); | |
| }; | |
| RegistrationBars.prototype = Rectangle.prototype; | |
| RegistrationBars.prototype.constructor = RegistrationBars; | |
| RegistrationBars.prototype.drawBars = function(ctx) { | |
| if (debugMode) { | |
| this.drawToCanvas(ctx, 'rgba(20,255,26,0.4)'); | |
| } | |
| var baseUnitWidth = this.width / 4; | |
| for (var i = 0, offsetX = this.x; i < 4; i++) { | |
| if (i % 2 === 0) { | |
| ctx.fillRect(Math.round(offsetX), 0, Math.round(baseUnitWidth) - SUBTRACT_FROM_ALL_BAR_WIDTHS - SUBTRACT_FROM_BAR_MULTIPLE_1, this.height); | |
| } | |
| offsetX += baseUnitWidth; | |
| } | |
| }; | |
| // Extend Rectangle | |
| var BarSequence = function(x, y, width, height) { | |
| Rectangle.apply(this, arguments); | |
| }; | |
| BarSequence.prototype = Rectangle.prototype; | |
| BarSequence.prototype.constructor = BarSequence; | |
| BarSequence.prototype.drawBarsForUPC = function(ctx, upc, upcMapping) { | |
| if (debugMode) { | |
| this.drawToCanvas(ctx, 'rgba(60,22,126,0.4)'); | |
| } | |
| var baseSegmentWidth = this.width / upc.length / 7; | |
| var padding = upc.length * 2; | |
| for (var i = 0, charAsInt, codeList, offsetX = Math.round(this.x); i < upc.length; i++) { | |
| charAsInt = parseInt(upc[i]); | |
| codeList = upcMapping[charAsInt]; | |
| for (var j = 0, width; j < codeList.length; j++) { | |
| width = Math.round(codeList[j] * baseSegmentWidth)-SUBTRACT_FROM_ALL_BAR_WIDTHS; | |
| switch (codeList[j]) { | |
| case 0: | |
| width-= SUBTRACT_FROM_BAR_MULTIPLE_1; | |
| break; | |
| case 1: | |
| width-= SUBTRACT_FROM_BAR_MULTIPLE_2; | |
| break; | |
| case 2: | |
| width-= SUBTRACT_FROM_BAR_MULTIPLE_3; | |
| break; | |
| case 3: | |
| width-= SUBTRACT_FROM_BAR_MULTIPLE_4; | |
| break; | |
| } | |
| if (j % 2 === 0) { | |
| ctx.fillRect(Math.round(offsetX), 0, width, this.height); | |
| } | |
| offsetX += codeList[j] * baseSegmentWidth; | |
| } | |
| } | |
| }; | |
| var UPC = function () { | |
| this.generate(); | |
| }; | |
| UPC.prototype = { | |
| upcAsString: null, | |
| firstCharacter: null, | |
| firstSequence: null, | |
| lastSequence: null, | |
| generate: function() { | |
| var UPC_LENGTH = 13, randomUpc = []; | |
| for (var i = 0; i < UPC_LENGTH; i++) { | |
| randomUpc.push(Math.round(Math.random()*9)); | |
| } | |
| this.upcAsString = randomUpc.join(''); | |
| this.firstCharacter = this.upcAsString[0]; | |
| this.firstSequence = this.upcAsString.substring(1,Math.round(this.upcAsString.length/2)); | |
| this.lastSequence = this.upcAsString.substring(Math.round(this.upcAsString.length/2), Math.round(this.upcAsString.length)); | |
| } | |
| }; | |
| return component; | |
| })(window, document); | |
| var barcodeGenerator = new BarCodeGenerator(); | |
| document.body.appendChild(barcodeGenerator.canvas); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment