123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import { countTextLength } from '../utils/util'
- export default class DrawText {
- constructor(params) {
- const { Context, commonUtilMethods, commonDrawMethods } = params
- this.Context = Context
- this.commonUtilMethods = commonUtilMethods
- this.commonDrawMethods = commonDrawMethods
- }
- /**
- * 获取绘制参数
- * @param { Object } params 参数
- * @param { Boolean } conversion 是否需要转换单位
- */
- getDrawParams(params = {}, conversion = true) {
- const globalDataParams = this.commonUtilMethods.getGlobalDataDrawParams(params)
- // 绘制文字的参数
- const {
- text = '', textIndent = 0, lastWidth = 0, font = {},
- textAlign = 'none', baseline = 'top', line = {},
- highlightText = [], textRect = { show: false, isFill: true, lineWidth: 1 }
- } = params
- const textParams = {
- ...globalDataParams,
- text: String(text) || '',
- textIndent,
- lastWidth,
- font: conversion ? this.commonUtilMethods.conversionUnit(this.getFontStyle(font)) : this.getFontStyle(font, conversion),
- textAlign,
- baseline,
- line: this.getTextLine(line, conversion),
- highlightText,
- textRect,
- }
- return conversion ? this.commonUtilMethods.conversionUnit(textParams) : textParams
- }
- /**
- * 绘制文字
- * @param { Object } params 文字参数
- * @param { Boolean } conversion 是否需要转换单位
- */
- draw(params = {}, conversion = true) {
- const { Context, commonUtilMethods, commonDrawMethods } = this
- const { canvasWidth, is2d } = commonUtilMethods
- let {
- x, y, w, h, text, textIndent,
- lastWidth, font, color, alpha,
- isFill, line, windowAlign, textAlign, baseline, highlightText, textRect, offsetRight
- } = this.getDrawParams(params, conversion)
- Context.save()
- Context.beginPath()
- commonDrawMethods.setAlpha(alpha)
- Context.font = font.style
- if (!is2d) {
- // #ifdef MP-TOUTIAO
- // 不知道为啥现在字节跳动一定用这个方法来设置文字大小了. 之前还不用...
- Context.setFontSize(font.fontSize)
- // #endif
- Context.setTextBaseline(baseline)
- }else{
- Context.textBaseline = baseline
- }
- if (typeof text !== 'string') {
- text += ''
- }
- // console.log(this.formatTextData(text, color, highlightText))
- const textArr = params.textArr || commonDrawMethods.computedFontTextLineHeight({
- x, y, w, text, textIndent, lastWidth, font, line, textAlign, windowAlign, defaultColor: color, offsetRight, highlightText
- })
- // console.log(textArr)
- if (textRect.show) {
- // 水平的 垂直的
- const { vorizontal, vertical, ...textReactParmas } = commonUtilMethods.conversionUnit(textRect)
- // console.log({
- // vorizontal,
- // vertical,
- // })
- const firstText = textArr[0]
- // console.log(firstText)
- let tw = w === canvasWidth ? commonUtilMethods.conversionUnit(params).tw ?? firstText.w : w
- let tx = firstText.x - vorizontal
- let ty = firstText.y - vertical
- let ey = textArr[textArr.length - 1].y + font.fontSize
- let th = ey - firstText.y
- th += vertical * 2
- // #ifdef MP-WEIXIN || MP-TOUTIAO
- if (uni.getSystemInfoSync().platform === 'android') {
- ty += font.fontSize / 3
- th -= font.fontSize / 3
- }
- // #endif
- tw += (vorizontal * 2)
- commonDrawMethods.drawParams.drawRect.draw({
- x: tx,
- y: ty,
- w: tw,
- h: th,
- ...textReactParmas
- }, false)
- }
- Context.font = font.style
- let currentFontSize = 0
- if (font.style.includes(8)) {
- currentFontSize = 8
- } else if (font.style.includes(16)) {
- currentFontSize = 16
- } else {
- currentFontSize = font.fontSize
- }
- textArr.forEach(item => {
- let { text, x, y, tx, ty, tw, fontColor, fontSize, font: customFont } = item
- if (currentFontSize !== fontSize) {
- const { fontStyle, fontVariant, fontWeight, fontFamily } = font
- const { fontStyle: customFontStyle, fontVariant: customFontVariant, fontWeight: customFontWeight, fontFamily: customfontFamily } = customFont
- Context.font = `${customFontStyle || fontStyle} ${customFontVariant || fontVariant} ${customFontWeight || fontWeight} ${fontSize || currentFontSize}px ${customfontFamily || fontFamily}`
- currentFontSize = fontSize
- }
- if (isFill) {
- commonDrawMethods.setFillStyle(fontColor)
- Context.fillText(text, x, y)
- } else {
- commonDrawMethods.setStrokeStyle(fontColor)
- Context.strokeText(text, x, y)
- }
- if (line.lineStyle !== 'none') {
- if (isFill) {
- commonDrawMethods.setFillStyle(color)
- } else {
- commonDrawMethods.setStrokeStyle(color)
- }
- commonDrawMethods.drawParams.drawLine.draw({
- x: tx,
- y: ty,
- w: tw,
- color,
- lineType: line.lineType,
- lineWidth: line.lineWidth
- }, false)
- }
- })
- Context.restore()
- Context.font = this.getFontStyle().style
- commonDrawMethods.setAlpha(1)
- }
- /**
- * 获取字体样式
- * @param { Object } font 字体样式
- * @param { Boolean } conversion 是否装换单位
- * @returns
- */
- getFontStyle(fontStyle = {}, conversion = true) {
- const { size, family, style, variant, weight } = {...this.commonUtilMethods.fontStyle, ...fontStyle}
- return {
- fontSize: size,
- fontSizeBefore: size,
- fontFamily: family,
- fontStyle: style,
- fontVariant: variant,
- fontWeight: weight,
- style: `${style || 'normal'} ${variant || 'normal'} ${weight || 'normal'} ${conversion ? this.commonUtilMethods.getConvertedValue(size) : size}px ${family || 'sans-serif'}`
- }
- }
- /**
- * 获取文字line样式
- * @param { Object } line 行高
- * @param { Object } conversion 是否转换单位默认true
- */
- getTextLine(line = {}, conversion = true) {
- const { num = -1, height = 0, style = 'none', type = 'solid', width = 1 } = line
- return {
- lineNum: num,
- lineHeight: conversion ? this.commonUtilMethods.getConvertedValue(height) : height,
- lineStyle: style,
- lineType: type,
- lineWidth: width
- }
- }
- /**
- * 格式化文字
- * @param { String } formatText 文字内容
- * @param { String } color 文字默认颜色
- * @param { Object } defaultFont 文字
- * @param { Array } highlightText 高亮文字
- * @returns
- */
- formatTextData(formatText, color = 'black', defaultFont, highlightText = []) {
- const isBr = formatText.includes('\n')
- const isHightText = highlightText.length !== 0
- if (isBr) {
- const formatTexts = formatText.split('\n')
- if (isHightText) {
- return formatTexts.map(text => this.formatHighlightText(text, color, defaultFont, highlightText)).flat()
- }
- return formatTexts.map(text => ({ text, color, font: defaultFont }))
- }
- if (isHightText) {
- return this.formatHighlightText(formatText, color, defaultFont, highlightText)
- }
- return [{ text: formatText, color, font: defaultFont }]
- }
- /**
- * 格式化高亮文字
- * @param { String } formatText 文字
- * @param { String } defaultColor 默认颜色
- * @param { Object } defaultFont 默认字体
- * @param { Array } highlightText 高亮文字
- * @returns
- */
- formatHighlightText(formatText, defaultColor = 'black', defaultFont, highlightText){
- const row = []
- const texts = highlightText.map(item => {
- item.i = 0
- return item
- })
- let flag = true
- const rulesData = []
- while (flag) {
- texts.forEach((item) => {
- const { text, color = defaultColor, i, fontSize, siblingsCenter = 'bottom', siblingsNum = 0, ...customFont } = item
- const index = formatText.indexOf(text, i)
- if (formatText.includes(text) && index !== -1) {
- item.i = index + 1 + text.length
- rulesData.push(({
- index,
- length: text.length,
- color,
- fontSize: fontSize ?? defaultFont.fontSize,
- font: Object.keys(customFont).length !== 0 ? this.getFontStyle(customFont, false) : defaultFont,
- siblingsCenter,
- siblingsNum
- }))
- } else {
- flag = false
- }
- })
- }
- const rulesIndex = rulesData.map(item => item.index)
- let text = ''
- for (let i = 0; i < formatText.length; i++) {
- if (rulesIndex.includes(i)) {
- const { length, color, fontSize, font, siblingsCenter, siblingsNum } = rulesData.find(item => item.index === i)
- if (text) {
- row.push({
- text,
- color: defaultColor,
- fontSize: defaultFont.fontSize,
- font: defaultFont,
-
- })
- text = ''
- }
- row.push({
- text: formatText.slice(i, i + length),
- color,
- fontSize,
- font,
- siblingsCenter,
- siblingsNum
- })
- i += length - 1
- continue
- }
- text += formatText[i]
- if (i === formatText.length - 1) {
- row.push({
- text,
- color: defaultColor,
- fontSize: defaultFont.fontSize,
- font: defaultFont
- })
- }
- }
- return row
- }
- }
|