feat: draw line break marker #520

pr675
Hufe921 2 years ago
parent 9144d05adf
commit 4c2b8fc20a

@ -69,6 +69,7 @@ interface IEditorOption {
pageBreak?: IPageBreak // PageBreak option。{font?:string; fontSize?:number; lineDash?:number[];}
zone?: IZoneOption // Zone option。{tipDisabled?:boolean;}
background?: IBackgroundOption // Background option. {color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat;}。default: {color: '#FFFFFF'}
lineBreak?: ILineBreakOption // LineBreak option. {disabled?:boolean; color?:string; lineWidth?:number;}
}
```

@ -69,6 +69,7 @@ interface IEditorOption {
pageBreak?: IPageBreak // 分页符配置。{font?:string; fontSize?:number; lineDash?:number[];}
zone?: IZoneOption // 编辑器区域配置。{tipDisabled?:boolean;}
background?: IBackgroundOption // 背景配置。{color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat;}。默认:{color: '#FFFFFF'}
lineBreak?: ILineBreakOption // 换行符配置。{disabled?:boolean; color?:string; lineWidth?:number;}
}
```

@ -93,6 +93,7 @@ import { Group } from './interactive/Group'
import { Override } from '../override/Override'
import { ImageDisplay } from '../../dataset/enum/Common'
import { PUNCTUATION_REG } from '../../dataset/constant/Regular'
import { LineBreakParticle } from './particle/LineBreakParticle'
export class Draw {
private container: HTMLDivElement
@ -143,6 +144,7 @@ export class Draw {
private checkboxParticle: CheckboxParticle
private blockParticle: BlockParticle
private listParticle: ListParticle
private lineBreakParticle: LineBreakParticle
private control: Control
private workerManager: WorkerManager
private scrollObserver: ScrollObserver
@ -216,6 +218,7 @@ export class Draw {
this.checkboxParticle = new CheckboxParticle(this)
this.blockParticle = new BlockParticle(this)
this.listParticle = new ListParticle(this)
this.lineBreakParticle = new LineBreakParticle(this)
this.control = new Control(this)
this.scrollObserver = new ScrollObserver(this)
@ -510,6 +513,10 @@ export class Draw {
return this.range
}
public getLineBreakParticle(): LineBreakParticle {
return this.lineBreakParticle
}
public getHeaderElementList(): IElement[] {
return this.header.getElementList()
}
@ -1531,7 +1538,8 @@ export class Draw {
}
}
listId = element.listId
if (
// 是否强制换行
const isForceBreak =
element.type === ElementType.SEPARATOR ||
element.type === ElementType.TABLE ||
preElement?.type === ElementType.TABLE ||
@ -1539,10 +1547,13 @@ export class Draw {
element.type === ElementType.BLOCK ||
preElement?.imgDisplay === ImageDisplay.INLINE ||
element.imgDisplay === ImageDisplay.INLINE ||
curRowWidth > availableWidth ||
(i !== 0 && element.value === ZERO) ||
preElement?.listId !== element.listId
) {
preElement?.listId !== element.listId ||
(i !== 0 && element.value === ZERO)
// 是否宽度不足导致换行
const isWidthNotEnough = curRowWidth > availableWidth
if (isForceBreak || isWidthNotEnough) {
// 换行原因:宽度不足
curRow.isWidthNotEnough = isWidthNotEnough && !isForceBreak
// 减小行元素前第一行空行行高
if (
curRow.startIndex === 0 &&
@ -1702,10 +1713,17 @@ export class Draw {
// 优先绘制高亮元素
this._drawHighlight(ctx, payload)
// 绘制元素、下划线、删除线、选区
const { rowList, pageNo, elementList, positionList, startIndex, zone } =
payload
const { scale, tdPadding, group, lineBreak } = this.options
const {
rowList,
pageNo,
elementList,
positionList,
startIndex,
zone,
isDrawLineBreak = !lineBreak.disabled
} = payload
const isPrintMode = this.mode === EditorMode.PRINT
const { scale, tdPadding, group } = this.options
const { isCrossRowCol, tableId } = this.range.getRange()
let index = startIndex
for (let i = 0; i < rowList.length; i++) {
@ -1807,6 +1825,14 @@ export class Draw {
this.textParticle.complete()
}
}
// 换行符绘制
if (
isDrawLineBreak &&
!curRow.isWidthNotEnough &&
j === curRow.elementList.length - 1
) {
this.lineBreakParticle.render(ctx, element, x, y + curRow.height / 2)
}
// 边框绘制(目前仅支持控件)
if (element.control?.border) {
// 不同控件边框立刻绘制
@ -1961,7 +1987,8 @@ export class Draw {
pageNo,
startIndex: 0,
innerWidth: (td.width! - tdPaddingWidth) * scale,
zone
zone,
isDrawLineBreak
})
}
}

@ -5,6 +5,7 @@ import { IRow } from '../../../interface/Row'
import { formatElementList } from '../../../utils/element'
import { Position } from '../../position/Position'
import { Draw } from '../Draw'
import { LineBreakParticle } from '../particle/LineBreakParticle'
export class Placeholder {
private draw: Draw
@ -45,10 +46,15 @@ export class Placeholder {
}
private _computePositionList() {
const { lineBreak, scale } = this.options
const headerExtraHeight = this.draw.getHeader().getExtraHeight()
const innerWidth = this.draw.getInnerWidth()
const margins = this.draw.getMargins()
const startX = margins[3]
let startX = margins[3]
// 换行符绘制开启时,移动起始位置
if (!lineBreak.disabled) {
startX += (LineBreakParticle.WIDTH + LineBreakParticle.GAP) * scale
}
const startY = margins[0] + headerExtraHeight
this.position.computePageRowPosition({
positionList: this.positionList,
@ -92,7 +98,8 @@ export class Placeholder {
rowList: this.rowList,
pageNo: 0,
startIndex: 0,
innerWidth
innerWidth,
isDrawLineBreak: false
})
ctx.restore()
}

@ -0,0 +1,55 @@
import { DeepRequired } from '../../../interface/Common'
import { IEditorOption } from '../../../interface/Editor'
import { IRowElement } from '../../../interface/Row'
import { Draw } from '../Draw'
export class LineBreakParticle {
private options: DeepRequired<IEditorOption>
public static readonly WIDTH = 12
public static readonly HEIGHT = 9
public static readonly GAP = 3 // 距离左边间隙
constructor(draw: Draw) {
this.options = draw.getOptions()
}
public render(
ctx: CanvasRenderingContext2D,
element: IRowElement,
x: number,
y: number
) {
const {
scale,
lineBreak: { color, lineWidth }
} = this.options
ctx.save()
ctx.beginPath()
// 换行符尺寸设置为9像素
const top = y - (LineBreakParticle.HEIGHT * scale) / 2
const left = x + element.metrics.width
// 移动位置并设置缩放
ctx.translate(left, top)
ctx.scale(scale, scale)
// 样式设置
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
ctx.lineCap = 'round'
ctx.lineJoin = 'round'
ctx.beginPath()
// 回车折线
ctx.moveTo(8, 0)
ctx.lineTo(12, 0)
ctx.lineTo(12, 6)
ctx.lineTo(3, 6)
// 箭头向上
ctx.moveTo(3, 6)
ctx.lineTo(6, 3)
// 箭头向下
ctx.moveTo(3, 6)
ctx.lineTo(6, 9)
ctx.stroke()
ctx.closePath()
ctx.restore()
}
}

@ -0,0 +1,7 @@
import { ILineBreakOption } from '../../interface/LineBreak'
export const defaultLineBreak: Readonly<Required<ILineBreakOption>> = {
disabled: true,
color: '#CCCCCC',
lineWidth: 1.5
}

@ -76,6 +76,8 @@ import { IBackgroundOption } from './interface/Background'
import { defaultBackground } from './dataset/constant/Background'
import { BackgroundRepeat, BackgroundSize } from './dataset/enum/Background'
import { TextDecorationStyle } from './dataset/enum/Text'
import { ILineBreakOption } from './interface/LineBreak'
import { defaultLineBreak } from './dataset/constant/LineBreak'
export default class Editor {
public command: Command
@ -143,6 +145,10 @@ export default class Editor {
...defaultBackground,
...options.background
}
const lineBreakOptions: Required<ILineBreakOption> = {
...defaultLineBreak,
...options.lineBreak
}
const editorOptions: DeepRequired<IEditorOption> = {
mode: EditorMode.EDIT,
@ -200,7 +206,8 @@ export default class Editor {
group: groupOptions,
pageBreak: pageBreakOptions,
zone: zoneOptions,
background: backgroundOptions
background: backgroundOptions,
lineBreak: lineBreakOptions
}
// 数据处理
data = deepClone(data)

@ -32,6 +32,7 @@ export interface IDrawRowPayload {
startIndex: number
innerWidth: number
zone?: EditorZone
isDrawLineBreak?: boolean
}
export interface IDrawFloatPayload {

@ -13,6 +13,7 @@ import { ICursorOption } from './Cursor'
import { IFooter } from './Footer'
import { IGroup } from './Group'
import { IHeader } from './Header'
import { ILineBreakOption } from './LineBreak'
import { IMargin } from './Margin'
import { IPageBreak } from './PageBreak'
import { IPageNumber } from './PageNumber'
@ -83,6 +84,7 @@ export interface IEditorOption {
pageBreak?: IPageBreak
zone?: IZoneOption
background?: IBackgroundOption
lineBreak?: ILineBreakOption
}
export interface IEditorResult {

@ -0,0 +1,5 @@
export interface ILineBreakOption {
disabled?: boolean
color?: string
lineWidth?: number
}

@ -18,4 +18,5 @@ export interface IRow {
listIndex?: number
offsetX?: number
elementList: IRowElement[]
isWidthNotEnough?: boolean
}

Loading…
Cancel
Save