feat:render header element

pr675
Hufe921 3 years ago
parent 8eee356787
commit da2dfd3a16

@ -2,7 +2,7 @@ import { version } from '../../../../package.json'
import { ZERO } from '../../dataset/constant/Common'
import { RowFlex } from '../../dataset/enum/Row'
import { IDrawOption, IDrawRowPayload, IPainterOptions } from '../../interface/Draw'
import { IEditorOption, IEditorResult } from '../../interface/Editor'
import { IEditorDrawData, IEditorOption, IEditorResult } from '../../interface/Editor'
import { IElement, IElementMetrics, IElementPosition, IElementFillRect, IElementStyle } from '../../interface/Element'
import { IRow, IRowElement } from '../../interface/Row'
import { deepClone, getUUID, nextTick } from '../../utils'
@ -61,7 +61,9 @@ export class Draw {
private mode: EditorMode
private options: DeepRequired<IEditorOption>
private position: Position
private headerElementList: IElement[]
private elementList: IElement[]
private footerElementList: IElement[]
private listener: Listener
private i18n: I18n
@ -110,7 +112,7 @@ export class Draw {
constructor(
rootContainer: HTMLElement,
options: DeepRequired<IEditorOption>,
elementList: IElement[],
data: IEditorDrawData,
listener: Listener
) {
this.container = this._wrapContainer(rootContainer)
@ -119,7 +121,9 @@ export class Draw {
this.pageNo = 0
this.mode = options.mode
this.options = options
this.elementList = elementList
this.headerElementList = data.header || []
this.elementList = data.main
this.footerElementList = data.footer || []
this.listener = listener
this._formatContainer()
@ -343,6 +347,10 @@ export class Draw {
return this.range
}
public getHeaderElementList(): IElement[] {
return this.headerElementList
}
public getElementList(): IElement[] {
const positionContext = this.position.getPositionContext()
if (positionContext.isTable) {
@ -352,6 +360,10 @@ export class Draw {
return this.elementList
}
public getFooterElementList(): IElement[] {
return this.footerElementList
}
public insertElementList(payload: IElement[]) {
if (!payload.length) return
const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside()
@ -596,15 +608,17 @@ export class Draw {
public getValue(): IEditorResult {
// 配置
const { width, height, margins, watermark, header } = this.options
const { width, height, margins, watermark } = this.options
// 数据
const data = zipElementList(this.elementList)
const data: IEditorDrawData = {
header: zipElementList(this.headerElementList),
main: zipElementList(this.elementList)
}
return {
version,
width,
height,
margins,
header: header.data ? header : undefined,
watermark: watermark.data ? watermark : undefined,
data
}
@ -670,7 +684,7 @@ export class Draw {
return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${size * scale}px ${font}`
}
private _computeRowList(innerWidth: number, elementList: IElement[]) {
public computeRowList(innerWidth: number, elementList: IElement[]) {
const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } = this.options
const defaultBasicRowMarginHeight = this.getDefaultBasicRowMarginHeight()
const canvas = document.createElement('canvas')
@ -726,7 +740,7 @@ export class Draw {
let maxTrHeight = 0
for (let d = 0; d < tr.tdList.length; 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)
td.rowList = rowList
// 移除缩放导致的行高变化-渲染时会进行缩放调整
@ -964,7 +978,7 @@ export class Draw {
this.textParticle.complete()
}
private _drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
const { rowList, pageNo, positionList, startIndex } = payload
const { scale, tdPadding } = this.options
const { isCrossRowCol, tableId } = this.range.getRange()
@ -1104,7 +1118,7 @@ export class Draw {
const tr = element.trList![t]
for (let d = 0; d < tr.tdList!.length; d++) {
const td = tr.tdList[d]
this._drawRow(ctx, {
this.drawRow(ctx, {
positionList: td.positionList!,
rowList: td.rowList!,
pageNo,
@ -1147,7 +1161,7 @@ export class Draw {
this.margin.render(ctx, pageNo)
// 渲染元素
const index = rowList[0].startIndex
this._drawRow(ctx, {
this.drawRow(ctx, {
positionList,
rowList,
pageNo,
@ -1175,6 +1189,7 @@ export class Draw {
entries.forEach(entry => {
if (entry.isIntersecting) {
const index = Number((<HTMLCanvasElement>entry.target).dataset.index)
this.header.render(this.ctxList[index])
this._drawPage(positionList, this.pageRowList[index], index)
}
})
@ -1203,8 +1218,10 @@ export class Draw {
const innerWidth = this.getInnerWidth()
// 计算文档信息
if (isCompute) {
// 页眉信息
this.header.compute()
// 行信息
this.rowList = this._computeRowList(innerWidth, this.elementList)
this.rowList = this.computeRowList(innerWidth, this.elementList)
// 页面信息
this.pageRowList = this._computePageList()
// 位置信息

@ -1,31 +1,72 @@
import { DeepRequired } from '../../../interface/Common'
import { IEditorOption } from '../../../interface/Editor'
import { IElement, IElementPosition } from '../../../interface/Element'
import { IRow } from '../../../interface/Row'
import { Position } from '../../position/Position'
import { Draw } from '../Draw'
export class Header {
private draw: Draw
private position: Position
private options: DeepRequired<IEditorOption>
private elementList: IElement[]
private rowList: IRow[]
private positionList: IElementPosition[]
constructor(draw: Draw) {
this.draw = draw
this.options = <DeepRequired<IEditorOption>>draw.getOptions()
this.position = draw.getPosition()
this.options = draw.getOptions()
this.elementList = draw.getHeaderElementList()
this.rowList = []
this.positionList = []
}
public compute() {
this._recovery()
this._computeRowList()
this._computePositionList()
}
private _recovery() {
this.rowList = []
this.positionList = []
}
private _computeRowList() {
const innerWidth = this.draw.getInnerWidth()
this.rowList = this.draw.computeRowList(innerWidth, this.elementList)
}
private _computePositionList() {
const { header: { top } } = this.options
const innerWidth = this.draw.getInnerWidth()
const margins = this.draw.getMargins()
const startX = margins[3]
const startY = margins[0] + top
this.position.computePageRowPosition({
positionList: this.positionList,
rowList: this.rowList,
pageNo: 0,
startIndex: 0,
startX,
startY,
innerWidth
})
}
public render(ctx: CanvasRenderingContext2D) {
const { header: { data, size, color, font }, scale } = this.options
if (!data) return
const width = this.draw.getWidth()
const top = this.draw.getHeaderTop()
ctx.save()
ctx.fillStyle = color
ctx.font = `${size! * scale}px ${font}`
// 文字长度
const textWidth = ctx.measureText(`${data}`).width
// 偏移量
const left = (width - textWidth) / 2
ctx.fillText(`${data}`, left < 0 ? 0 : left, top)
ctx.restore()
const innerWidth = this.draw.getInnerWidth()
this.draw.drawRow(ctx, {
positionList: this.positionList,
rowList: this.rowList,
pageNo: 0,
startIndex: 0,
innerWidth
})
}
}

@ -46,7 +46,7 @@ export class Position {
this.positionList = payload
}
private computePageRowPosition(payload: IComputePageRowPositionPayload): IComputePageRowPositionResult {
public computePageRowPosition(payload: IComputePageRowPositionPayload): IComputePageRowPositionResult {
const { positionList, rowList, pageNo, startX, startY, startIndex, innerWidth } = payload
const { scale, tdPadding } = this.options
let x = startX

@ -1,8 +1,7 @@
import { IHeader } from '../../interface/Header'
import { HeaderMaxHeightRatio } from '../enum/Header'
export const defaultHeaderOption: Readonly<Required<IHeader>> = {
data: '',
color: '#AAAAAA',
size: 14,
font: 'Yahei'
top: -50,
maxHeightRadio: HeaderMaxHeightRatio.HALF
}

@ -18,6 +18,12 @@ export enum EditorMode {
READONLY = 'readonly'
}
export enum EditorZone {
HEADER = 'header',
MAIN = 'main',
FOOTER = 'footer'
}
export enum PageMode {
PAGING = 'paging',
CONTINUITY = 'continuity'

@ -0,0 +1,5 @@
export enum HeaderMaxHeightRatio {
HALF = 'half',
ONE_THIRD = 'one-third',
QUARTER = 'quarter'
}

@ -1,5 +1,5 @@
import './assets/css/index.css'
import { IEditorOption, IEditorResult } from './interface/Editor'
import { IEditorData, IEditorOption, IEditorResult } from './interface/Editor'
import { IElement } from './interface/Element'
import { Draw } from './core/draw/Draw'
import { Command } from './core/command/Command'
@ -39,7 +39,7 @@ export default class Editor {
public register: Register
public destroy: Function
constructor(container: HTMLDivElement, elementList: IElement[], options: IEditorOption = {}) {
constructor(container: HTMLDivElement, data: IEditorData, options: IEditorOption = {}) {
const headerOptions: Required<IHeader> = {
...defaultHeaderOption,
...options.header
@ -103,13 +103,33 @@ export default class Editor {
checkbox: checkboxOptions,
cursor: cursorOptions
}
formatElementList(elementList, {
// 数据处理
let headerElementList: IElement[] = []
let mainElementList: IElement[] = []
if (Array.isArray(data)) {
mainElementList = data
} else {
headerElementList = data.header || []
mainElementList = data.main
}
formatElementList(headerElementList, {
editorOptions
})
formatElementList(mainElementList, {
editorOptions
})
// 监听
this.listener = new Listener()
// 启动
const draw = new Draw(container, editorOptions, elementList, this.listener)
const draw = new Draw(
container,
editorOptions,
{
header: headerElementList,
main: mainElementList
},
this.listener
)
// 命令
this.command = new Command(new CommandAdapt(draw))
// 菜单

@ -7,6 +7,14 @@ import { IHeader } from './Header'
import { IMargin } from './Margin'
import { IWatermark } from './Watermark'
export interface IEditorDrawData {
header?: IElement[];
main: IElement[];
footer?: IElement[];
}
export type IEditorData = IEditorDrawData | IElement[]
export interface IEditorOption {
mode?: EditorMode;
defaultType?: string;
@ -54,7 +62,6 @@ export interface IEditorResult {
width: number;
height: number;
margins: IMargin;
header?: IHeader;
watermark?: IWatermark;
data: IElement[];
data: IEditorData;
}

@ -1,6 +1,6 @@
import { HeaderMaxHeightRatio } from '../dataset/enum/Header'
export interface IHeader {
data: string;
color?: string;
size?: number;
font?: string;
top?: number;
maxHeightRadio?: HeaderMaxHeightRatio;
}

@ -1,7 +1,7 @@
import { data, options } from './mock'
import './style.css'
import prism from 'prismjs'
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, IElement, KeyMap, PageMode, PaperDirection } from './editor'
import Editor, { BlockType, Command, ControlType, EditorMode, ElementType, IBlock, IElement, KeyMap, PageMode, PaperDirection, RowFlex } from './editor'
import { Dialog } from './components/dialog/Dialog'
import { formatPrismToken } from './utils/prism'
import { Signature } from './components/signature/Signature'
@ -11,7 +11,19 @@ window.onload = function () {
// 1. 初始化编辑器
const container = document.querySelector<HTMLDivElement>('.editor')!
const instance = new Editor(container, <IElement[]>data, options)
const instance = new Editor(
container,
{
header: [{
value: '人民医院门诊',
size: 14,
color: '#AAAAAA',
rowFlex: RowFlex.CENTER
}],
main: <IElement[]>data
},
options
)
console.log('实例: ', instance)
// cypress使用
Reflect.set(window, 'editor', instance)

@ -312,9 +312,6 @@ export const data: IElement[] = elementList
export const options: IEditorOption = {
margins: [100, 120, 100, 120],
header: {
data: '人民医院门诊'
},
watermark: {
data: 'CANVAS-EDITOR',
size: 120

Loading…
Cancel
Save