feat: add word break option #212

pr675
Hufe921 3 years ago
parent 0c4d53ccc9
commit d471165430

@ -51,6 +51,7 @@ interface IEditorOption {
paperDirection?: PaperDirection; // 纸张方向:纵向、横向
inactiveAlpha?: number; // 正文内容失焦时透明度。默认值0.6
historyMaxRecordCount: number; // 历史撤销重做最大记录次数。默认100次
wordBreak: WordBreak; // 单词与标点断行BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认BREAK_WORD
watermark?: IWatermark; // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
control?: IControlOption; // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string;}
checkbox?: ICheckboxOption; // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; fontStyle?: string;}

@ -35,7 +35,7 @@ import { SubscriptParticle } from './particle/Subscript'
import { SeparatorParticle } from './particle/Separator'
import { PageBreakParticle } from './particle/PageBreak'
import { Watermark } from './frame/Watermark'
import { EditorComponent, EditorMode, EditorZone, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { EditorComponent, EditorMode, EditorZone, PageMode, PaperDirection, WordBreak } from '../../dataset/enum/Editor'
import { Control } from './control/Control'
import { zipElementList } from '../../utils/element'
import { CheckboxParticle } from './particle/CheckboxParticle'
@ -55,6 +55,7 @@ import { Footer } from './frame/Footer'
import { INLINE_ELEMENT_TYPE } from '../../dataset/constant/Element'
import { ListParticle } from './particle/ListParticle'
import { Placeholder } from './frame/Placeholder'
import { WORD_LIKE_REG } from '../../dataset/constant/Regular'
export class Draw {
@ -1107,9 +1108,20 @@ export class Draw {
})
// 超过限定宽度
const preElement = elementList[i - 1]
const nextElement = elementList[i + 1]
// 累计行宽 + 当前元素宽度 + 后面标点符号宽度
const curRowWidth = curRow.width + metrics.width + this.textParticle.measurePunctuationWidth(ctx, nextElement)
let nextElement = elementList[i + 1]
// 累计行宽 + 当前元素宽度 + 排版宽度(英文单词整体宽度 + 后面标点符号宽度)
let curRowWidth = curRow.width + metrics.width
if (this.options.wordBreak === WordBreak.BREAK_WORD) {
// 英文单词
const word = `${preElement?.value || ''}${element.value}`
if (WORD_LIKE_REG.test(word)) {
const { width, endElement } = this.textParticle.measureWord(ctx, elementList, i)
curRowWidth += width
nextElement = endElement
}
// 标点符号
curRowWidth += this.textParticle.measurePunctuationWidth(ctx, nextElement)
}
// 列表信息
if (element.listId) {
if (element.listId !== listId) {

@ -1,8 +1,14 @@
import { IElement } from '../../..'
import { PUNCTUATION_LIST } from '../../../dataset/constant/Common'
import { LETTER_REG } from '../../../dataset/constant/Regular'
import { IRowElement } from '../../../interface/Row'
import { Draw } from '../Draw'
export interface IMeasureWordResult {
width: number;
endElement: IElement;
}
export class TextParticle {
private ctx: CanvasRenderingContext2D
@ -22,6 +28,25 @@ export class TextParticle {
this.cacheMeasureText = new Map()
}
public measureWord(ctx: CanvasRenderingContext2D, elementList: IElement[], curIndex: number): IMeasureWordResult {
let width = 0
let endElement: IElement = elementList[curIndex]
let i = curIndex
while (i < elementList.length) {
const element = elementList[i]
if (!LETTER_REG.test(element.value)) {
endElement = element
break
}
width += this.measureText(ctx, element).width
i++
}
return {
width,
endElement
}
}
public measurePunctuationWidth(ctx: CanvasRenderingContext2D, element: IElement): number {
if (!element || !PUNCTUATION_LIST.includes(element.value)) return 0
return this.measureText(ctx, element).width

@ -2,3 +2,4 @@ export const NUMBER_REG = /[0-9]/
export const LETTER_REG = /[a-zA-Z]/
export const NUMBER_LIKE_REG = /[0-9.]/
export const CHINESE_REG = /[\u4e00-\u9fa5]/
export const WORD_LIKE_REG = /[^a-zA-Z][a-zA-Z]/

@ -34,3 +34,8 @@ export enum PaperDirection {
VERTICAL = 'vertical',
HORIZONTAL = 'horizontal'
}
export enum WordBreak {
BREAK_ALL = 'break-all',
BREAK_WORD = 'break-word'
}

@ -11,7 +11,7 @@ import { formatElementList } from './utils/element'
import { Register } from './core/register/Register'
import { ContextMenu } from './core/contextmenu/ContextMenu'
import { IContextMenuContext, IRegisterContextMenu } from './interface/contextmenu/ContextMenu'
import { EditorComponent, EditorZone, EditorMode, PageMode, PaperDirection } from './dataset/enum/Editor'
import { EditorComponent, EditorZone, EditorMode, PageMode, PaperDirection, WordBreak } from './dataset/enum/Editor'
import { EDITOR_COMPONENT } from './dataset/constant/Editor'
import { IHeader } from './interface/Header'
import { IWatermark } from './interface/Watermark'
@ -129,6 +129,7 @@ export default class Editor {
paperDirection: PaperDirection.VERTICAL,
inactiveAlpha: 0.6,
historyMaxRecordCount: 100,
wordBreak: WordBreak.BREAK_WORD,
...options,
header: headerOptions,
footer: footerOptions,

@ -1,5 +1,5 @@
import { IElement } from '..'
import { EditorMode, PageMode, PaperDirection } from '../dataset/enum/Editor'
import { EditorMode, PageMode, PaperDirection, WordBreak } from '../dataset/enum/Editor'
import { ICheckboxOption } from './Checkbox'
import { IControlOption } from './Control'
import { ICursorOption } from './Cursor'
@ -52,6 +52,7 @@ export interface IEditorOption {
paperDirection?: PaperDirection;
inactiveAlpha?: number;
historyMaxRecordCount?: number;
wordBreak?: WordBreak;
header?: IHeader;
footer?: IFooter;
pageNumber?: IPageNumber;

Loading…
Cancel
Save