fix: strikeout style rendering position #498

pr675
Hufe921 2 years ago
parent 9ad991a393
commit 46e153d588

@ -80,7 +80,10 @@ import { I18n } from '../i18n/I18n'
import { ImageObserver } from '../observer/ImageObserver' import { ImageObserver } from '../observer/ImageObserver'
import { Zone } from '../zone/Zone' import { Zone } from '../zone/Zone'
import { Footer } from './frame/Footer' import { Footer } from './frame/Footer'
import { INLINE_ELEMENT_TYPE } from '../../dataset/constant/Element' import {
INLINE_ELEMENT_TYPE,
TEXTLIKE_ELEMENT_TYPE
} from '../../dataset/constant/Element'
import { ListParticle } from './particle/ListParticle' import { ListParticle } from './particle/ListParticle'
import { Placeholder } from './frame/Placeholder' import { Placeholder } from './frame/Placeholder'
import { EventBus } from '../event/eventbus/EventBus' import { EventBus } from '../event/eventbus/EventBus'
@ -1079,7 +1082,7 @@ export class Draw {
ctx.direction = 'ltr' ctx.direction = 'ltr'
} }
private _getFont(el: IElement, scale = 1): string { public getElementFont(el: IElement, scale = 1): string {
const { defaultSize, defaultFont } = this.options const { defaultSize, defaultFont } = this.options
const font = el.font || defaultFont const font = el.font || defaultFont
const size = el.actualSize || el.size || defaultSize const size = el.actualSize || el.size || defaultSize
@ -1088,6 +1091,10 @@ export class Draw {
}px ${font}` }px ${font}`
} }
public getElementSize(el: IElement) {
return el.actualSize || el.size || this.options.defaultSize
}
public computeRowList(innerWidth: number, elementList: IElement[]) { public computeRowList(innerWidth: number, elementList: IElement[]) {
const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } = const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } =
this.options this.options
@ -1414,7 +1421,7 @@ export class Draw {
element.actualSize = Math.ceil(size * 0.6) element.actualSize = Math.ceil(size * 0.6)
} }
metrics.height = (element.actualSize || size) * scale metrics.height = (element.actualSize || size) * scale
ctx.font = this._getFont(element) ctx.font = this.getElementFont(element)
const fontMetrics = this.textParticle.measureText(ctx, element) const fontMetrics = this.textParticle.measureText(ctx, element)
metrics.width = fontMetrics.width * scale metrics.width = fontMetrics.width * scale
if (element.letterSpacing) { if (element.letterSpacing) {
@ -1445,7 +1452,7 @@ export class Draw {
rowMargin rowMargin
const rowElement: IRowElement = Object.assign(element, { const rowElement: IRowElement = Object.assign(element, {
metrics, metrics,
style: this._getFont(element, scale) style: this.getElementFont(element, scale)
}) })
// 暂时只考虑非换行场景:控件开始时统计宽度,结束时消费宽度及还原 // 暂时只考虑非换行场景:控件开始时统计宽度,结束时消费宽度及还原
if (rowElement.control?.minWidth) { if (rowElement.control?.minWidth) {
@ -1831,12 +1838,34 @@ export class Draw {
} }
// 删除线记录 // 删除线记录
if (element.strikeout) { if (element.strikeout) {
this.strikeout.recordFillInfo( // 仅文本类元素支持删除线
ctx, if (!element.type || TEXTLIKE_ELEMENT_TYPE.includes(element.type)) {
x, // 字体大小不同时需立即绘制
y + curRow.height / 2, if (
metrics.width preElement &&
) this.getElementSize(preElement) !== this.getElementSize(element)
) {
this.strikeout.render(ctx)
}
// 基线文字测量信息
const standardMetrics = this.textParticle.measureBasisWord(
ctx,
this.getElementFont(element)
)
// 文字渲染位置 + 基线文字下偏移量 - 一半文字高度
let adjustY =
y +
offsetY +
standardMetrics.actualBoundingBoxDescent * scale -
metrics.height / 2
// 上下标位置调整
if (element.type === ElementType.SUBSCRIPT) {
adjustY += this.subscriptParticle.getOffsetY(element)
} else if (element.type === ElementType.SUPERSCRIPT) {
adjustY += this.superscriptParticle.getOffsetY(element)
}
this.strikeout.recordFillInfo(ctx, x, adjustY, metrics.width)
}
} else if (preElement?.strikeout) { } else if (preElement?.strikeout) {
this.strikeout.render(ctx) this.strikeout.render(ctx)
} }

@ -1,5 +1,8 @@
import { ElementType, IEditorOption, IElement } from '../../..' import { ElementType, IEditorOption, IElement } from '../../..'
import { PUNCTUATION_LIST } from '../../../dataset/constant/Common' import {
PUNCTUATION_LIST,
METRICS_BASIS_TEXT
} from '../../../dataset/constant/Common'
import { DeepRequired } from '../../../interface/Common' import { DeepRequired } from '../../../interface/Common'
import { IRowElement } from '../../../interface/Row' import { IRowElement } from '../../../interface/Row'
import { ITextMetrics } from '../../../interface/Text' import { ITextMetrics } from '../../../interface/Text'
@ -33,6 +36,19 @@ export class TextParticle {
this.cacheMeasureText = new Map() this.cacheMeasureText = new Map()
} }
public measureBasisWord(
ctx: CanvasRenderingContext2D,
font: string
): ITextMetrics {
ctx.save()
ctx.font = font
const textMetrics = this.measureText(ctx, {
value: METRICS_BASIS_TEXT
})
ctx.restore()
return textMetrics
}
public measureWord( public measureWord(
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
elementList: IElement[], elementList: IElement[],

@ -12,9 +12,10 @@ export class Strikeout extends AbstractRichText {
public render(ctx: CanvasRenderingContext2D) { public render(ctx: CanvasRenderingContext2D) {
if (!this.fillRect.width) return if (!this.fillRect.width) return
const { strikeoutColor } = this.options const { scale, strikeoutColor } = this.options
const { x, y, width } = this.fillRect const { x, y, width } = this.fillRect
ctx.save() ctx.save()
ctx.lineWidth = scale
ctx.strokeStyle = strikeoutColor ctx.strokeStyle = strikeoutColor
const adjustY = y + 0.5 // 从1处渲染避免线宽度等于3 const adjustY = y + 0.5 // 从1处渲染避免线宽度等于3
ctx.beginPath() ctx.beginPath()

@ -40,3 +40,5 @@ export const LETTER_CLASS = {
SWEDISH: 'A-Za-zÅåÄäÖö', SWEDISH: 'A-Za-zÅåÄäÖö',
GREEK: 'ΑαΒβΓγΔδΕεΖζΗηΘθΙιΚκΛλΜμΝνΞξΟοΠπΡρΣσςΤτΥυΦφΧχΨψΩω' GREEK: 'ΑαΒβΓγΔδΕεΖζΗηΘθΙιΚκΛλΜμΝνΞξΟοΠπΡρΣσςΤτΥυΦφΧχΨψΩω'
} }
export const METRICS_BASIS_TEXT = '日'

@ -754,6 +754,9 @@ export function convertElementToDom(
if (element.underline) { if (element.underline) {
dom.style.textDecoration = 'underline' dom.style.textDecoration = 'underline'
} }
if (element.strikeout) {
dom.style.textDecoration += ' line-through'
}
dom.innerText = element.value.replace(new RegExp(`${ZERO}`, 'g'), '\n') dom.innerText = element.value.replace(new RegExp(`${ZERO}`, 'g'), '\n')
return dom return dom
} }
@ -981,9 +984,13 @@ export function convertTextNodeToElement(
element.highlight = style.backgroundColor element.highlight = style.backgroundColor
} }
// 下划线 // 下划线
if (style.textDecorationLine === 'underline') { if (style.textDecorationLine.includes('underline')) {
element.underline = true element.underline = true
} }
// 删除线
if (style.textDecorationLine.includes('line-through')) {
element.strikeout = true
}
return element return element
} }

Loading…
Cancel
Save