red-agate-barcode
Version:
red-agate barcode tag library.
248 lines • 9.01 kB
JavaScript
// Copyright (c) 2017, Shellyl_N and Authors
// license: ISC
// https://github.com/shellyln
import * as RedAgate from 'red-agate/modules/red-agate';
import { SvgCanvas } from 'red-agate-svg-canvas/modules/drawing/canvas/SvgCanvas';
import { shapePropsDefault, Shape, renderSvgCanvas, toImgTag, toElementStyle, toDataUrl, toSvg, CONTEXT_SVG_CANVAS } from 'red-agate/modules/red-agate/tags/Shape';
export const barcodeBasePropsDefault = Object.assign({}, shapePropsDefault, {
fillColor: "black",
font: "normal 3.5px 'OCRB'",
rotation: 0,
height: 6.35,
quietWidth: 2.54,
quietHeight: 0.66,
unit: "mm",
drawText: true,
useRawDataAsText: false,
textHeight: 3.55
});
export class BarcodeBase extends Shape {
constructor(props, charactersMap) {
super(Object.assign({}, barcodeBasePropsDefault, props));
this.charactersMap = charactersMap;
}
toImgTag() {
return toImgTag(this);
}
toElementStyle() {
return toElementStyle(this);
}
toDataUrl() {
return toDataUrl(this);
}
toSvg() {
return toSvg(this);
}
toRendered() {
return RedAgate.renderAsHtml_noDefer(this);
}
render(contexts, children) {
let canvas = this.getContext(contexts, CONTEXT_SVG_CANVAS);
const contextHasCanvas = Boolean(canvas);
if (!contextHasCanvas) {
canvas = new SvgCanvas();
this.setContext(contexts, CONTEXT_SVG_CANVAS, canvas);
super.beforeRender(contexts);
}
let data = this.props.data || "";
let text = this.props.text;
const originalData = data;
let heightData, labelText, startChar, stopChar;
({ data, heightData, labelText, startChar, stopChar } = this.encodeData(data));
const cdChar = this.calcCheckDigit(data);
// tw: total width (quiet + data + start + stop + cd)
// th: total height (quiet + bar + text)
const { tw, th } = this.calcSymbolSize(data, startChar, stopChar, cdChar);
data = `${startChar}${data}${cdChar}${stopChar}`;
if (labelText !== void 0) {
text = labelText;
}
else {
if (text === void 0 || text === null)
text = this.props.text;
if (text === void 0 || text === null)
text = originalData;
}
let rotation = (this.props.rotation === void 0 || this.props.rotation === null) ?
0 : Math.floor(this.props.rotation / 90) % 4;
if (rotation < 0)
rotation += 4;
switch (rotation) {
case 1:
canvas.rotate(Math.PI * 1.5);
canvas.translate(-tw, 0);
break;
case 2:
canvas.rotate(Math.PI);
canvas.translate(-tw, -th);
break;
case 3:
canvas.rotate(Math.PI * 0.5);
canvas.translate(0, -th);
break;
}
if (this.props.drawText) {
canvas.beginGroup();
}
if (this.isHeightModulated) {
this.renderHeightModulatedBarData(canvas, tw, th, data, heightData, text);
}
else {
this.renderBarData(canvas, tw, th, data, heightData, text);
}
this.renderAdditional(canvas, tw, th, data, text);
if (this.props.drawText) {
canvas.endGroup();
canvas.beginGroup();
}
if (this.props.drawText) {
if (this.props.font)
canvas.font = this.props.font;
this.renderText(canvas, tw, th, data, text);
}
if (this.props.drawText) {
canvas.endGroup();
}
if (contextHasCanvas) {
return ``;
}
else {
super.afterRender(contexts);
this.unsetContext(contexts, CONTEXT_SVG_CANVAS);
const imageWidth = tw + (this.props.x || 0);
const imageHeight = th + (this.props.y || 0);
return renderSvgCanvas(this.props, canvas, imageWidth, imageHeight);
}
}
// total width (quiet + data + start + stop + cd)
// total height (quiet + bar + text)
calcSymbolSize(data, startChar, stopChar, cdChar) {
return {
// total width (quiet + data + start + stop + cd)
tw: 0,
// total height (quiet + bar + text)
th: 0
};
}
calcCheckDigit(data) {
return "";
}
encodeData(data) {
return { data, startChar: "", stopChar: "" };
}
getBarSpaceWidth() {
return [];
}
getBarSpaceHeight() {
const props = this.props;
return [[{ offset: 0, height: props.height }]];
}
getRenderStartCoodinate(data, text) {
const props = this.props;
return { rx: props.quietWidth, ry: props.quietHeight };
}
get isHeightModulated() {
return false;
}
renderBarData(canvas, tw, th, data, heightData, text) {
const bw = this.getBarSpaceWidth();
const vseg = this.getBarSpaceHeight();
// tslint:disable-next-line:prefer-const
let { rx, ry } = this.getRenderStartCoodinate(data, text);
for (let i = 0; i < data.length; i++) {
const cmap = this.charactersMap.get(data[i]);
if (!cmap) {
throw new Error("BarcodeBase#renderBarData: character is out of range.");
}
const pattern = cmap.pattern;
let bar = true;
let dx = 0;
for (let j = 0; j < pattern.length; j++) {
const c = pattern[j];
switch (c) {
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
// "0" is character gap
{
const w = bw[Number.parseInt(c, 10)];
if (bar) {
const ss = (heightData === void 0) ? vseg[0] : vseg[Number.parseInt(heightData[i], 10)];
for (const seg of ss) {
canvas.rect(rx + dx, ry + seg.offset, w, seg.height);
}
}
dx += w;
bar = !bar;
}
break;
case "+":
bar = true;
break;
case "-":
bar = false;
break;
}
}
rx += dx;
}
canvas.fill();
canvas.beginPath();
}
renderHeightModulatedBarData(canvas, tw, th, data, heightData, text) {
const bw = this.getBarSpaceWidth();
const w = bw[1];
const vseg = this.getBarSpaceHeight();
// tslint:disable-next-line:prefer-const
let { rx, ry } = this.getRenderStartCoodinate(data, text);
for (let i = 0; i < data.length; i++) {
const pattern = this.charactersMap.get(data[i]).pattern;
const bar = true;
let dx = 0;
for (let j = 0; j < pattern.length; j++) {
const c = pattern[j];
switch (c) {
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
{
const ss = vseg[Number.parseInt(c, 10)];
for (const seg of ss) {
canvas.rect(rx + dx, ry + seg.offset, w, seg.height);
}
}
// FALL THRU
case "0":
// "0" is space
dx += w * 2;
break;
}
}
rx += dx;
}
canvas.fill();
canvas.beginPath();
}
renderAdditional(canvas, tw, th, data, text) {
}
renderText(canvas, tw, th, data, text) {
const props = this.props;
canvas.textAlign = "center";
canvas.textBaseline = "alphabetic";
canvas.fillText(props.useRawDataAsText ? data : text, tw / 2, th - props.quietHeight);
}
}
//# sourceMappingURL=BarcodeBase.js.map