fix: strikeout style rendering position #498
This commit is contained in:
@@ -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(
|
// 仅文本类元素支持删除线
|
||||||
|
if (!element.type || TEXTLIKE_ELEMENT_TYPE.includes(element.type)) {
|
||||||
|
// 字体大小不同时需立即绘制
|
||||||
|
if (
|
||||||
|
preElement &&
|
||||||
|
this.getElementSize(preElement) !== this.getElementSize(element)
|
||||||
|
) {
|
||||||
|
this.strikeout.render(ctx)
|
||||||
|
}
|
||||||
|
// 基线文字测量信息
|
||||||
|
const standardMetrics = this.textParticle.measureBasisWord(
|
||||||
ctx,
|
ctx,
|
||||||
x,
|
this.getElementFont(element)
|
||||||
y + curRow.height / 2,
|
|
||||||
metrics.width
|
|
||||||
)
|
)
|
||||||
|
// 文字渲染位置 + 基线文字下偏移量 - 一半文字高度
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user