feat:optimize rich text render performance
This commit is contained in:
@@ -767,6 +767,13 @@ export class Draw {
|
||||
return rowList
|
||||
}
|
||||
|
||||
private _drawRichText(ctx: CanvasRenderingContext2D) {
|
||||
this.underline.render(ctx)
|
||||
this.strikeout.render(ctx)
|
||||
this.highlight.render(ctx)
|
||||
this.textParticle.complete()
|
||||
}
|
||||
|
||||
private _drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload): IDrawRowResult {
|
||||
const { positionList, rowList, pageNo, startX, startY, startIndex, innerWidth } = payload
|
||||
const { scale, tdPadding } = this.options
|
||||
@@ -823,10 +830,10 @@ export class Draw {
|
||||
positionList.push(positionItem)
|
||||
// 元素绘制
|
||||
if (element.type === ElementType.IMAGE) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.imageParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.LATEX) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.laTexParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.TABLE) {
|
||||
if (isCrossRowCol) {
|
||||
@@ -836,16 +843,16 @@ export class Draw {
|
||||
}
|
||||
this.tableParticle.render(ctx, element, x, y)
|
||||
} else if (element.type === ElementType.HYPERLINK) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.hyperlinkParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.DATE) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.dateParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.SUPERSCRIPT) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.superscriptParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.SUBSCRIPT) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.subscriptParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.SEPARATOR) {
|
||||
this.separatorParticle.render(ctx, element, x, y)
|
||||
@@ -857,24 +864,24 @@ export class Draw {
|
||||
element.type === ElementType.CHECKBOX ||
|
||||
element.controlComponent === ControlComponent.CHECKBOX
|
||||
) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
this.checkboxParticle.render(ctx, element, x, y + offsetY)
|
||||
} else if (element.type === ElementType.TAB) {
|
||||
this.textParticle.complete()
|
||||
this._drawRichText(ctx)
|
||||
} else {
|
||||
this.textParticle.record(ctx, element, x, y + offsetY)
|
||||
}
|
||||
// 下划线绘制
|
||||
// 下划线记录
|
||||
if (element.underline) {
|
||||
this.underline.render(ctx, element.color!, x, y + curRow.height, metrics.width)
|
||||
this.underline.recordFillInfo(ctx, x, y + curRow.height, metrics.width, 0, element.color)
|
||||
}
|
||||
// 删除线绘制
|
||||
// 删除线记录
|
||||
if (element.strikeout) {
|
||||
this.strikeout.render(ctx, x, y + curRow.height / 2, metrics.width)
|
||||
this.strikeout.recordFillInfo(ctx, x, y + curRow.height / 2, metrics.width)
|
||||
}
|
||||
// 元素高亮
|
||||
// 元素高亮记录
|
||||
if (element.highlight) {
|
||||
this.highlight.render(ctx, element.highlight, x, y, metrics.width, curRow.height)
|
||||
this.highlight.recordFillInfo(ctx, x, y, metrics.width, curRow.height, element.highlight)
|
||||
}
|
||||
// 选区记录
|
||||
const { startIndex, endIndex } = this.range.getRange()
|
||||
@@ -937,7 +944,8 @@ export class Draw {
|
||||
y = tablePreY
|
||||
}
|
||||
}
|
||||
this.textParticle.complete()
|
||||
// 绘制富文本及文字
|
||||
this._drawRichText(ctx)
|
||||
// 绘制选区
|
||||
if (rangeRecord.width && rangeRecord.height) {
|
||||
const { x, y, width, height } = rangeRecord
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { IElementFillRect } from '../../../interface/Element'
|
||||
|
||||
export abstract class AbstractRichText {
|
||||
public fillRect: IElementFillRect
|
||||
public fillColor?: string
|
||||
|
||||
constructor() {
|
||||
this.fillRect = this.clearFillInfo()
|
||||
}
|
||||
|
||||
public clearFillInfo() {
|
||||
this.fillColor = undefined
|
||||
return this.fillRect = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
}
|
||||
|
||||
public recordFillInfo(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height?: number, color?: string) {
|
||||
const isFirstRecord = !this.fillRect.width
|
||||
if (!isFirstRecord && this.fillColor && this.fillColor !== color) {
|
||||
this.render(ctx)
|
||||
this.clearFillInfo()
|
||||
return
|
||||
}
|
||||
if (isFirstRecord) {
|
||||
this.fillRect.x = x
|
||||
this.fillRect.y = y
|
||||
}
|
||||
if (height && this.fillRect.height < height) {
|
||||
this.fillRect.height = height
|
||||
}
|
||||
this.fillRect.width += width
|
||||
this.fillColor = color
|
||||
}
|
||||
|
||||
public abstract render(ctx: CanvasRenderingContext2D): void
|
||||
|
||||
}
|
||||
@@ -1,21 +1,26 @@
|
||||
import { AbstractRichText } from './AbstractRichText'
|
||||
import { IEditorOption } from '../../../interface/Editor'
|
||||
import { Draw } from '../Draw'
|
||||
|
||||
export class Highlight {
|
||||
export class Highlight extends AbstractRichText {
|
||||
|
||||
private options: Required<IEditorOption>
|
||||
|
||||
constructor(draw: Draw) {
|
||||
super()
|
||||
this.options = draw.getOptions()
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, color: string, x: number, y: number, width: number, height: number) {
|
||||
public render(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.fillRect.width) return
|
||||
const { highlightAlpha } = this.options
|
||||
const { x, y, width, height } = this.fillRect
|
||||
ctx.save()
|
||||
ctx.globalAlpha = highlightAlpha
|
||||
ctx.fillStyle = color
|
||||
ctx.fillStyle = this.fillColor!
|
||||
ctx.fillRect(x, y, width, height)
|
||||
ctx.restore()
|
||||
this.clearFillInfo()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
import { AbstractRichText } from './AbstractRichText'
|
||||
import { IEditorOption } from '../../../interface/Editor'
|
||||
import { Draw } from '../Draw'
|
||||
|
||||
export class Strikeout {
|
||||
export class Strikeout extends AbstractRichText {
|
||||
|
||||
private options: Required<IEditorOption>
|
||||
|
||||
constructor(draw: Draw) {
|
||||
super()
|
||||
this.options = draw.getOptions()
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, x: number, y: number, width: number) {
|
||||
public render(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.fillRect.width) return
|
||||
const { strikeoutColor } = this.options
|
||||
const { x, y, width } = this.fillRect
|
||||
ctx.save()
|
||||
ctx.strokeStyle = strikeoutColor
|
||||
const adjustY = y + 0.5 // 从1处渲染,避免线宽度等于3
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x, y)
|
||||
ctx.lineTo(x + width, y)
|
||||
ctx.moveTo(x, adjustY)
|
||||
ctx.lineTo(x + width, adjustY)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
this.clearFillInfo()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
import { AbstractRichText } from './AbstractRichText'
|
||||
import { IEditorOption } from '../../../interface/Editor'
|
||||
import { Draw } from '../Draw'
|
||||
|
||||
export class Underline {
|
||||
export class Underline extends AbstractRichText {
|
||||
|
||||
private options: Required<IEditorOption>
|
||||
|
||||
constructor(draw: Draw) {
|
||||
super()
|
||||
this.options = draw.getOptions()
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, color: string, x: number, y: number, width: number) {
|
||||
public render(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.fillRect.width) return
|
||||
const { underlineColor } = this.options
|
||||
const { x, y, width } = this.fillRect
|
||||
ctx.save()
|
||||
ctx.strokeStyle = color || underlineColor
|
||||
ctx.strokeStyle = this.fillColor || underlineColor
|
||||
const adjustY = y + 0.5 // 从1处渲染,避免线宽度等于3
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x, y)
|
||||
ctx.lineTo(x + width, y)
|
||||
ctx.moveTo(x, adjustY)
|
||||
ctx.lineTo(x + width, adjustY)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
this.clearFillInfo()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user