UNPKG

wapp-cli

Version:
367 lines (300 loc) 9.29 kB
import { strLen } from '.'; interface ICtx { ctx: WXContext; } interface IShadow { shadow: { offsetX?: number; offsetY?: number; blur: number; color: string; }; } interface IFillStyle { color: string; } interface IFontSize { fontSize: number; } interface ITextAlign { align: string; } interface IRect { x: number; y: number; width: number; height: number; } interface IArc { x: number; y: number; r: number; startAngle?: number; sweepAngle?: number; } interface IDottedLine { margin: number; } interface IImage { imageResource: string; x: number; y: number; width: number; height: number; } interface IText { text: string; x: number; y: number; } interface IStrongText { strongText: { text: string; color: string; fontSize: number; }; } interface ITextBaseLine { baseline: string; } interface IBold { isBold: boolean; } interface ITextWidthWrap { maxWidth: number; maxLine: number; lineHeight: number; } interface IHalfMode { isHalfMode: boolean; } export function setShadow<T extends ICtx & IShadow>(options: T) { const { ctx, shadow } = options; ctx.setShadow(0, 0, shadow.blur, shadow.color); } // 绘制背景底色 export function drawBaseBackground<T extends ICtx & IFillStyle & IRect>(options: T) { const { ctx, color, x, y, width, height } = options; ctx.save(); ctx.beginPath(); ctx.setFillStyle(color); ctx.fillRect(x, y, width, height); ctx.restore(); } // 绘制圆 export function drawCircle<T extends ICtx & IFillStyle & IArc & IShadow>(options: T) { const { ctx, color, r, x, y, shadow } = options; ctx.save(); if (shadow) { ctx.setShadow(0, 0, shadow.blur, shadow.color); } ctx.setFillStyle(color); ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.fill(); ctx.restore(); if (shadow) { ctx.setShadow(0, 0, 0, shadow.color); } } // 绘制头像<T extends ICtx & IArc & IImage> export function drawCircleImage(options: any) { const { ctx, imageResource, r, x, y, color, shadow } = options; ctx.save(); if (shadow) { ctx.setShadow(0, 0, shadow.blur, shadow.color); } ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.setFillStyle(color); ctx.fill(); ctx.clip(); ctx.drawImage(imageResource, x - r, y - r, r * 2, r * 2); ctx.restore(); } // 绘制矩形图片 export function drawRectImage<T extends ICtx & IImage>(options: T) { const { ctx, imageResource, width, height, x, y } = options; ctx.save(); ctx.drawImage(imageResource, x, y, width, height); ctx.restore(); } // 绘制字体 export function fillText<T extends ICtx & IFillStyle & IText & IFontSize & ITextAlign & ITextBaseLine & IBold>(options: T) { const { ctx, text, fontSize, color, x, y, align, baseline, isBold } = options; if (isBold) { ctx.font = 'bold 32px PingFang SC'; } else { ctx.font = '32px PingFang SC UltraLight'; } ctx.setTextAlign(align); ctx.setFillStyle(color); ctx.setTextBaseline(baseline || 'middle'); ctx.setFontSize(fontSize); ctx.fillText(text, x, y); } function toLine(str: string, maxChar: number): string[] { const dict: number[] = []; let count = 0; for (let i = 0, len = str.length; i < len; i++) { if (count >= maxChar) { dict.push(i - 1); count = 0; } count += str.charCodeAt(i) < 256 ? 1 : 2; } if (dict.length > 0) { return dict.map((v, i) => { return i === 0 ? str.slice(0, v) : str.slice(dict[i - 1], v); }).concat(str.slice(dict[dict.length - 1])); } else { return [str]; } } // 自动换行并根据配置截取文段后 绘制字体 export function fillTextWidthWrap<T extends ICtx & ITextAlign & IFillStyle & ITextBaseLine & IFontSize & IText & IBold & ITextWidthWrap>(options: T) { let isEllipse: boolean; const { ctx, text, fontSize, color, x, y, align, baseline, isBold, maxWidth, maxLine, lineHeight } = options; if (isBold) { ctx.font = 'bold 32px PingFang SC'; } else { ctx.font = '32px PingFang SC UltraLight'; } ctx.setTextAlign(align); ctx.setFillStyle(color); ctx.setTextBaseline(baseline || 'middle'); ctx.setFontSize(fontSize); // single char length const CHAR = ctx.measureText('一').width / 2; // single line has chars length const CHAR_AMOUNT_INLINE = Math.floor(maxWidth / CHAR); // text in wrap const originTextList = text.split('\n'); const textList = originTextList.slice(0, maxLine); if (originTextList.length > maxLine) { isEllipse = true; } let canvasContentList: string[] = []; textList.forEach((paragraph: string) => { canvasContentList = canvasContentList.concat(toLine(paragraph, CHAR_AMOUNT_INLINE)); }); if (canvasContentList.length > maxLine) { isEllipse = true; } canvasContentList = canvasContentList.slice(0, maxLine); canvasContentList.forEach((val, index) => { const res = isEllipse && canvasContentList.length - 1 === index ? `${val}...` : val; ctx.fillText(res, x, y + index * (fontSize + lineHeight)); }); } // 目前只考虑 加重字段在 文本中,不考虑在头|尾的情况 export function fillTextWidthStrongStyle<T extends ICtx & IFillStyle & IText & IFontSize & ITextAlign & ITextBaseLine & IBold & IStrongText>(options: T) { const { ctx, text, fontSize, color, x, y, align, baseline, isBold, strongText } = options; if (isBold) { ctx.font = 'bold 32px PingFang SC'; } else { ctx.font = '32px PingFang SC UltraLight'; } if (strongText && ~text.indexOf(strongText.text)) { ctx.setFontSize(strongText.fontSize); const strongChar = ctx.measureText('一').width / 2; const strongW = strLen(strongText.text) * strongChar; const simpeTextList = text.split(strongText.text); ctx.setFontSize(fontSize); const leftChar = ctx.measureText(simpeTextList[0]).width / 2; const leftstrongW = strLen(simpeTextList[0]) * leftChar; fillText(Object.assign({}, options, { text: simpeTextList[0], align })); fillText(Object.assign({}, options, { text: simpeTextList[1], x: +leftstrongW + strongW - 8, align })); fillText(Object.assign({}, options, { ...options.strongText, x: +leftstrongW - 25, align })); } } // 圆角矩形 export function drawRoundedRect<T extends ICtx & IArc & IRect & IFillStyle & IShadow | ICtx & IArc & IRect & IFillStyle>(options: T) { // @ts-ignore const { ctx, x, y, r, width, height, color, shadow } = options; ctx.save(); if (shadow) { ctx.setShadow(0, 0, shadow.blur, shadow.color); } ctx.beginPath(); ctx.moveTo(x, y + r); ctx.lineTo(x, y + height - r); ctx.quadraticCurveTo(x, y + height, x + r, y + height); ctx.lineTo(x + width - r, y + height); ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - r); ctx.lineTo(x + width, y + r); ctx.quadraticCurveTo(x + width, y, x + width - r, y); ctx.lineTo(x + r, y); ctx.quadraticCurveTo(x, y, x, y + r); ctx.setFillStyle(color); ctx.closePath(); ctx.fill(); ctx.restore(); } // 圆角矩形Path export function drawRoundedRectPath<T extends ICtx & IArc & IRect & IHalfMode>(options: T) { const { ctx, x, y, r, width, height, isHalfMode } = options; ctx.beginPath(); // 仅圆角左侧 if (isHalfMode) { ctx.moveTo(x + width, y + height); } else { // 从右下角顺时针绘制,弧度从0到1/2PI ctx.arc(x + width - r, y + height - r, r, 0, Math.PI / 2); } // 矩形下边线 ctx.lineTo(x + r, y + height); // 左下角圆弧,弧度从1/2PI到PI ctx.arc(x + r, y + height - r, r, Math.PI / 2, Math.PI); // 矩形左边线 ctx.lineTo(x, y + r); // 左上角圆弧,弧度从PI到3/2PI ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 3 / 2); if (isHalfMode) { // 上边线 ctx.lineTo(x + width, y); // 右上角 ctx.lineTo(x + width, y + r); } else { // 上边线 ctx.lineTo(x + width - r, y); // 右上角圆弧 ctx.arc(x + width - r, y + r, r, Math.PI * 3 / 2, Math.PI * 2); } // 右边线 ctx.lineTo(x + width, y + height - r); ctx.clip(); ctx.closePath(); } // 圆点 export function drawdottedLine<T extends ICtx & IArc & IRect & IDottedLine & IFillStyle>(options: T) { const { ctx, x, y, r, width, margin, color } = options; for (let i = 0; i < Math.floor(width / ((r + margin) * 2)); i++) { drawCircle({ ctx, color: '#FFE6E1', r, x: x + ((r + margin) * 2) * i, y, shadow: { blur: 0, color: '#FFE6E1' } }); } }