diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index dae5ec9..d17655b 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -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 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, - 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((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() // 位置信息 diff --git a/src/editor/core/draw/frame/Header.ts b/src/editor/core/draw/frame/Header.ts index 9650499..e4b6970 100644 --- a/src/editor/core/draw/frame/Header.ts +++ b/src/editor/core/draw/frame/Header.ts @@ -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 + private elementList: IElement[] + private rowList: IRow[] + private positionList: IElementPosition[] + constructor(draw: Draw) { this.draw = draw - this.options = >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 + }) } } \ No newline at end of file diff --git a/src/editor/core/position/Position.ts b/src/editor/core/position/Position.ts index 63eed8c..38770a7 100644 --- a/src/editor/core/position/Position.ts +++ b/src/editor/core/position/Position.ts @@ -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 diff --git a/src/editor/dataset/constant/Header.ts b/src/editor/dataset/constant/Header.ts index 6923088..4fbc78b 100644 --- a/src/editor/dataset/constant/Header.ts +++ b/src/editor/dataset/constant/Header.ts @@ -1,8 +1,7 @@ import { IHeader } from '../../interface/Header' +import { HeaderMaxHeightRatio } from '../enum/Header' export const defaultHeaderOption: Readonly> = { - data: '', - color: '#AAAAAA', - size: 14, - font: 'Yahei' + top: -50, + maxHeightRadio: HeaderMaxHeightRatio.HALF } \ No newline at end of file diff --git a/src/editor/dataset/enum/Editor.ts b/src/editor/dataset/enum/Editor.ts index c8c08e0..74af9ea 100644 --- a/src/editor/dataset/enum/Editor.ts +++ b/src/editor/dataset/enum/Editor.ts @@ -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' diff --git a/src/editor/dataset/enum/Header.ts b/src/editor/dataset/enum/Header.ts new file mode 100644 index 0000000..71c69d1 --- /dev/null +++ b/src/editor/dataset/enum/Header.ts @@ -0,0 +1,5 @@ +export enum HeaderMaxHeightRatio { + HALF = 'half', + ONE_THIRD = 'one-third', + QUARTER = 'quarter' +} \ No newline at end of file diff --git a/src/editor/index.ts b/src/editor/index.ts index 194619d..1c421c3 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -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 = { ...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)) // 菜单 diff --git a/src/editor/interface/Editor.ts b/src/editor/interface/Editor.ts index ed7f45e..db0fb39 100644 --- a/src/editor/interface/Editor.ts +++ b/src/editor/interface/Editor.ts @@ -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; } \ No newline at end of file diff --git a/src/editor/interface/Header.ts b/src/editor/interface/Header.ts index 10b85f9..c188b03 100644 --- a/src/editor/interface/Header.ts +++ b/src/editor/interface/Header.ts @@ -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; } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index adc1f4e..11fe326 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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('.editor')! - const instance = new Editor(container, data, options) + const instance = new Editor( + container, + { + header: [{ + value: '人民医院门诊', + size: 14, + color: '#AAAAAA', + rowFlex: RowFlex.CENTER + }], + main: data + }, + options + ) console.log('实例: ', instance) // cypress使用 Reflect.set(window, 'editor', instance) diff --git a/src/mock.ts b/src/mock.ts index 0924fcc..c7da542 100644 --- a/src/mock.ts +++ b/src/mock.ts @@ -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