UNPKG

vxe-pc-ui

Version:
150 lines (149 loc) 5.28 kB
import XEUtils from 'xe-utils'; import { toCssUnit } from '../../ui/src/dom'; let canvasEl = null; let fontEl = null; const fontCacheMaps = {}; function getMarkCanvas() { if (!canvasEl) { canvasEl = document.createElement('canvas'); canvasEl.style.position = 'absolute'; canvasEl.style.top = '0'; canvasEl.style.left = '0'; } return canvasEl; } function removeMarkElement(elem) { if (elem) { const parentEl = elem.parentNode; if (parentEl) { parentEl.removeChild(elem); } } } function calcFontWH(text, fontSize) { const fKey = `${fontSize}_${text}`; if (!fontCacheMaps[fKey]) { if (!fontEl) { fontEl = document.createElement('span'); } if (!fontEl.parentNode) { document.body.append(fontEl); } fontEl.textContent = text; fontEl.style.fontSize = toCssUnit(fontSize); const width = fontEl.offsetWidth; const height = fontEl.offsetHeight; fontCacheMaps[fKey] = { width, height }; } return fontCacheMaps[fKey]; } function calcContentWH(contList) { let contentWidth = 0; let contentHeight = 0; contList.forEach(item => { contentWidth = Math.max(item.width, contentWidth); contentHeight = Math.max(item.height, contentHeight); }); return { contentWidth, contentHeight }; } function getFontConf(item, key, opts) { return (item.font ? item.font[key] : '') || (opts.font ? opts.font[key] : ''); } function createMarkFont(contConf, defaultFontSize, opts) { const { offset } = opts; const text = XEUtils.toValueString(contConf.textContent); const fontSize = XEUtils.toNumber(getFontConf(contConf, 'fontSize', opts) || defaultFontSize) || 14; const [offsetX = 0, offsetY = 0] = offset ? ((XEUtils.isArray(offset) ? offset : [offset, offset])) : []; const { width, height } = calcFontWH(text, fontSize); return { text, fontSize, font: contConf.font, width: width + XEUtils.toNumber(offsetX), height: height + XEUtils.toNumber(offsetY) }; } function drayFont(ctx, item, opts) { const fontWeight = getFontConf(item, 'fontWeight', opts); ctx.fillStyle = `${getFontConf(item, 'color', opts) || 'rgba(0, 0, 0, 0.15)'}`; ctx.font = [ getFontConf(item, 'fontStyle', opts) || 'normal', fontWeight === 'bold' || fontWeight === 'bolder' ? 'bold' : '', toCssUnit(item.fontSize), getFontConf(item, 'fontFamily', opts) || 'sans-serif' ].join(' '); } export function getContentUrl(content, defaultFontSize, options) { const opts = Object.assign({}, options); const { rotate } = opts; const deg = XEUtils.toNumber(rotate); const contList = (XEUtils.isArray(content) ? content : [content]).map(item => { if (item) { if (item.textContent) { return createMarkFont(item, defaultFontSize, opts); } return createMarkFont({ textContent: `${item}` }, defaultFontSize, opts); } return createMarkFont({ textContent: '' }, defaultFontSize, opts); }); removeMarkElement(fontEl); return new Promise((resolve) => { const canvasEl = getMarkCanvas(); if (!canvasEl.parentNode) { document.body.append(canvasEl); } const ctx = canvasEl.getContext('2d'); if (ctx && contList.length) { const { gap } = opts; const gapList = gap ? ((XEUtils.isArray(gap) ? gap : [gap, gap])) : []; const gapX = XEUtils.toNumber(gapList[0]); const gapY = XEUtils.toNumber(gapList[1]); const { contentWidth } = calcContentWH(contList); const canvasWidth = contentWidth * 2 + gapX * 2 + (gapX / 2); const canvasHeight = contentWidth * 2 + gapY; canvasEl.width = canvasWidth; canvasEl.height = canvasHeight; const drayX = (gapX / 2); const drayY = contentWidth + (gapY / 2); ctx.save(); ctx.translate(drayX, drayY); ctx.rotate(deg * Math.PI / 180); ctx.translate(-drayX, -drayY); let txtOffsetY = 0; contList.forEach((item) => { drayFont(ctx, item, opts); const txtX = drayX; const txtY = drayY + txtOffsetY; ctx.fillText(item.text, txtX, txtY, contentWidth); txtOffsetY += item.height; }); const offsetX = gapX; const offsetY = gapY + contentWidth; txtOffsetY = 0; contList.forEach((item) => { drayFont(ctx, item, opts); const txtX = drayX + offsetX; const txtY = drayY + txtOffsetY + offsetY; ctx.fillText(item.text, txtX, txtY, contentWidth); txtOffsetY += item.height; }); ctx.restore(); resolve(canvasEl.toDataURL()); removeMarkElement(canvasEl); } else { resolve(''); removeMarkElement(canvasEl); } }); }