feat: add word break option #212
This commit is contained in:
@@ -51,6 +51,7 @@ interface IEditorOption {
|
|||||||
paperDirection?: PaperDirection; // 纸张方向:纵向、横向
|
paperDirection?: PaperDirection; // 纸张方向:纵向、横向
|
||||||
inactiveAlpha?: number; // 正文内容失焦时透明度。默认值:0.6
|
inactiveAlpha?: number; // 正文内容失焦时透明度。默认值:0.6
|
||||||
historyMaxRecordCount: number; // 历史(撤销重做)最大记录次数。默认:100次
|
historyMaxRecordCount: number; // 历史(撤销重做)最大记录次数。默认:100次
|
||||||
|
wordBreak: WordBreak; // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
||||||
watermark?: IWatermark; // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
watermark?: IWatermark; // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
||||||
control?: IControlOption; // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?: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;}
|
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 { SeparatorParticle } from './particle/Separator'
|
||||||
import { PageBreakParticle } from './particle/PageBreak'
|
import { PageBreakParticle } from './particle/PageBreak'
|
||||||
import { Watermark } from './frame/Watermark'
|
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 { Control } from './control/Control'
|
||||||
import { zipElementList } from '../../utils/element'
|
import { zipElementList } from '../../utils/element'
|
||||||
import { CheckboxParticle } from './particle/CheckboxParticle'
|
import { CheckboxParticle } from './particle/CheckboxParticle'
|
||||||
@@ -55,6 +55,7 @@ import { Footer } from './frame/Footer'
|
|||||||
import { INLINE_ELEMENT_TYPE } from '../../dataset/constant/Element'
|
import { INLINE_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 { WORD_LIKE_REG } from '../../dataset/constant/Regular'
|
||||||
|
|
||||||
export class Draw {
|
export class Draw {
|
||||||
|
|
||||||
@@ -1107,9 +1108,20 @@ export class Draw {
|
|||||||
})
|
})
|
||||||
// 超过限定宽度
|
// 超过限定宽度
|
||||||
const preElement = elementList[i - 1]
|
const preElement = elementList[i - 1]
|
||||||
const nextElement = elementList[i + 1]
|
let nextElement = elementList[i + 1]
|
||||||
// 累计行宽 + 当前元素宽度 + 后面标点符号宽度
|
// 累计行宽 + 当前元素宽度 + 排版宽度(英文单词整体宽度 + 后面标点符号宽度)
|
||||||
const curRowWidth = curRow.width + metrics.width + this.textParticle.measurePunctuationWidth(ctx, nextElement)
|
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) {
|
||||||
if (element.listId !== listId) {
|
if (element.listId !== listId) {
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { IElement } from '../../..'
|
import { IElement } from '../../..'
|
||||||
import { PUNCTUATION_LIST } from '../../../dataset/constant/Common'
|
import { PUNCTUATION_LIST } from '../../../dataset/constant/Common'
|
||||||
|
import { LETTER_REG } from '../../../dataset/constant/Regular'
|
||||||
import { IRowElement } from '../../../interface/Row'
|
import { IRowElement } from '../../../interface/Row'
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
|
|
||||||
|
export interface IMeasureWordResult {
|
||||||
|
width: number;
|
||||||
|
endElement: IElement;
|
||||||
|
}
|
||||||
|
|
||||||
export class TextParticle {
|
export class TextParticle {
|
||||||
|
|
||||||
private ctx: CanvasRenderingContext2D
|
private ctx: CanvasRenderingContext2D
|
||||||
@@ -22,6 +28,25 @@ export class TextParticle {
|
|||||||
this.cacheMeasureText = new Map()
|
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 {
|
public measurePunctuationWidth(ctx: CanvasRenderingContext2D, element: IElement): number {
|
||||||
if (!element || !PUNCTUATION_LIST.includes(element.value)) return 0
|
if (!element || !PUNCTUATION_LIST.includes(element.value)) return 0
|
||||||
return this.measureText(ctx, element).width
|
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 LETTER_REG = /[a-zA-Z]/
|
||||||
export const NUMBER_LIKE_REG = /[0-9.]/
|
export const NUMBER_LIKE_REG = /[0-9.]/
|
||||||
export const CHINESE_REG = /[\u4e00-\u9fa5]/
|
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',
|
VERTICAL = 'vertical',
|
||||||
HORIZONTAL = 'horizontal'
|
HORIZONTAL = 'horizontal'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum WordBreak {
|
||||||
|
BREAK_ALL = 'break-all',
|
||||||
|
BREAK_WORD = 'break-word'
|
||||||
|
}
|
||||||
+2
-1
@@ -11,7 +11,7 @@ import { formatElementList } from './utils/element'
|
|||||||
import { Register } from './core/register/Register'
|
import { Register } from './core/register/Register'
|
||||||
import { ContextMenu } from './core/contextmenu/ContextMenu'
|
import { ContextMenu } from './core/contextmenu/ContextMenu'
|
||||||
import { IContextMenuContext, IRegisterContextMenu } from './interface/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 { EDITOR_COMPONENT } from './dataset/constant/Editor'
|
||||||
import { IHeader } from './interface/Header'
|
import { IHeader } from './interface/Header'
|
||||||
import { IWatermark } from './interface/Watermark'
|
import { IWatermark } from './interface/Watermark'
|
||||||
@@ -129,6 +129,7 @@ export default class Editor {
|
|||||||
paperDirection: PaperDirection.VERTICAL,
|
paperDirection: PaperDirection.VERTICAL,
|
||||||
inactiveAlpha: 0.6,
|
inactiveAlpha: 0.6,
|
||||||
historyMaxRecordCount: 100,
|
historyMaxRecordCount: 100,
|
||||||
|
wordBreak: WordBreak.BREAK_WORD,
|
||||||
...options,
|
...options,
|
||||||
header: headerOptions,
|
header: headerOptions,
|
||||||
footer: footerOptions,
|
footer: footerOptions,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IElement } from '..'
|
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 { ICheckboxOption } from './Checkbox'
|
||||||
import { IControlOption } from './Control'
|
import { IControlOption } from './Control'
|
||||||
import { ICursorOption } from './Cursor'
|
import { ICursorOption } from './Cursor'
|
||||||
@@ -52,6 +52,7 @@ export interface IEditorOption {
|
|||||||
paperDirection?: PaperDirection;
|
paperDirection?: PaperDirection;
|
||||||
inactiveAlpha?: number;
|
inactiveAlpha?: number;
|
||||||
historyMaxRecordCount?: number;
|
historyMaxRecordCount?: number;
|
||||||
|
wordBreak?: WordBreak;
|
||||||
header?: IHeader;
|
header?: IHeader;
|
||||||
footer?: IFooter;
|
footer?: IFooter;
|
||||||
pageNumber?: IPageNumber;
|
pageNumber?: IPageNumber;
|
||||||
|
|||||||
Reference in New Issue
Block a user