Skip to content

Instantly share code, notes, and snippets.

@idettman
Last active October 30, 2025 07:53
Show Gist options
  • Select an option

  • Save idettman/450524697c99350063a0e1c594239b62 to your computer and use it in GitHub Desktop.

Select an option

Save idettman/450524697c99350063a0e1c594239b62 to your computer and use it in GitHub Desktop.
Dynamically generated barcode
/*
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