export default class Printctrl { /** * @description 绘制模板至缓存 * @param {Object} configs 配置信息 * @param {Boolean} selectId 编辑元素 */ static sketch (configs, selectId, debug = false) { if (!configs.height || !configs.width) return if (configs.height / configs.width > 10 || configs.width / configs.height > 10) return let ratio = parseInt(document.getElementById('darea').style.width) / configs.width * (window.devicePixelRatio || 1) * 1.5 let sizeradio = 210 / configs.width * (window.devicePixelRatio || 1) * 1.5 let canvas = document.createElement('canvas') canvas.height = configs.height * ratio canvas.width = configs.width * ratio let context = canvas.getContext('2d') if (configs.elements.length > 0) { let elements = JSON.parse(JSON.stringify(configs.elements)) elements.forEach(element => { element.left = element.left * ratio element.top = element.top * ratio element.oriwidth = element.width element.oriheight = element.height element.width = element.width * ratio element.height = element.height * ratio if (element.type === 'text') { element.padding = element.padding * ratio element.fontSize = element.fontSize * sizeradio } else if (element.type === 'barcode') { element.barcodeWidth = element.barcodeWidth * ratio element.barcodeHeight = element.barcodeHeight * ratio element.fontSize = element.fontSize * sizeradio } else if (element.type === 'qrcode') { element.qrcodeWidth = element.qrcodeWidth * ratio if (element.qrcodeWidth > element.height) { element.qrcodeWidth = element.height } if (element.qrcodeWidth > element.width) { element.qrcodeWidth = element.width } } else if (element.type === 'image') { element.imgWidth = element.imgWidth * ratio element.imgHeight = element.imgHeight * ratio } }) return new Promise(resolve => { this.sketchothers(context, elements, selectId, debug, ratio, resolve) }) } else { return new Promise(resolve => { this.cachesketch(context, resolve) }) } } /** * @description 绘制图片及文字 * @param {Object} context 画布对象 * @param {Object} elements 图片文字信息 */ static sketchothers (context, elements, selectId, debug, ratio, resolve) { let element = elements.splice(0, 1)[0] // 逐个绘制图片文字 let textLineSpace = 5 // 绘制时行间距,防止文字重叠 context.save() // if (element.rotate) { // 元素旋转时,设置画布旋转角度 // let _cx = element.left + element.width / 2 // let _cy = element.top + element.height / 2 // context.translate(_cx, _cy) // 移动原点 // context.rotate(element.rotate * Math.PI / 180) // context.translate(-_cx, -_cy) // 恢复原点 // } if (selectId === element.uuid) { // 选中元素,设置外部阴影 context.shadowBlur = 5 context.shadowColor = '#1890ff' context.fillStyle = 'white' context.fillRect(element.left, element.top, element.width || 1, element.height || 1) context.shadowBlur = 0 } else if (debug) { context.shadowBlur = 3 context.shadowColor = 'orange' context.fillStyle = 'white' context.fillRect(element.left, element.top, element.width || 1, element.height || 1) context.shadowBlur = 0 } // 绘制边框 // context.rect(element.left + element.borderSize / 2, element.top + element.borderSize / 2, element.width - element.borderSize, element.height - element.borderSize) if (element.borderSize >= 1) { context.beginPath() context.strokeStyle = element.borderColor context.lineWidth = element.borderSize context.rect(element.left, element.top, element.width, element.height) context.stroke() } // 设置背景色 if (!element.borderSize && (element.oriwidth === 1 || element.oriheight === 1)) { // 线 context.strokeStyle = element.background context.beginPath() if (element.oriwidth === 1) { context.moveTo(element.left, element.top) context.lineTo(element.left, element.top + element.height) } else { context.moveTo(element.left, element.top + element.height) context.lineTo(element.left + element.width, element.top + element.height) } context.stroke() } else if (element.background && element.background !== 'white') { context.fillStyle = element.background context.fillRect(element.left, element.top, element.width, element.height) } if (selectId === element.uuid && element.width > 3 * ratio && element.height > 3 * ratio) { // 选中元素,设置外部阴影 context.strokeStyle = '#1890ff' context.beginPath() context.moveTo(element.left + element.width - 7, element.top + element.height - 2) context.lineTo(element.left + element.width - 2, element.top + element.height - 7) context.moveTo(element.left + element.width - 14, element.top + element.height - 2) context.lineTo(element.left + element.width - 2, element.top + element.height - 14) context.stroke() } if (!element.width || !element.height) { context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } else if (element.type === 'text') { // 绘制文字信息 if (element.fontSize < 12) { // 浏览器最小字体 textLineSpace += 12 - element.fontSize } // italic 斜体 small-caps(英文小写字母变成小的大写) context.font = 'normal normal ' + element.fontWeight + ' ' + element.fontSize + 'px ' + element.fontFamily context.fillStyle = element.fontColor let lines = element.value.split('\n') if (!element.value && element.field) { if (element.field === 'other_field') { lines = [element.cusfield || ''] } else { lines = [element.field] } } let _y = element.top + element.padding + element.fontSize + element.borderSize let _left = element.left + element.borderSize + element.padding let _right = element.left + element.width - element.padding - element.borderSize let _width = _right - _left if (element.vertialAlign === 'top') { lines.forEach(text => { if (!text) { _y += element.fontSize + textLineSpace } let _textArr = [] let _text = '' text.split('').forEach(word => { if (context.measureText(_text + word).width <= _width) { _text = _text + word } else { _textArr.push(_text) _text = word } }) _textArr.forEach(word => { let _l = _left if (element.align === 'center') { _l = _left + (_width - context.measureText(word).width) / 2 } else if (element.align === 'right') { _l = _right - context.measureText(word).width } else if (element.align === 'justify') { _l = _left + (_width - context.measureText(word).width) / 2 } context.fillText(word, _l, _y) _y += element.fontSize + textLineSpace }) if (!_text) { return } if (element.align === 'left') { context.fillText(_text, _left, _y) } else if (element.align === 'center') { context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y) } else if (element.align === 'right') { context.fillText(_text, _right - context.measureText(_text).width, _y) } else if (element.align === 'justify') { if (_text.length === 1) { context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y) } else { let _dleft = _left _text.split('').forEach(_word => { context.fillText(_word, _dleft, _y) _dleft += (_width - context.measureText(_text).width) / (_text.length - 1) + context.measureText(_word).width }) } } _y += element.fontSize + textLineSpace }) } else if (element.vertialAlign === 'middle' || element.vertialAlign === 'bottom') { let lineheight = 0 lines.forEach(text => { if (!text) { lineheight += element.fontSize + textLineSpace return } lineheight += Math.ceil(context.measureText(text).width / _width) * (element.fontSize + textLineSpace) }) if (element.vertialAlign === 'middle') { _y += (element.height - element.padding * 2 - element.borderSize * 2 - lineheight) / 2 } else { _y += element.height - element.padding * 2 - element.borderSize * 2 - lineheight } lines.forEach(text => { if (!text) { _y += element.fontSize + textLineSpace } let _textArr = [] let _text = '' text.split('').forEach(word => { if (context.measureText(_text + word).width <= _width) { _text = _text + word } else { _textArr.push(_text) _text = word } }) _textArr.forEach(word => { let _l = _left if (element.align === 'center') { _l = _left + (_width - context.measureText(word).width) / 2 } else if (element.align === 'right') { _l = _right - context.measureText(word).width } else if (element.align === 'justify') { _l = _left + (_width - context.measureText(word).width) / 2 } context.fillText(word, _l, _y) _y += element.fontSize + textLineSpace }) if (!_text) { return } if (element.align === 'left') { context.fillText(_text, _left, _y) } else if (element.align === 'center') { context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y) } else if (element.align === 'right') { context.fillText(_text, _right - context.measureText(_text).width, _y) } else if (element.align === 'justify') { if (_text.length === 1) { context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y) } else { let _dleft = _left _text.split('').forEach(_word => { context.fillText(_word, _dleft, _y) _dleft += (_width - context.measureText(_text).width) / (_text.length - 1) + context.measureText(_word).width }) } } _y += element.fontSize + textLineSpace }) } context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } else if (element.type === 'barcode') { let _space = 5 let _left = element.left let _top = element.top if (element.vertialAlign === 'middle') { if (element.barcodeLabel === 'true') { _top = element.top + (element.height - element.barcodeHeight - element.fontSize - _space) / 2 } else { _top = element.top + (element.height - element.barcodeHeight) / 2 } } else if (element.vertialAlign === 'bottom') { if (element.barcodeLabel === 'true') { _top = element.top + (element.height - element.barcodeHeight - element.fontSize - _space) } else { _top = element.top + element.height - element.barcodeHeight } } if (element.align === 'center') { _left = element.left + (element.width - element.barcodeWidth) / 2 } else if (element.align === 'right') { _left = element.left + element.width - element.barcodeWidth } context.font = 'normal normal normal ' + element.fontSize + 'px Microsoft YaHei' context.fillStyle = 'black' let text = '1234567890123' let _tleft = _left + (element.barcodeWidth - context.measureText(text).width) / 2 let _ttop = _top + element.barcodeHeight + _space + element.fontSize let image = new Image() image.src = element.url if (image.complete) { context.drawImage(image, _left, _top, element.barcodeWidth, element.barcodeHeight) if (element.barcodeLabel === 'true') { context.fillText(text, _tleft, _ttop) } context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } else { image.onload = () => { context.drawImage(image, _left, _top, element.barcodeWidth, element.barcodeHeight) if (element.barcodeLabel === 'true') { context.fillText(text, _tleft, _ttop) } context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } } } else if (element.type === 'qrcode') { let _left = element.left let _top = element.top if (element.vertialAlign === 'middle') { _top = element.top + (element.height - element.qrcodeWidth) / 2 } else if (element.vertialAlign === 'bottom') { _top = element.top + element.height - element.qrcodeWidth } if (element.align === 'center') { _left = element.left + (element.width - element.qrcodeWidth) / 2 } else if (element.align === 'right') { _left = element.left + element.width - element.qrcodeWidth } let image = new Image() image.src = element.url if (image.complete) { context.drawImage(image, _left, _top, element.qrcodeWidth, element.qrcodeWidth) context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } else { image.onload = () => { context.drawImage(image, _left, _top, element.qrcodeWidth, element.qrcodeWidth) context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } } } else if (element.type === 'image') { let _left = element.left let _top = element.top if (element.vertialAlign === 'middle') { _top = element.top + (element.height - element.imgHeight) / 2 } else if (element.vertialAlign === 'bottom') { _top = element.top + element.height - element.imgHeight } if (element.align === 'center') { _left = element.left + (element.width - element.imgWidth) / 2 } else if (element.align === 'right') { _left = element.left + element.width - element.imgWidth } let image = new Image() image.src = element.url if (element.value && element.value.indexOf(window.location.hostname) > -1) { image.src = element.value } if (image.complete) { context.drawImage(image, _left, _top, element.imgWidth, element.imgHeight) context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } else { image.onload = () => { context.drawImage(image, _left, _top, element.imgWidth, element.imgHeight) context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } } image.onerror = () => { context.restore() // 重置画布 if (elements.length > 0) { this.sketchothers(context, elements, selectId, debug, ratio, resolve) } else { this.cachesketch(context, resolve) } } } } /** * @description 绘制模板值页面 * @param {Object} configs 配置信息 */ static cachesketch (context, resolve) { let cacheCanvas = context.canvas let canvas = document.getElementById('darea') canvas.width = cacheCanvas.width canvas.height = cacheCanvas.height let ctx = canvas.getContext('2d') ctx.clearRect(0, 0, canvas.width + 1, canvas.height + 1) ctx.beginPath() ctx.fillStyle = 'white' ctx.fillRect(0, 0, canvas.width + 1, canvas.height + 1) ctx.drawImage(cacheCanvas, 0, 0, canvas.width, canvas.height) resolve(canvas.toDataURL('image/png')) } }