| @@ 4-158 (lines=155) @@ | ||
| 1 | import merge from "../help/merge.js"; |
|
| 2 | import {getEncodingHeight, getBarcodePadding} from "./shared.js"; |
|
| 3 | ||
| 4 | class CanvasRenderer{ |
|
| 5 | constructor(canvas, encodings, options){ |
|
| 6 | this.canvas = canvas; |
|
| 7 | this.encodings = encodings; |
|
| 8 | this.options = options; |
|
| 9 | } |
|
| 10 | ||
| 11 | render(){ |
|
| 12 | // Abort if the browser does not support HTML5 canvas |
|
| 13 | if (!this.canvas.getContext) { |
|
| 14 | throw new Error('The browser does not support canvas.'); |
|
| 15 | } |
|
| 16 | ||
| 17 | this.prepareCanvas(); |
|
| 18 | for(let i = 0; i < this.encodings.length; i++){ |
|
| 19 | var encodingOptions = merge(this.options, this.encodings[i].options); |
|
| 20 | ||
| 21 | this.drawCanvasBarcode(encodingOptions, this.encodings[i]); |
|
| 22 | this.drawCanvasText(encodingOptions, this.encodings[i]); |
|
| 23 | ||
| 24 | this.moveCanvasDrawing(this.encodings[i]); |
|
| 25 | } |
|
| 26 | ||
| 27 | this.restoreCanvas(); |
|
| 28 | } |
|
| 29 | ||
| 30 | prepareCanvas(){ |
|
| 31 | // Get the canvas context |
|
| 32 | var ctx = this.canvas.getContext("2d"); |
|
| 33 | ||
| 34 | ctx.save(); |
|
| 35 | ||
| 36 | // Calculate total width |
|
| 37 | var totalWidth = 0; |
|
| 38 | var maxHeight = 0; |
|
| 39 | for(let i = 0; i < this.encodings.length; i++){ |
|
| 40 | var options = merge(this.options, this.encodings[i].options); |
|
| 41 | var encoding = this.encodings[i]; |
|
| 42 | ||
| 43 | // Set font |
|
| 44 | ctx.font = options.fontOptions + " " + options.fontSize + "px " + options.font; |
|
| 45 | ||
| 46 | // Calculate the width of the encoding |
|
| 47 | var textWidth = ctx.measureText(encoding.text).width; |
|
| 48 | var barcodeWidth = encoding.data.length * options.width; |
|
| 49 | encoding.width = Math.ceil(Math.max(textWidth, barcodeWidth)); |
|
| 50 | ||
| 51 | // Calculate the height of the encoding |
|
| 52 | var height = getEncodingHeight(encoding, options); |
|
| 53 | ||
| 54 | encoding.barcodePadding = getBarcodePadding(textWidth, barcodeWidth, options); |
|
| 55 | ||
| 56 | if(height > maxHeight){ |
|
| 57 | maxHeight = height; |
|
| 58 | } |
|
| 59 | ||
| 60 | totalWidth += encoding.width; |
|
| 61 | } |
|
| 62 | ||
| 63 | this.canvas.width = totalWidth + this.options.marginLeft + this.options.marginRight; |
|
| 64 | ||
| 65 | this.canvas.height = maxHeight; |
|
| 66 | ||
| 67 | // Paint the canvas |
|
| 68 | ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); |
|
| 69 | if(this.options.background){ |
|
| 70 | ctx.fillStyle = this.options.background; |
|
| 71 | ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); |
|
| 72 | } |
|
| 73 | ||
| 74 | ctx.translate(this.options.marginLeft, 0); |
|
| 75 | } |
|
| 76 | ||
| 77 | drawCanvasBarcode(options, encoding){ |
|
| 78 | // Get the canvas context |
|
| 79 | var ctx = this.canvas.getContext("2d"); |
|
| 80 | ||
| 81 | var binary = encoding.data; |
|
| 82 | ||
| 83 | // Creates the barcode out of the encoded binary |
|
| 84 | var yFrom; |
|
| 85 | if(options.textPosition == "top"){ |
|
| 86 | yFrom = options.marginTop + options.fontSize + options.textMargin; |
|
| 87 | } |
|
| 88 | else{ |
|
| 89 | yFrom = options.marginTop; |
|
| 90 | } |
|
| 91 | ||
| 92 | ctx.fillStyle = options.lineColor; |
|
| 93 | ||
| 94 | for(var b = 0; b < binary.length; b++){ |
|
| 95 | var x = b * options.width + encoding.barcodePadding; |
|
| 96 | ||
| 97 | if(binary[b] === "1"){ |
|
| 98 | ctx.fillRect(x, yFrom, options.width, options.height); |
|
| 99 | } |
|
| 100 | else if(binary[b]){ |
|
| 101 | ctx.fillRect(x, yFrom, options.width, options.height * binary[b]); |
|
| 102 | } |
|
| 103 | } |
|
| 104 | } |
|
| 105 | ||
| 106 | drawCanvasText(options, encoding){ |
|
| 107 | // Get the canvas context |
|
| 108 | var ctx = this.canvas.getContext("2d"); |
|
| 109 | ||
| 110 | var font = options.fontOptions + " " + options.fontSize + "px " + options.font; |
|
| 111 | ||
| 112 | // Draw the text if displayValue is set |
|
| 113 | if(options.displayValue){ |
|
| 114 | var x, y; |
|
| 115 | ||
| 116 | if(options.textPosition == "top"){ |
|
| 117 | y = options.marginTop + options.fontSize - options.textMargin; |
|
| 118 | } |
|
| 119 | else{ |
|
| 120 | y = options.height + options.textMargin + options.marginTop + options.fontSize; |
|
| 121 | } |
|
| 122 | ||
| 123 | ctx.font = font; |
|
| 124 | ||
| 125 | // Draw the text in the correct X depending on the textAlign option |
|
| 126 | if(options.textAlign == "left" || encoding.barcodePadding > 0){ |
|
| 127 | x = 0; |
|
| 128 | ctx.textAlign = 'left'; |
|
| 129 | } |
|
| 130 | else if(options.textAlign == "right"){ |
|
| 131 | x = encoding.width - 1; |
|
| 132 | ctx.textAlign = 'right'; |
|
| 133 | } |
|
| 134 | // In all other cases, center the text |
|
| 135 | else{ |
|
| 136 | x = encoding.width / 2; |
|
| 137 | ctx.textAlign = 'center'; |
|
| 138 | } |
|
| 139 | ||
| 140 | ctx.fillText(encoding.text, x, y); |
|
| 141 | } |
|
| 142 | } |
|
| 143 | ||
| 144 | ||
| 145 | ||
| 146 | moveCanvasDrawing(encoding){ |
|
| 147 | var ctx = this.canvas.getContext("2d"); |
|
| 148 | ||
| 149 | ctx.translate(encoding.width, 0); |
|
| 150 | } |
|
| 151 | ||
| 152 | restoreCanvas(){ |
|
| 153 | // Get the canvas context |
|
| 154 | var ctx = this.canvas.getContext("2d"); |
|
| 155 | ||
| 156 | ctx.restore(); |
|
| 157 | } |
|
| 158 | } |
|
| 159 | ||
| 160 | export default CanvasRenderer; |
|
| 161 | ||
| @@ 6-157 (lines=152) @@ | ||
| 3 | ||
| 4 | var svgns = "http://www.w3.org/2000/svg"; |
|
| 5 | ||
| 6 | class SVGRenderer{ |
|
| 7 | constructor(svg, encodings, options){ |
|
| 8 | this.svg = svg; |
|
| 9 | this.encodings = encodings; |
|
| 10 | this.options = options; |
|
| 11 | } |
|
| 12 | ||
| 13 | render(){ |
|
| 14 | var currentX = this.options.marginLeft; |
|
| 15 | ||
| 16 | this.prepareSVG(); |
|
| 17 | for(let i = 0; i < this.encodings.length; i++){ |
|
| 18 | var encoding = this.encodings[i]; |
|
| 19 | var encodingOptions = merge(this.options, encoding.options); |
|
| 20 | ||
| 21 | var group = createGroup(currentX, encodingOptions.marginTop, this.svg); |
|
| 22 | ||
| 23 | setGroupOptions(group, encodingOptions); |
|
| 24 | ||
| 25 | this.drawSvgBarcode(group, encodingOptions, encoding); |
|
| 26 | this.drawSVGText(group, encodingOptions, encoding); |
|
| 27 | ||
| 28 | currentX += encoding.width; |
|
| 29 | } |
|
| 30 | } |
|
| 31 | ||
| 32 | prepareSVG(){ |
|
| 33 | // Clear the SVG |
|
| 34 | while (this.svg.firstChild) { |
|
| 35 | this.svg.removeChild(this.firstChild); |
|
| 36 | } |
|
| 37 | ||
| 38 | var totalWidth = 0; |
|
| 39 | var maxHeight = 0; |
|
| 40 | for(let i = 0; i < this.encodings.length; i++){ |
|
| 41 | var encoding = this.encodings[i]; |
|
| 42 | var options = merge(this.options, this.encodings[i].options); |
|
| 43 | ||
| 44 | // Calculate the width of the encoding |
|
| 45 | var textWidth = messureSVGtext(encoding.text, options); |
|
| 46 | var barcodeWidth = encoding.data.length * options.width; |
|
| 47 | encoding.width = Math.ceil(Math.max(textWidth, barcodeWidth)); |
|
| 48 | ||
| 49 | // Calculate the height of the encoding |
|
| 50 | var encodingHeight = getEncodingHeight(encoding, options); |
|
| 51 | ||
| 52 | encoding.barcodePadding = getBarcodePadding(textWidth, barcodeWidth, options); |
|
| 53 | ||
| 54 | if(encodingHeight > maxHeight){ |
|
| 55 | maxHeight = encodingHeight; |
|
| 56 | } |
|
| 57 | ||
| 58 | totalWidth += encoding.width; |
|
| 59 | } |
|
| 60 | ||
| 61 | var width = totalWidth + this.options.marginLeft + this.options.marginRight; |
|
| 62 | this.setSvgAttributes(width, maxHeight); |
|
| 63 | } |
|
| 64 | ||
| 65 | drawSvgBarcode(parent, options, encoding){ |
|
| 66 | var binary = encoding.data; |
|
| 67 | ||
| 68 | // Creates the barcode out of the encoded binary |
|
| 69 | var yFrom; |
|
| 70 | if(options.textPosition == "top"){ |
|
| 71 | yFrom = options.fontSize + options.textMargin; |
|
| 72 | } |
|
| 73 | else{ |
|
| 74 | yFrom = 0; |
|
| 75 | } |
|
| 76 | ||
| 77 | var barWidth = 0; |
|
| 78 | var x; |
|
| 79 | for(var b = 0; b < binary.length; b++){ |
|
| 80 | x = b * options.width + encoding.barcodePadding; |
|
| 81 | ||
| 82 | if(binary[b] === "1"){ |
|
| 83 | barWidth++; |
|
| 84 | } |
|
| 85 | else if(barWidth > 0){ |
|
| 86 | drawLine(x - options.width * barWidth, yFrom, options.width * barWidth, options.height, parent); |
|
| 87 | barWidth = 0; |
|
| 88 | } |
|
| 89 | } |
|
| 90 | ||
| 91 | // Last draw is needed since the barcode ends with 1 |
|
| 92 | if(barWidth > 0){ |
|
| 93 | drawLine(x - options.width * (barWidth - 1), yFrom, options.width * barWidth, options.height, parent); |
|
| 94 | } |
|
| 95 | } |
|
| 96 | ||
| 97 | drawSVGText(parent, options, encoding){ |
|
| 98 | var textElem = document.createElementNS(svgns, 'text'); |
|
| 99 | ||
| 100 | // Draw the text if displayValue is set |
|
| 101 | if(options.displayValue){ |
|
| 102 | var x, y; |
|
| 103 | ||
| 104 | textElem.setAttribute("style", |
|
| 105 | "font:" + options.fontOptions + " " + options.fontSize + "px " + options.font |
|
| 106 | ); |
|
| 107 | ||
| 108 | if(options.textPosition == "top"){ |
|
| 109 | y = options.fontSize - options.textMargin; |
|
| 110 | } |
|
| 111 | else{ |
|
| 112 | y = options.height + options.textMargin + options.fontSize; |
|
| 113 | } |
|
| 114 | ||
| 115 | // Draw the text in the correct X depending on the textAlign option |
|
| 116 | if(options.textAlign == "left" || encoding.barcodePadding > 0){ |
|
| 117 | x = 0; |
|
| 118 | textElem.setAttribute("text-anchor", "start"); |
|
| 119 | } |
|
| 120 | else if(options.textAlign == "right"){ |
|
| 121 | x = encoding.width - 1; |
|
| 122 | textElem.setAttribute("text-anchor", "end"); |
|
| 123 | } |
|
| 124 | // In all other cases, center the text |
|
| 125 | else{ |
|
| 126 | x = encoding.width / 2; |
|
| 127 | textElem.setAttribute("text-anchor", "middle"); |
|
| 128 | } |
|
| 129 | ||
| 130 | textElem.setAttribute("x", x); |
|
| 131 | textElem.setAttribute("y", y); |
|
| 132 | ||
| 133 | textElem.appendChild(document.createTextNode(encoding.text)); |
|
| 134 | ||
| 135 | parent.appendChild(textElem); |
|
| 136 | } |
|
| 137 | } |
|
| 138 | ||
| 139 | ||
| 140 | setSvgAttributes(width, height){ |
|
| 141 | var svg = this.svg; |
|
| 142 | svg.setAttribute("width", width + "px"); |
|
| 143 | svg.setAttribute("height", height + "px"); |
|
| 144 | svg.setAttribute("x", "0px"); |
|
| 145 | svg.setAttribute("y", "0px"); |
|
| 146 | svg.setAttribute("viewBox", "0 0 " + width + " " + height); |
|
| 147 | ||
| 148 | svg.setAttribute("xmlns", svgns); |
|
| 149 | svg.setAttribute("version", "1.1"); |
|
| 150 | ||
| 151 | svg.style.transform = "translate(0,0)"; |
|
| 152 | ||
| 153 | if(this.options.background){ |
|
| 154 | svg.style.background = this.options.background; |
|
| 155 | } |
|
| 156 | } |
|
| 157 | } |
|
| 158 | ||
| 159 | function messureSVGtext(string, options){ |
|
| 160 | // Set font |
|