178 lines
5.5 KiB
TypeScript
178 lines
5.5 KiB
TypeScript
// 导入所有条形码
|
||
// @ts-nocheck
|
||
import barcodes from './jsbarcode/barcodes/';
|
||
import fixOptions from './jsbarcode/help/fixOptions';
|
||
import merge from './jsbarcode/help/merge';
|
||
import defaultOptions from './jsbarcode/options/defaults';
|
||
import { InvalidInputException } from './jsbarcode/exceptions/exceptions';
|
||
import linearizeEncodings from './jsbarcode/help/linearizeEncodings';
|
||
import { calculateEncodingAttributes, getTotalWidthOfEncodings, getMaximumHeightOfEncodings } from "./jsbarcode/renderers/shared";
|
||
import { LBarcodeOptions, EncodeResult } from './type'
|
||
|
||
function autoSelectBarcode() : string {
|
||
// 如果有 CODE128,则使用它
|
||
if (barcodes["CODE128"]) {
|
||
return "CODE128";
|
||
}
|
||
|
||
// 否则,使用第一个(或唯一)条形码
|
||
return Object.keys(barcodes)[0];
|
||
}
|
||
// encode() 处理编码器调用并生成要呈现的二进制数据
|
||
function encode(text : string, Encoder : any, options : LBarcodeOptions) : any {
|
||
// 确保文本是字符串
|
||
text = "" + text;
|
||
|
||
let encoder = new Encoder(text, options);
|
||
|
||
// 如果输入对编码器无效,则抛出错误。如果已设置有效回调选项,则调用该选项
|
||
if (!encoder.valid()) {
|
||
throw new InvalidInputException(encoder.constructor.name, text);
|
||
}
|
||
|
||
// 为要呈现的二进制数据发出请求(和其他信息)
|
||
let encoded = encoder.encode();
|
||
|
||
// 编码可以像 [1-1, 1-2], 2, [3-1, 3-2] 一样嵌套
|
||
// 将其转换为 [1-1, 1-2, 2, 3-1, 3-2]
|
||
encoded = linearizeEncodings(encoded);
|
||
|
||
// 合并
|
||
for (let i = 0; i< encoded.length; i++) {
|
||
encoded[i].options = merge(options, encoded[i].options);
|
||
}
|
||
|
||
return encoded;
|
||
}
|
||
|
||
|
||
let timer = null
|
||
function prepareCanvas(element : any, encodings : any, options : LBarcodeOptions) {
|
||
const ctx = element.getContext('2d');
|
||
ctx.save();
|
||
calculateEncodingAttributes(encodings, options, ctx);
|
||
const totalWidth = getTotalWidthOfEncodings(encodings);
|
||
const maxHeight = getMaximumHeightOfEncodings(encodings);
|
||
const width = totalWidth + options.marginLeft + options.marginRight
|
||
// 为避免报黄 Multiple readback operations using getImageData
|
||
element.width = width;
|
||
element.height = maxHeight
|
||
}
|
||
|
||
function drawCanvasBarcode(element : any, options : LBarcodeOptions, encoding : EncodeResult) {
|
||
// Get the canvas context
|
||
const ctx = element.getContext("2d");
|
||
const binary = encoding.data;
|
||
// Creates the barcode out of the encoded binary
|
||
let yFrom = 0;
|
||
if (options.textPosition == "top") {
|
||
yFrom = options.marginTop + options.fontSize + options.textMargin;
|
||
}
|
||
else {
|
||
yFrom = options.marginTop;
|
||
}
|
||
ctx.fillStyle = options.lineColor;
|
||
for (let b = 0; b < binary.length; b++) {
|
||
let x = b * options.width + encoding.barcodePadding;
|
||
if (binary[b] === "1") {
|
||
ctx.fillRect(x, yFrom, options.width, options.height);
|
||
}
|
||
else if (binary[b]) {
|
||
ctx.fillRect(x, yFrom, options.width, options.height * parseInt(binary[b]));
|
||
}
|
||
}
|
||
}
|
||
function drawCanvasText(element : any, options : LBarcodeOptions, encoding : EncodeResult) {
|
||
// Get the canvas context
|
||
const ctx = element.getContext("2d");
|
||
|
||
const font = `${options.fontOptions} ${options.fontSize}px ${options.font}`.trim();
|
||
|
||
// Draw the text if displayValue is set
|
||
if (options.displayValue) {
|
||
let x = 0, y = 0;
|
||
|
||
if (options.textPosition == "top") {
|
||
y = options.marginTop + options.fontSize - options.textMargin;
|
||
}
|
||
else {
|
||
y = options.height + options.textMargin + options.marginTop + options.fontSize;
|
||
}
|
||
|
||
ctx.font = font;
|
||
|
||
// Draw the text in the correct X depending on the textAlign option
|
||
if (options.textAlign == "left" || encoding.barcodePadding > 0) {
|
||
x = 0;
|
||
ctx.textAlign = 'left';
|
||
}
|
||
else if (options.textAlign == "right") {
|
||
x = encoding.width - 1;
|
||
|
||
ctx.textAlign = 'right';
|
||
}
|
||
// In all other cases, center the text
|
||
else {
|
||
x = encoding.width / 2;
|
||
ctx.textAlign = 'center';
|
||
}
|
||
ctx.fillText(encoding.text, x, y);
|
||
}
|
||
}
|
||
function moveCanvasDrawing(element : any, encoding: EncodeResult) {
|
||
const ctx = element.getContext("2d");
|
||
ctx.translate(encoding.width, 0);
|
||
}
|
||
|
||
export function CanvasRenderer(element : any, text : string, options : LBarcodeOptions, cb: ()=> void) {
|
||
if (typeof element === "undefined") {
|
||
throw Error("No element to render on was provided.");
|
||
}
|
||
if (text) {
|
||
let newOptions = { ...defaultOptions, text };
|
||
for (let key in options) {
|
||
const value = options[key]
|
||
if (value || typeof value == 'boolean') {
|
||
newOptions[key] = value
|
||
}
|
||
}
|
||
newOptions = fixOptions(newOptions);
|
||
if (!newOptions.format || newOptions.format == "auto") {
|
||
newOptions.format = autoSelectBarcode();
|
||
}
|
||
if (!element.getContext) {
|
||
throw new Error('不存在 getContext');
|
||
}
|
||
const ctx = element.getContext('2d');
|
||
const Encoder = barcodes[newOptions.format.toUpperCase()];
|
||
const encodings = encode(text, Encoder, newOptions);
|
||
prepareCanvas(element, encodings, newOptions)
|
||
// Paint the canvas
|
||
// clearTimeout(timer)
|
||
setTimeout(() => {
|
||
ctx.clearRect(0, 0, element.width, element.height);
|
||
if (newOptions.background) {
|
||
ctx.fillStyle = newOptions.background;
|
||
ctx.fillRect(0, 0, element.width, element.height);
|
||
}
|
||
ctx.translate(newOptions.marginLeft, 0);
|
||
// render
|
||
for (let i = 0; i < encodings.length; i++) {
|
||
const encodingOptions = merge(newOptions, encodings[i].options);
|
||
|
||
drawCanvasBarcode(element, encodingOptions, encodings[i]);
|
||
drawCanvasText(element, encodingOptions, encodings[i]);
|
||
|
||
moveCanvasDrawing(element, encodings[i]);
|
||
}
|
||
// render end
|
||
ctx.restore();
|
||
if (ctx.draw) {
|
||
ctx.draw(false, cb)
|
||
} else {
|
||
cb && cb()
|
||
}
|
||
}, 300)
|
||
}
|
||
|
||
} |