|
|
|
@ -1,9 +1,25 @@
|
|
|
|
import { version } from '../../../../package.json'
|
|
|
|
import { version } from '../../../../package.json'
|
|
|
|
import { ZERO } from '../../dataset/constant/Common'
|
|
|
|
import { ZERO } from '../../dataset/constant/Common'
|
|
|
|
import { RowFlex } from '../../dataset/enum/Row'
|
|
|
|
import { RowFlex } from '../../dataset/enum/Row'
|
|
|
|
import { IAppendElementListOption, IDrawOption, IDrawPagePayload, IDrawRowPayload, IGetValueOption, IPainterOption } from '../../interface/Draw'
|
|
|
|
import {
|
|
|
|
import { IEditorData, IEditorOption, IEditorResult } from '../../interface/Editor'
|
|
|
|
IAppendElementListOption,
|
|
|
|
import { IElement, IElementMetrics, IElementFillRect, IElementStyle } from '../../interface/Element'
|
|
|
|
IDrawOption,
|
|
|
|
|
|
|
|
IDrawPagePayload,
|
|
|
|
|
|
|
|
IDrawRowPayload,
|
|
|
|
|
|
|
|
IGetValueOption,
|
|
|
|
|
|
|
|
IPainterOption
|
|
|
|
|
|
|
|
} from '../../interface/Draw'
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
IEditorData,
|
|
|
|
|
|
|
|
IEditorOption,
|
|
|
|
|
|
|
|
IEditorResult
|
|
|
|
|
|
|
|
} from '../../interface/Editor'
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
IElement,
|
|
|
|
|
|
|
|
IElementMetrics,
|
|
|
|
|
|
|
|
IElementFillRect,
|
|
|
|
|
|
|
|
IElementStyle
|
|
|
|
|
|
|
|
} from '../../interface/Element'
|
|
|
|
import { IRow, IRowElement } from '../../interface/Row'
|
|
|
|
import { IRow, IRowElement } from '../../interface/Row'
|
|
|
|
import { deepClone, getUUID, nextTick } from '../../utils'
|
|
|
|
import { deepClone, getUUID, nextTick } from '../../utils'
|
|
|
|
import { Cursor } from '../cursor/Cursor'
|
|
|
|
import { Cursor } from '../cursor/Cursor'
|
|
|
|
@ -35,7 +51,14 @@ 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, WordBreak } 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'
|
|
|
|
@ -58,7 +81,6 @@ import { Placeholder } from './frame/Placeholder'
|
|
|
|
import { WORD_LIKE_REG } from '../../dataset/constant/Regular'
|
|
|
|
import { WORD_LIKE_REG } from '../../dataset/constant/Regular'
|
|
|
|
|
|
|
|
|
|
|
|
export class Draw {
|
|
|
|
export class Draw {
|
|
|
|
|
|
|
|
|
|
|
|
private container: HTMLDivElement
|
|
|
|
private container: HTMLDivElement
|
|
|
|
private pageContainer: HTMLDivElement
|
|
|
|
private pageContainer: HTMLDivElement
|
|
|
|
private pageList: HTMLCanvasElement[]
|
|
|
|
private pageList: HTMLCanvasElement[]
|
|
|
|
@ -276,7 +298,10 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getPageNumberBottom(): number {
|
|
|
|
public getPageNumberBottom(): number {
|
|
|
|
const { pageNumber: { bottom }, scale } = this.options
|
|
|
|
const {
|
|
|
|
|
|
|
|
pageNumber: { bottom },
|
|
|
|
|
|
|
|
scale
|
|
|
|
|
|
|
|
} = this.options
|
|
|
|
return bottom * scale
|
|
|
|
return bottom * scale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -444,7 +469,8 @@ export class Draw {
|
|
|
|
|
|
|
|
|
|
|
|
public insertElementList(payload: IElement[]) {
|
|
|
|
public insertElementList(payload: IElement[]) {
|
|
|
|
if (!payload.length) return
|
|
|
|
if (!payload.length) return
|
|
|
|
const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside()
|
|
|
|
const isPartRangeInControlOutside =
|
|
|
|
|
|
|
|
this.control.isPartRangeInControlOutside()
|
|
|
|
if (isPartRangeInControlOutside) return
|
|
|
|
if (isPartRangeInControlOutside) return
|
|
|
|
const { startIndex, endIndex } = this.range.getRange()
|
|
|
|
const { startIndex, endIndex } = this.range.getRange()
|
|
|
|
if (!~startIndex && !~endIndex) return
|
|
|
|
if (!~startIndex && !~endIndex) return
|
|
|
|
@ -475,7 +501,10 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public appendElementList(elementList: IElement[], options: IAppendElementListOption = {}) {
|
|
|
|
public appendElementList(
|
|
|
|
|
|
|
|
elementList: IElement[],
|
|
|
|
|
|
|
|
options: IAppendElementListOption = {}
|
|
|
|
|
|
|
|
) {
|
|
|
|
if (!elementList.length) return
|
|
|
|
if (!elementList.length) return
|
|
|
|
formatElementList(elementList, {
|
|
|
|
formatElementList(elementList, {
|
|
|
|
isHandleFirstElement: false,
|
|
|
|
isHandleFirstElement: false,
|
|
|
|
@ -496,17 +525,30 @@ export class Draw {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public spliceElementList(elementList: IElement[], start: number, deleteCount: number, ...items: IElement[]) {
|
|
|
|
public spliceElementList(
|
|
|
|
|
|
|
|
elementList: IElement[],
|
|
|
|
|
|
|
|
start: number,
|
|
|
|
|
|
|
|
deleteCount: number,
|
|
|
|
|
|
|
|
...items: IElement[]
|
|
|
|
|
|
|
|
) {
|
|
|
|
if (deleteCount > 0) {
|
|
|
|
if (deleteCount > 0) {
|
|
|
|
// 当最后元素与开始元素列表信息不一致时:清除当前列表信息
|
|
|
|
// 当最后元素与开始元素列表信息不一致时:清除当前列表信息
|
|
|
|
const endIndex = start + deleteCount
|
|
|
|
const endIndex = start + deleteCount
|
|
|
|
const endElement = elementList[endIndex]
|
|
|
|
const endElement = elementList[endIndex]
|
|
|
|
const endElementListId = endElement?.listId
|
|
|
|
const endElementListId = endElement?.listId
|
|
|
|
if (endElementListId && elementList[start - 1]?.listId !== endElementListId) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
endElementListId &&
|
|
|
|
|
|
|
|
elementList[start - 1]?.listId !== endElementListId
|
|
|
|
|
|
|
|
) {
|
|
|
|
let startIndex = endIndex
|
|
|
|
let startIndex = endIndex
|
|
|
|
while (startIndex < elementList.length) {
|
|
|
|
while (startIndex < elementList.length) {
|
|
|
|
const curElement = elementList[startIndex]
|
|
|
|
const curElement = elementList[startIndex]
|
|
|
|
if (curElement.listId !== endElementListId || curElement.value === ZERO) break
|
|
|
|
if (
|
|
|
|
|
|
|
|
curElement.listId !== endElementListId ||
|
|
|
|
|
|
|
|
curElement.value === ZERO
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
delete curElement.listId
|
|
|
|
delete curElement.listId
|
|
|
|
delete curElement.listType
|
|
|
|
delete curElement.listType
|
|
|
|
delete curElement.listStyle
|
|
|
|
delete curElement.listStyle
|
|
|
|
@ -597,18 +639,23 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getPainterStyle(): IElementStyle | null {
|
|
|
|
public getPainterStyle(): IElementStyle | null {
|
|
|
|
return this.painterStyle && Object.keys(this.painterStyle).length ? this.painterStyle : null
|
|
|
|
return this.painterStyle && Object.keys(this.painterStyle).length
|
|
|
|
|
|
|
|
? this.painterStyle
|
|
|
|
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getPainterOptions(): IPainterOption | null {
|
|
|
|
public getPainterOptions(): IPainterOption | null {
|
|
|
|
return this.painterOptions
|
|
|
|
return this.painterOptions
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public setPainterStyle(payload: IElementStyle | null, options?: IPainterOption) {
|
|
|
|
public setPainterStyle(
|
|
|
|
|
|
|
|
payload: IElementStyle | null,
|
|
|
|
|
|
|
|
options?: IPainterOption
|
|
|
|
|
|
|
|
) {
|
|
|
|
this.painterStyle = payload
|
|
|
|
this.painterStyle = payload
|
|
|
|
this.painterOptions = options || null
|
|
|
|
this.painterOptions = options || null
|
|
|
|
if (this.getPainterStyle()) {
|
|
|
|
if (this.getPainterStyle()) {
|
|
|
|
this.pageList.forEach(c => c.style.cursor = 'copy')
|
|
|
|
this.pageList.forEach(c => (c.style.cursor = 'copy'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -747,8 +794,14 @@ export class Draw {
|
|
|
|
// 数据
|
|
|
|
// 数据
|
|
|
|
const { pageNo } = options
|
|
|
|
const { pageNo } = options
|
|
|
|
let mainElementList = this.elementList
|
|
|
|
let mainElementList = this.elementList
|
|
|
|
if (Number.isInteger(pageNo) && pageNo! >= 0 && pageNo! < this.pageRowList.length) {
|
|
|
|
if (
|
|
|
|
mainElementList = this.pageRowList[pageNo!].flatMap(row => row.elementList)
|
|
|
|
Number.isInteger(pageNo) &&
|
|
|
|
|
|
|
|
pageNo! >= 0 &&
|
|
|
|
|
|
|
|
pageNo! < this.pageRowList.length
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
mainElementList = this.pageRowList[pageNo!].flatMap(
|
|
|
|
|
|
|
|
row => row.elementList
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const data: IEditorData = {
|
|
|
|
const data: IEditorData = {
|
|
|
|
header: zipElementList(this.headerElementList),
|
|
|
|
header: zipElementList(this.headerElementList),
|
|
|
|
@ -850,11 +903,14 @@ export class Draw {
|
|
|
|
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
|
|
|
|
return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${size * scale}px ${font}`
|
|
|
|
return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${
|
|
|
|
|
|
|
|
size * scale
|
|
|
|
|
|
|
|
}px ${font}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public computeRowList(innerWidth: number, elementList: IElement[]) {
|
|
|
|
public computeRowList(innerWidth: number, elementList: IElement[]) {
|
|
|
|
const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } = this.options
|
|
|
|
const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } =
|
|
|
|
|
|
|
|
this.options
|
|
|
|
const defaultBasicRowMarginHeight = this.getDefaultBasicRowMarginHeight()
|
|
|
|
const defaultBasicRowMarginHeight = this.getDefaultBasicRowMarginHeight()
|
|
|
|
const canvas = document.createElement('canvas')
|
|
|
|
const canvas = document.createElement('canvas')
|
|
|
|
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
|
|
|
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
|
|
|
@ -877,7 +933,8 @@ export class Draw {
|
|
|
|
for (let i = 0; i < elementList.length; i++) {
|
|
|
|
for (let i = 0; i < elementList.length; i++) {
|
|
|
|
const curRow: IRow = rowList[rowList.length - 1]
|
|
|
|
const curRow: IRow = rowList[rowList.length - 1]
|
|
|
|
const element = elementList[i]
|
|
|
|
const element = elementList[i]
|
|
|
|
const rowMargin = defaultBasicRowMarginHeight * (element.rowMargin || defaultRowMargin)
|
|
|
|
const rowMargin =
|
|
|
|
|
|
|
|
defaultBasicRowMarginHeight * (element.rowMargin || defaultRowMargin)
|
|
|
|
const metrics: IElementMetrics = {
|
|
|
|
const metrics: IElementMetrics = {
|
|
|
|
width: 0,
|
|
|
|
width: 0,
|
|
|
|
height: 0,
|
|
|
|
height: 0,
|
|
|
|
@ -887,17 +944,24 @@ export class Draw {
|
|
|
|
// 实际可用宽度
|
|
|
|
// 实际可用宽度
|
|
|
|
const offsetX = element.listId ? listStyleMap.get(element.listId) || 0 : 0
|
|
|
|
const offsetX = element.listId ? listStyleMap.get(element.listId) || 0 : 0
|
|
|
|
const availableWidth = innerWidth - offsetX
|
|
|
|
const availableWidth = innerWidth - offsetX
|
|
|
|
if (element.type === ElementType.IMAGE || element.type === ElementType.LATEX) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
element.type === ElementType.IMAGE ||
|
|
|
|
|
|
|
|
element.type === ElementType.LATEX
|
|
|
|
|
|
|
|
) {
|
|
|
|
const elementWidth = element.width! * scale
|
|
|
|
const elementWidth = element.width! * scale
|
|
|
|
const elementHeight = element.height! * scale
|
|
|
|
const elementHeight = element.height! * scale
|
|
|
|
// 图片超出尺寸后自适应
|
|
|
|
// 图片超出尺寸后自适应
|
|
|
|
const curRowWidth = element.imgDisplay === ImageDisplay.INLINE ? 0 : curRow.width
|
|
|
|
const curRowWidth =
|
|
|
|
|
|
|
|
element.imgDisplay === ImageDisplay.INLINE ? 0 : curRow.width
|
|
|
|
if (curRowWidth + elementWidth > availableWidth) {
|
|
|
|
if (curRowWidth + elementWidth > availableWidth) {
|
|
|
|
// 计算剩余大小
|
|
|
|
// 计算剩余大小
|
|
|
|
const surplusWidth = availableWidth - curRowWidth
|
|
|
|
const surplusWidth = availableWidth - curRowWidth
|
|
|
|
const adaptiveWidth = surplusWidth > 0 ? surplusWidth : Math.min(elementWidth, availableWidth)
|
|
|
|
const adaptiveWidth =
|
|
|
|
|
|
|
|
surplusWidth > 0
|
|
|
|
|
|
|
|
? surplusWidth
|
|
|
|
|
|
|
|
: Math.min(elementWidth, availableWidth)
|
|
|
|
element.width = adaptiveWidth
|
|
|
|
element.width = adaptiveWidth
|
|
|
|
element.height = elementHeight * adaptiveWidth / elementWidth
|
|
|
|
element.height = (elementHeight * adaptiveWidth) / elementWidth
|
|
|
|
metrics.width = element.width
|
|
|
|
metrics.width = element.width
|
|
|
|
metrics.height = element.height
|
|
|
|
metrics.height = element.height
|
|
|
|
metrics.boundingBoxDescent = element.height
|
|
|
|
metrics.boundingBoxDescent = element.height
|
|
|
|
@ -917,7 +981,10 @@ export class Draw {
|
|
|
|
const tr = trList[t]
|
|
|
|
const tr = trList[t]
|
|
|
|
for (let d = 0; d < tr.tdList.length; d++) {
|
|
|
|
for (let d = 0; d < tr.tdList.length; d++) {
|
|
|
|
const td = tr.tdList[d]
|
|
|
|
const td = tr.tdList[d]
|
|
|
|
const rowList = this.computeRowList((td.width! - tdGap) * scale, td.value)
|
|
|
|
const rowList = this.computeRowList(
|
|
|
|
|
|
|
|
(td.width! - tdGap) * scale,
|
|
|
|
|
|
|
|
td.value
|
|
|
|
|
|
|
|
)
|
|
|
|
const rowHeight = rowList.reduce((pre, cur) => pre + cur.height, 0)
|
|
|
|
const rowHeight = rowList.reduce((pre, cur) => pre + cur.height, 0)
|
|
|
|
td.rowList = rowList
|
|
|
|
td.rowList = rowList
|
|
|
|
// 移除缩放导致的行高变化-渲染时会进行缩放调整
|
|
|
|
// 移除缩放导致的行高变化-渲染时会进行缩放调整
|
|
|
|
@ -957,9 +1024,10 @@ export class Draw {
|
|
|
|
const curTdHeight = td.mainHeight!
|
|
|
|
const curTdHeight = td.mainHeight!
|
|
|
|
const curTdMinHeight = td.realMinHeight!
|
|
|
|
const curTdMinHeight = td.realMinHeight!
|
|
|
|
// 获取最大可减少高度
|
|
|
|
// 获取最大可减少高度
|
|
|
|
const curReduceHeight = curTdHeight < curTdMinHeight
|
|
|
|
const curReduceHeight =
|
|
|
|
? curTdRealHeight - curTdMinHeight
|
|
|
|
curTdHeight < curTdMinHeight
|
|
|
|
: curTdRealHeight - curTdHeight
|
|
|
|
? curTdRealHeight - curTdMinHeight
|
|
|
|
|
|
|
|
: curTdRealHeight - curTdHeight
|
|
|
|
if (!~reduceHeight || curReduceHeight < reduceHeight) {
|
|
|
|
if (!~reduceHeight || curReduceHeight < reduceHeight) {
|
|
|
|
reduceHeight = curReduceHeight
|
|
|
|
reduceHeight = curReduceHeight
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -976,7 +1044,10 @@ export class Draw {
|
|
|
|
this.tableParticle.computeRowColInfo(element)
|
|
|
|
this.tableParticle.computeRowColInfo(element)
|
|
|
|
// 计算出表格高度
|
|
|
|
// 计算出表格高度
|
|
|
|
const tableHeight = trList.reduce((pre, cur) => pre + cur.height, 0)
|
|
|
|
const tableHeight = trList.reduce((pre, cur) => pre + cur.height, 0)
|
|
|
|
const tableWidth = element.colgroup!.reduce((pre, cur) => pre + cur.width, 0)
|
|
|
|
const tableWidth = element.colgroup!.reduce(
|
|
|
|
|
|
|
|
(pre, cur) => pre + cur.width,
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
)
|
|
|
|
element.width = tableWidth
|
|
|
|
element.width = tableWidth
|
|
|
|
element.height = tableHeight
|
|
|
|
element.height = tableHeight
|
|
|
|
const elementWidth = tableWidth * scale
|
|
|
|
const elementWidth = tableWidth * scale
|
|
|
|
@ -991,7 +1062,10 @@ export class Draw {
|
|
|
|
let curPagePreHeight = marginHeight
|
|
|
|
let curPagePreHeight = marginHeight
|
|
|
|
for (let r = 0; r < rowList.length; r++) {
|
|
|
|
for (let r = 0; r < rowList.length; r++) {
|
|
|
|
const row = rowList[r]
|
|
|
|
const row = rowList[r]
|
|
|
|
if (row.height + curPagePreHeight > height || rowList[r - 1]?.isPageBreak) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
row.height + curPagePreHeight > height ||
|
|
|
|
|
|
|
|
rowList[r - 1]?.isPageBreak
|
|
|
|
|
|
|
|
) {
|
|
|
|
curPagePreHeight = marginHeight + row.height
|
|
|
|
curPagePreHeight = marginHeight + row.height
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
curPagePreHeight += row.height
|
|
|
|
curPagePreHeight += row.height
|
|
|
|
@ -1009,7 +1083,10 @@ export class Draw {
|
|
|
|
for (let r = 0; r < trList.length; r++) {
|
|
|
|
for (let r = 0; r < trList.length; r++) {
|
|
|
|
const tr = trList[r]
|
|
|
|
const tr = trList[r]
|
|
|
|
const trHeight = tr.height * scale
|
|
|
|
const trHeight = tr.height * scale
|
|
|
|
if (curPagePreHeight + rowMarginHeight + preTrHeight + trHeight > height) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
curPagePreHeight + rowMarginHeight + preTrHeight + trHeight >
|
|
|
|
|
|
|
|
height
|
|
|
|
|
|
|
|
) {
|
|
|
|
// 是否跨列
|
|
|
|
// 是否跨列
|
|
|
|
if (element.colgroup?.length !== tr.tdList.length) {
|
|
|
|
if (element.colgroup?.length !== tr.tdList.length) {
|
|
|
|
deleteCount = 0
|
|
|
|
deleteCount = 0
|
|
|
|
@ -1024,7 +1101,10 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (deleteCount) {
|
|
|
|
if (deleteCount) {
|
|
|
|
const cloneTrList = trList.splice(deleteStart, deleteCount)
|
|
|
|
const cloneTrList = trList.splice(deleteStart, deleteCount)
|
|
|
|
const cloneTrHeight = cloneTrList.reduce((pre, cur) => pre + cur.height, 0)
|
|
|
|
const cloneTrHeight = cloneTrList.reduce(
|
|
|
|
|
|
|
|
(pre, cur) => pre + cur.height,
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
)
|
|
|
|
element.height -= cloneTrHeight
|
|
|
|
element.height -= cloneTrHeight
|
|
|
|
metrics.height -= cloneTrHeight
|
|
|
|
metrics.height -= cloneTrHeight
|
|
|
|
metrics.boundingBoxDescent -= cloneTrHeight
|
|
|
|
metrics.boundingBoxDescent -= cloneTrHeight
|
|
|
|
@ -1035,7 +1115,10 @@ export class Draw {
|
|
|
|
this.spliceElementList(elementList, i + 1, 0, cloneElement)
|
|
|
|
this.spliceElementList(elementList, i + 1, 0, cloneElement)
|
|
|
|
// 换页的是当前行则改变上下文
|
|
|
|
// 换页的是当前行则改变上下文
|
|
|
|
const positionContext = this.position.getPositionContext()
|
|
|
|
const positionContext = this.position.getPositionContext()
|
|
|
|
if (positionContext.isTable && positionContext.trIndex === deleteStart) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
positionContext.isTable &&
|
|
|
|
|
|
|
|
positionContext.trIndex === deleteStart
|
|
|
|
|
|
|
|
) {
|
|
|
|
positionContext.index! += 1
|
|
|
|
positionContext.index! += 1
|
|
|
|
positionContext.trIndex = 0
|
|
|
|
positionContext.trIndex = 0
|
|
|
|
this.position.setPositionContext(positionContext)
|
|
|
|
this.position.setPositionContext(positionContext)
|
|
|
|
@ -1079,7 +1162,10 @@ export class Draw {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// 设置上下标真实字体尺寸
|
|
|
|
// 设置上下标真实字体尺寸
|
|
|
|
const size = element.size || defaultSize
|
|
|
|
const size = element.size || defaultSize
|
|
|
|
if (element.type === ElementType.SUPERSCRIPT || element.type === ElementType.SUBSCRIPT) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
element.type === ElementType.SUPERSCRIPT ||
|
|
|
|
|
|
|
|
element.type === ElementType.SUBSCRIPT
|
|
|
|
|
|
|
|
) {
|
|
|
|
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
|
|
|
|
@ -1089,19 +1175,29 @@ export class Draw {
|
|
|
|
if (element.letterSpacing) {
|
|
|
|
if (element.letterSpacing) {
|
|
|
|
metrics.width += element.letterSpacing * scale
|
|
|
|
metrics.width += element.letterSpacing * scale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
metrics.boundingBoxAscent = (element.value === ZERO ? defaultSize : fontMetrics.actualBoundingBoxAscent) * scale
|
|
|
|
metrics.boundingBoxAscent =
|
|
|
|
metrics.boundingBoxDescent = fontMetrics.actualBoundingBoxDescent * scale
|
|
|
|
(element.value === ZERO
|
|
|
|
|
|
|
|
? defaultSize
|
|
|
|
|
|
|
|
: fontMetrics.actualBoundingBoxAscent) * scale
|
|
|
|
|
|
|
|
metrics.boundingBoxDescent =
|
|
|
|
|
|
|
|
fontMetrics.actualBoundingBoxDescent * scale
|
|
|
|
if (element.type === ElementType.SUPERSCRIPT) {
|
|
|
|
if (element.type === ElementType.SUPERSCRIPT) {
|
|
|
|
metrics.boundingBoxAscent += metrics.height / 2
|
|
|
|
metrics.boundingBoxAscent += metrics.height / 2
|
|
|
|
} else if (element.type === ElementType.SUBSCRIPT) {
|
|
|
|
} else if (element.type === ElementType.SUBSCRIPT) {
|
|
|
|
metrics.boundingBoxDescent += metrics.height / 2
|
|
|
|
metrics.boundingBoxDescent += metrics.height / 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const ascent = (element.imgDisplay !== ImageDisplay.INLINE && element.type === ElementType.IMAGE) ||
|
|
|
|
const ascent =
|
|
|
|
|
|
|
|
(element.imgDisplay !== ImageDisplay.INLINE &&
|
|
|
|
|
|
|
|
element.type === ElementType.IMAGE) ||
|
|
|
|
element.type === ElementType.LATEX
|
|
|
|
element.type === ElementType.LATEX
|
|
|
|
? metrics.height + rowMargin
|
|
|
|
? metrics.height + rowMargin
|
|
|
|
: metrics.boundingBoxAscent + rowMargin
|
|
|
|
: metrics.boundingBoxAscent + rowMargin
|
|
|
|
const height = rowMargin + metrics.boundingBoxAscent + metrics.boundingBoxDescent + rowMargin
|
|
|
|
const height =
|
|
|
|
|
|
|
|
rowMargin +
|
|
|
|
|
|
|
|
metrics.boundingBoxAscent +
|
|
|
|
|
|
|
|
metrics.boundingBoxDescent +
|
|
|
|
|
|
|
|
rowMargin
|
|
|
|
const rowElement: IRowElement = Object.assign(element, {
|
|
|
|
const rowElement: IRowElement = Object.assign(element, {
|
|
|
|
metrics,
|
|
|
|
metrics,
|
|
|
|
style: this._getFont(element, scale)
|
|
|
|
style: this._getFont(element, scale)
|
|
|
|
@ -1119,12 +1215,19 @@ export class Draw {
|
|
|
|
// 英文单词
|
|
|
|
// 英文单词
|
|
|
|
const word = `${preElement?.value || ''}${element.value}`
|
|
|
|
const word = `${preElement?.value || ''}${element.value}`
|
|
|
|
if (WORD_LIKE_REG.test(word)) {
|
|
|
|
if (WORD_LIKE_REG.test(word)) {
|
|
|
|
const { width, endElement } = this.textParticle.measureWord(ctx, elementList, i)
|
|
|
|
const { width, endElement } = this.textParticle.measureWord(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
elementList,
|
|
|
|
|
|
|
|
i
|
|
|
|
|
|
|
|
)
|
|
|
|
curRowWidth += width
|
|
|
|
curRowWidth += width
|
|
|
|
nextElement = endElement
|
|
|
|
nextElement = endElement
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 标点符号
|
|
|
|
// 标点符号
|
|
|
|
curRowWidth += this.textParticle.measurePunctuationWidth(ctx, nextElement)
|
|
|
|
curRowWidth += this.textParticle.measurePunctuationWidth(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
nextElement
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 列表信息
|
|
|
|
// 列表信息
|
|
|
|
@ -1137,15 +1240,15 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
listId = element.listId
|
|
|
|
listId = element.listId
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
element.type === ElementType.TABLE
|
|
|
|
element.type === ElementType.TABLE ||
|
|
|
|
|| preElement?.type === ElementType.TABLE
|
|
|
|
preElement?.type === ElementType.TABLE ||
|
|
|
|
|| preElement?.type === ElementType.BLOCK
|
|
|
|
preElement?.type === ElementType.BLOCK ||
|
|
|
|
|| element.type === ElementType.BLOCK
|
|
|
|
element.type === ElementType.BLOCK ||
|
|
|
|
|| preElement?.imgDisplay === ImageDisplay.INLINE
|
|
|
|
preElement?.imgDisplay === ImageDisplay.INLINE ||
|
|
|
|
|| element.imgDisplay === ImageDisplay.INLINE
|
|
|
|
element.imgDisplay === ImageDisplay.INLINE ||
|
|
|
|
|| curRowWidth > availableWidth
|
|
|
|
curRowWidth > availableWidth ||
|
|
|
|
|| (i !== 0 && element.value === ZERO)
|
|
|
|
(i !== 0 && element.value === ZERO) ||
|
|
|
|
|| (preElement?.listId !== element.listId)
|
|
|
|
preElement?.listId !== element.listId
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
// 减小行元素前第一行空行行高
|
|
|
|
// 减小行元素前第一行空行行高
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
@ -1156,8 +1259,12 @@ export class Draw {
|
|
|
|
curRow.height = defaultBasicRowMarginHeight
|
|
|
|
curRow.height = defaultBasicRowMarginHeight
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 两端对齐
|
|
|
|
// 两端对齐
|
|
|
|
if (preElement?.rowFlex === RowFlex.ALIGNMENT && curRowWidth > availableWidth) {
|
|
|
|
if (
|
|
|
|
const gap = (availableWidth - curRow.width) / curRow.elementList.length
|
|
|
|
preElement?.rowFlex === RowFlex.ALIGNMENT &&
|
|
|
|
|
|
|
|
curRowWidth > availableWidth
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
const gap =
|
|
|
|
|
|
|
|
(availableWidth - curRow.width) / curRow.elementList.length
|
|
|
|
for (let e = 0; e < curRow.elementList.length; e++) {
|
|
|
|
for (let e = 0; e < curRow.elementList.length; e++) {
|
|
|
|
const el = curRow.elementList[e]
|
|
|
|
const el = curRow.elementList[e]
|
|
|
|
el.metrics.width += gap
|
|
|
|
el.metrics.width += gap
|
|
|
|
@ -1217,7 +1324,10 @@ export class Draw {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
for (let i = 0; i < this.rowList.length; i++) {
|
|
|
|
for (let i = 0; i < this.rowList.length; i++) {
|
|
|
|
const row = this.rowList[i]
|
|
|
|
const row = this.rowList[i]
|
|
|
|
if (row.height + pageHeight > height || this.rowList[i - 1]?.isPageBreak) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
row.height + pageHeight > height ||
|
|
|
|
|
|
|
|
this.rowList[i - 1]?.isPageBreak
|
|
|
|
|
|
|
|
) {
|
|
|
|
pageHeight = marginHeight + row.height
|
|
|
|
pageHeight = marginHeight + row.height
|
|
|
|
pageRowList.push([row])
|
|
|
|
pageRowList.push([row])
|
|
|
|
pageNo++
|
|
|
|
pageNo++
|
|
|
|
@ -1238,7 +1348,8 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
|
|
|
|
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
|
|
|
|
const { rowList, pageNo, elementList, positionList, startIndex, zone } = payload
|
|
|
|
const { rowList, pageNo, elementList, positionList, startIndex, zone } =
|
|
|
|
|
|
|
|
payload
|
|
|
|
const { scale, tdPadding } = this.options
|
|
|
|
const { scale, tdPadding } = this.options
|
|
|
|
const { isCrossRowCol, tableId } = this.range.getRange()
|
|
|
|
const { isCrossRowCol, tableId } = this.range.getRange()
|
|
|
|
let index = startIndex
|
|
|
|
let index = startIndex
|
|
|
|
@ -1266,10 +1377,21 @@ export class Draw {
|
|
|
|
// 元素高亮记录
|
|
|
|
// 元素高亮记录
|
|
|
|
if (element.highlight) {
|
|
|
|
if (element.highlight) {
|
|
|
|
// 高亮元素相连需立即绘制,并记录下一元素坐标
|
|
|
|
// 高亮元素相连需立即绘制,并记录下一元素坐标
|
|
|
|
if (preElement && preElement.highlight && preElement.highlight !== element.highlight) {
|
|
|
|
if (
|
|
|
|
|
|
|
|
preElement &&
|
|
|
|
|
|
|
|
preElement.highlight &&
|
|
|
|
|
|
|
|
preElement.highlight !== element.highlight
|
|
|
|
|
|
|
|
) {
|
|
|
|
this.highlight.render(ctx)
|
|
|
|
this.highlight.render(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.highlight.recordFillInfo(ctx, x, y, metrics.width, curRow.height, element.highlight)
|
|
|
|
this.highlight.recordFillInfo(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
x,
|
|
|
|
|
|
|
|
y,
|
|
|
|
|
|
|
|
metrics.width,
|
|
|
|
|
|
|
|
curRow.height,
|
|
|
|
|
|
|
|
element.highlight
|
|
|
|
|
|
|
|
)
|
|
|
|
} else if (preElement?.highlight) {
|
|
|
|
} else if (preElement?.highlight) {
|
|
|
|
this.highlight.render(ctx)
|
|
|
|
this.highlight.render(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1325,19 +1447,40 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 下划线记录
|
|
|
|
// 下划线记录
|
|
|
|
if (element.underline) {
|
|
|
|
if (element.underline) {
|
|
|
|
this.underline.recordFillInfo(ctx, x, y + curRow.height, metrics.width, 0, element.color)
|
|
|
|
this.underline.recordFillInfo(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
x,
|
|
|
|
|
|
|
|
y + curRow.height,
|
|
|
|
|
|
|
|
metrics.width,
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
|
|
|
element.color
|
|
|
|
|
|
|
|
)
|
|
|
|
} else if (preElement?.underline) {
|
|
|
|
} else if (preElement?.underline) {
|
|
|
|
this.underline.render(ctx)
|
|
|
|
this.underline.render(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 删除线记录
|
|
|
|
// 删除线记录
|
|
|
|
if (element.strikeout) {
|
|
|
|
if (element.strikeout) {
|
|
|
|
this.strikeout.recordFillInfo(ctx, x, y + curRow.height / 2, metrics.width)
|
|
|
|
this.strikeout.recordFillInfo(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
x,
|
|
|
|
|
|
|
|
y + curRow.height / 2,
|
|
|
|
|
|
|
|
metrics.width
|
|
|
|
|
|
|
|
)
|
|
|
|
} else if (preElement?.strikeout) {
|
|
|
|
} else if (preElement?.strikeout) {
|
|
|
|
this.strikeout.render(ctx)
|
|
|
|
this.strikeout.render(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 选区记录
|
|
|
|
// 选区记录
|
|
|
|
const { zone: currentZone, startIndex, endIndex } = this.range.getRange()
|
|
|
|
const {
|
|
|
|
if (currentZone === zone && startIndex !== endIndex && startIndex <= index && index <= endIndex) {
|
|
|
|
zone: currentZone,
|
|
|
|
|
|
|
|
startIndex,
|
|
|
|
|
|
|
|
endIndex
|
|
|
|
|
|
|
|
} = this.range.getRange()
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
currentZone === zone &&
|
|
|
|
|
|
|
|
startIndex !== endIndex &&
|
|
|
|
|
|
|
|
startIndex <= index &&
|
|
|
|
|
|
|
|
index <= endIndex
|
|
|
|
|
|
|
|
) {
|
|
|
|
// 从行尾开始-绘制最小宽度
|
|
|
|
// 从行尾开始-绘制最小宽度
|
|
|
|
if (startIndex === index) {
|
|
|
|
if (startIndex === index) {
|
|
|
|
const nextElement = elementList[startIndex + 1]
|
|
|
|
const nextElement = elementList[startIndex + 1]
|
|
|
|
@ -1351,8 +1494,8 @@ export class Draw {
|
|
|
|
const positionContext = this.position.getPositionContext()
|
|
|
|
const positionContext = this.position.getPositionContext()
|
|
|
|
// 表格需限定上下文
|
|
|
|
// 表格需限定上下文
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
(!positionContext.isTable && !element.tdId)
|
|
|
|
(!positionContext.isTable && !element.tdId) ||
|
|
|
|
|| positionContext.tdId === element.tdId
|
|
|
|
positionContext.tdId === element.tdId
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let rangeWidth = metrics.width
|
|
|
|
let rangeWidth = metrics.width
|
|
|
|
// 最小选区宽度
|
|
|
|
// 最小选区宽度
|
|
|
|
@ -1392,7 +1535,11 @@ export class Draw {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 绘制列表样式
|
|
|
|
// 绘制列表样式
|
|
|
|
if (curRow.isList) {
|
|
|
|
if (curRow.isList) {
|
|
|
|
this.listParticle.drawListStyle(ctx, curRow, positionList[curRow.startIndex])
|
|
|
|
this.listParticle.drawListStyle(
|
|
|
|
|
|
|
|
ctx,
|
|
|
|
|
|
|
|
curRow,
|
|
|
|
|
|
|
|
positionList[curRow.startIndex]
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 绘制富文本及文字
|
|
|
|
// 绘制富文本及文字
|
|
|
|
this._drawRichText(ctx)
|
|
|
|
this._drawRichText(ctx)
|
|
|
|
@ -1401,8 +1548,16 @@ export class Draw {
|
|
|
|
const { x, y, width, height } = rangeRecord
|
|
|
|
const { x, y, width, height } = rangeRecord
|
|
|
|
this.range.render(ctx, x, y, width, height)
|
|
|
|
this.range.render(ctx, x, y, width, height)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isCrossRowCol && tableRangeElement && tableRangeElement.id === tableId) {
|
|
|
|
if (
|
|
|
|
const { coordinate: { leftTop: [x, y] } } = positionList[curRow.startIndex]
|
|
|
|
isCrossRowCol &&
|
|
|
|
|
|
|
|
tableRangeElement &&
|
|
|
|
|
|
|
|
tableRangeElement.id === tableId
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
|
|
coordinate: {
|
|
|
|
|
|
|
|
leftTop: [x, y]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} = positionList[curRow.startIndex]
|
|
|
|
this.tableParticle.drawRange(ctx, tableRangeElement, x, y)
|
|
|
|
this.tableParticle.drawRange(ctx, tableRangeElement, x, y)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1474,7 +1629,7 @@ export class Draw {
|
|
|
|
const positionList = this.position.getOriginalMainPositionList()
|
|
|
|
const positionList = this.position.getOriginalMainPositionList()
|
|
|
|
const elementList = this.getOriginalMainElementList()
|
|
|
|
const elementList = this.getOriginalMainElementList()
|
|
|
|
this._disconnectLazyRender()
|
|
|
|
this._disconnectLazyRender()
|
|
|
|
this.lazyRenderIntersectionObserver = new IntersectionObserver((entries) => {
|
|
|
|
this.lazyRenderIntersectionObserver = new IntersectionObserver(entries => {
|
|
|
|
entries.forEach(entry => {
|
|
|
|
entries.forEach(entry => {
|
|
|
|
if (entry.isIntersecting) {
|
|
|
|
if (entry.isIntersecting) {
|
|
|
|
const index = Number((<HTMLCanvasElement>entry.target).dataset.index)
|
|
|
|
const index = Number((<HTMLCanvasElement>entry.target).dataset.index)
|
|
|
|
@ -1555,7 +1710,8 @@ export class Draw {
|
|
|
|
if (prePageCount > curPageCount) {
|
|
|
|
if (prePageCount > curPageCount) {
|
|
|
|
const deleteCount = prePageCount - curPageCount
|
|
|
|
const deleteCount = prePageCount - curPageCount
|
|
|
|
this.ctxList.splice(curPageCount, deleteCount)
|
|
|
|
this.ctxList.splice(curPageCount, deleteCount)
|
|
|
|
this.pageList.splice(curPageCount, deleteCount)
|
|
|
|
this.pageList
|
|
|
|
|
|
|
|
.splice(curPageCount, deleteCount)
|
|
|
|
.forEach(page => page.remove())
|
|
|
|
.forEach(page => page.remove())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 绘制元素
|
|
|
|
// 绘制元素
|
|
|
|
@ -1572,14 +1728,17 @@ export class Draw {
|
|
|
|
if (positionContext.isTable) {
|
|
|
|
if (positionContext.isTable) {
|
|
|
|
const { index, trIndex, tdIndex } = positionContext
|
|
|
|
const { index, trIndex, tdIndex } = positionContext
|
|
|
|
const elementList = this.getOriginalElementList()
|
|
|
|
const elementList = this.getOriginalElementList()
|
|
|
|
const tablePositionList = elementList[index!].trList?.[trIndex!].tdList[tdIndex!].positionList
|
|
|
|
const tablePositionList =
|
|
|
|
|
|
|
|
elementList[index!].trList?.[trIndex!].tdList[tdIndex!].positionList
|
|
|
|
if (curIndex === undefined && tablePositionList) {
|
|
|
|
if (curIndex === undefined && tablePositionList) {
|
|
|
|
curIndex = tablePositionList.length - 1
|
|
|
|
curIndex = tablePositionList.length - 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const tablePosition = tablePositionList?.[curIndex!]
|
|
|
|
const tablePosition = tablePositionList?.[curIndex!]
|
|
|
|
this.position.setCursorPosition(tablePosition || null)
|
|
|
|
this.position.setCursorPosition(tablePosition || null)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
this.position.setCursorPosition(curIndex !== undefined ? positionList[curIndex] : null)
|
|
|
|
this.position.setCursorPosition(
|
|
|
|
|
|
|
|
curIndex !== undefined ? positionList[curIndex] : null
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.cursor.drawCursor()
|
|
|
|
this.cursor.drawCursor()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1631,5 +1790,4 @@ export class Draw {
|
|
|
|
this.scrollObserver.removeEvent()
|
|
|
|
this.scrollObserver.removeEvent()
|
|
|
|
this.selectionObserver.removeEvent()
|
|
|
|
this.selectionObserver.removeEvent()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|