@jackybaby/react-custom-qrcode
Version:
React component to generate a QR Code customizable with logo and more properties
268 lines (267 loc) • 11.6 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.QRCode = void 0;
var isEqual = require("lodash.isequal");
var qrGenerator = require("qrcode-generator");
var React = require("react");
var ReactDOM = require("react-dom");
var QRCode = /** @class */ (function (_super) {
__extends(QRCode, _super);
function QRCode(props) {
var _this = _super.call(this, props) || this;
_this.canvas = React.createRef();
return _this;
}
QRCode.utf16to8 = function (str) {
var out = '', i, c;
var len = str.length;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
}
else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
};
/**
* Draw a rounded square in the canvas
*/
QRCode.prototype.drawRoundedSquare = function (lineWidth, x, y, size, radii, fill, ctx) {
ctx.lineWidth = lineWidth;
// Adjust coordinates so that the outside of the stroke is aligned to the edges
y += lineWidth / 2;
x += lineWidth / 2;
size -= lineWidth;
if (!Array.isArray(radii)) {
radii = [radii, radii, radii, radii];
}
// Radius should not be greater than half the size or less than zero
radii = radii.map(function (r) {
r = Math.min(r, size / 2);
return (r < 0) ? 0 : r;
});
var rTopLeft = radii[0] || 0;
var rTopRight = radii[1] || 0;
var rBottomRight = radii[2] || 0;
var rBottomLeft = radii[3] || 0;
ctx.beginPath();
ctx.moveTo(x + rTopLeft, y);
ctx.lineTo(x + size - rTopRight, y);
if (rTopRight)
ctx.quadraticCurveTo(x + size, y, x + size, y + rTopRight);
ctx.lineTo(x + size, y + size - rBottomRight);
if (rBottomRight)
ctx.quadraticCurveTo(x + size, y + size, x + size - rBottomRight, y + size);
ctx.lineTo(x + rBottomLeft, y + size);
if (rBottomLeft)
ctx.quadraticCurveTo(x, y + size, x, y + size - rBottomLeft);
ctx.lineTo(x, y + rTopLeft);
if (rTopLeft)
ctx.quadraticCurveTo(x, y, x + rTopLeft, y);
ctx.closePath();
ctx.stroke();
if (fill) {
ctx.fill();
}
};
/**
* Draw a single positional pattern eye.
*/
QRCode.prototype.drawPositioningPattern = function (ctx, cellSize, offset, row, col, radii, colors) {
if (radii === void 0) { radii = [0, 0, 0, 0]; }
if (colors === void 0) { colors = ['#000000', '#000000']; }
var lineWidth = Math.ceil(cellSize);
var radiiOuter;
var radiiInner;
var fgColor = this.props.fgColor;
if (typeof radii !== 'number' && !Array.isArray(radii)) {
radiiOuter = radii.outer || 0;
radiiInner = radii.inner || 0;
}
else {
radiiOuter = radii;
radiiInner = radiiOuter;
}
var y = (row * cellSize) + offset;
var x = (col * cellSize) + offset;
var size = cellSize * 7;
ctx.strokeStyle = colors[0];
// Outer box
this.drawRoundedSquare(lineWidth, x, y, size, radiiOuter, false, ctx);
ctx.fillStyle = colors[1];
ctx.strokeStyle = colors[1];
// Inner box
size = cellSize * 3;
y += cellSize * 2;
x += cellSize * 2;
this.drawRoundedSquare(lineWidth, x, y, size, radiiInner, true, ctx);
};
;
/**
* Is this dot inside a positional pattern zone.
*/
QRCode.prototype.isInPositioninZone = function (col, row, zones) {
return zones.some(function (zone) { return (row >= zone.row && row <= zone.row + 7 &&
col >= zone.col && col <= zone.col + 7); });
};
QRCode.prototype.transformPixelLengthIntoNumberOfCells = function (pixelLength, cellSize) {
return pixelLength / cellSize;
};
QRCode.prototype.isCoordinateInImage = function (col, row, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage) {
if (logoImage) {
var numberOfCellsMargin = 2;
var firstRowOfLogo = this.transformPixelLengthIntoNumberOfCells(dxLogo, cellSize);
var firstColumnOfLogo = this.transformPixelLengthIntoNumberOfCells(dyLogo, cellSize);
var logoWidthInCells = this.transformPixelLengthIntoNumberOfCells(dWidthLogo, cellSize) - 1;
var logoHeightInCells = this.transformPixelLengthIntoNumberOfCells(dHeightLogo, cellSize) - 1;
return row >= firstRowOfLogo - numberOfCellsMargin && row <= firstRowOfLogo + logoWidthInCells + numberOfCellsMargin // check rows
&& col >= firstColumnOfLogo - numberOfCellsMargin && col <= firstColumnOfLogo + logoHeightInCells + numberOfCellsMargin; // check cols
}
else {
return false;
}
};
QRCode.prototype.shouldComponentUpdate = function (nextProps) {
return !isEqual(this.props, nextProps);
};
QRCode.prototype.componentDidMount = function () {
this.update();
};
QRCode.prototype.componentDidUpdate = function () {
this.update();
};
QRCode.prototype.update = function () {
var _a = this.props, value = _a.value, ecLevel = _a.ecLevel, enableCORS = _a.enableCORS, size = _a.size, quietZone = _a.quietZone, bgColor = _a.bgColor, fgColor = _a.fgColor, logoImage = _a.logoImage, logoWidth = _a.logoWidth, logoHeight = _a.logoHeight, logoOpacity = _a.logoOpacity, removeQrCodeBehindLogo = _a.removeQrCodeBehindLogo, qrStyle = _a.qrStyle, eyeRadius = _a.eyeRadius, eyeColor = _a.eyeColor;
var qrCode = qrGenerator(0, ecLevel);
qrCode.addData(QRCode.utf16to8(value));
qrCode.make();
var canvas = ReactDOM.findDOMNode(this.canvas.current);
var ctx = canvas.getContext('2d');
var canvasSize = +size + (2 * +quietZone);
var length = qrCode.getModuleCount();
var cellSize = size / length;
var scale = (window.devicePixelRatio || 1);
canvas.height = canvas.width = canvasSize * scale;
ctx.scale(scale, scale);
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvasSize, canvasSize);
var offset = +quietZone;
var dWidthLogo = logoWidth || size * 0.2;
var dHeightLogo = logoHeight || dWidthLogo;
var dxLogo = ((size - dWidthLogo) / 2);
var dyLogo = ((size - dHeightLogo) / 2);
var positioningZones = [
{ row: 0, col: 0 },
{ row: 0, col: length - 7 },
{ row: length - 7, col: 0 },
];
ctx.strokeStyle = fgColor;
if (qrStyle === 'dots') {
ctx.fillStyle = fgColor;
var radius = cellSize / 2;
for (var row = 0; row < length; row++) {
for (var col = 0; col < length; col++) {
if (qrCode.isDark(row, col) && !this.isInPositioninZone(row, col, positioningZones) && !(removeQrCodeBehindLogo && this.isCoordinateInImage(row, col, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage))) {
ctx.beginPath();
ctx.arc(Math.round(col * cellSize) + radius + offset, Math.round(row * cellSize) + radius + offset, (radius / 100) * 75, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
}
}
}
else {
for (var row = 0; row < length; row++) {
for (var col = 0; col < length; col++) {
if (qrCode.isDark(row, col) && !this.isInPositioninZone(row, col, positioningZones) && !(removeQrCodeBehindLogo && this.isCoordinateInImage(row, col, dWidthLogo, dHeightLogo, dxLogo, dyLogo, cellSize, logoImage))) {
ctx.fillStyle = fgColor;
var w = (Math.ceil((col + 1) * cellSize) - Math.floor(col * cellSize));
var h = (Math.ceil((row + 1) * cellSize) - Math.floor(row * cellSize));
ctx.fillRect(Math.round(col * cellSize) + offset, Math.round(row * cellSize) + offset, w, h);
}
}
}
}
// Draw positioning patterns
for (var i = 0; i < 3; i++) {
var _b = positioningZones[i], row = _b.row, col = _b.col;
var radii = eyeRadius;
var colors = eyeColor;
if (Array.isArray(radii)) {
radii = radii[i];
}
if (typeof radii == 'number') {
radii = [radii, radii, radii, radii];
}
if (typeof colors == 'string') {
colors = [eyeColor, eyeColor];
}
this.drawPositioningPattern(ctx, cellSize, offset, row, col, radii, colors);
}
if (logoImage) {
var image_1 = new Image();
if (enableCORS) {
image_1.crossOrigin = 'Anonymous';
}
image_1.onload = function () {
ctx.save();
ctx.globalAlpha = logoOpacity;
ctx.drawImage(image_1, dxLogo + offset, dyLogo + offset, dWidthLogo, dHeightLogo);
ctx.restore();
};
image_1.src = logoImage;
}
};
QRCode.prototype.render = function () {
var _a;
var size = +this.props.size + (2 * +this.props.quietZone);
return React.createElement('canvas', {
id: (_a = this.props.id) !== null && _a !== void 0 ? _a : 'react-qrcode-logo',
height: size,
width: size,
style: { height: size + 'px', width: size + 'px' },
ref: this.canvas
});
};
QRCode.defaultProps = {
value: 'https://reactjs.org/',
ecLevel: 'M',
enableCORS: false,
size: 150,
quietZone: 10,
bgColor: '#FFFFFF',
fgColor: '#000000',
logoOpacity: 1,
removeQrCodeBehindLogo: false,
qrStyle: 'squares',
eyeRadius: [],
eyeColor: [
'#000000',
'#000000',
]
};
return QRCode;
}(React.Component));
exports.QRCode = QRCode;