diff --git a/docs/en/guide/command-get.md b/docs/en/guide/command-get.md index bbfa8c3..96f633b 100644 --- a/docs/en/guide/command-get.md +++ b/docs/en/guide/command-get.md @@ -34,7 +34,7 @@ Feature: Gets the base64 string of the current page image Usage: ```javascript -const base64StringList = await instance.command.getImage(pixelRatio?: number) +const base64StringList = await instance.command.getImage(option?: IGetImageOption) ``` ## getWordCount diff --git a/docs/en/guide/option.md b/docs/en/guide/option.md index 1f18adc..329d051 100644 --- a/docs/en/guide/option.md +++ b/docs/en/guide/option.md @@ -14,7 +14,7 @@ new Editor(container, IEditorData | IElement[], { ```typescript interface IEditorOption { - mode?: EditorMode // Editor mode: Edit, Clean (Visual aids are not displayed, For example: page break), ReadOnly, Form (Only editable within the control). default: Edit + mode?: EditorMode // Editor mode: Edit, Clean (Visual aids are not displayed, For example: page break), ReadOnly, Form (Only editable within the control), Print (Visual aids are not displayed, Unwritten content control). default: Edit defaultType?: string // Default element type. default: TEXT defaultFont?: string // Default font. default: Yahei defaultSize?: number // Default font size. default: 16 diff --git a/docs/guide/command-get.md b/docs/guide/command-get.md index 720079b..bdeaf55 100644 --- a/docs/guide/command-get.md +++ b/docs/guide/command-get.md @@ -34,7 +34,7 @@ const { 用法: ```javascript -const base64StringList = await instance.command.getImage(pixelRatio?: number) +const base64StringList = await instance.command.getImage(option?: IGetImageOption) ``` ## getWordCount diff --git a/docs/guide/option.md b/docs/guide/option.md index 2da8288..7b5eaea 100644 --- a/docs/guide/option.md +++ b/docs/guide/option.md @@ -14,7 +14,7 @@ new Editor(container, IEditorData | IElement[], { ```typescript interface IEditorOption { - mode?: EditorMode // 编辑器模式:编辑、清洁(不显示视觉辅助元素。如:分页符)、只读、表单(仅控件内可编辑)。默认:编辑 + mode?: EditorMode // 编辑器模式:编辑、清洁(不显示视觉辅助元素。如:分页符)、只读、表单(仅控件内可编辑)、打印(不显示辅助元素、未书写控件及前后括号)。默认:编辑 defaultType?: string // 默认元素类型。默认:TEXT defaultFont?: string // 默认字体。默认:Yahei defaultSize?: number // 默认字号。默认:16 diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index c793ca8..7e00da7 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -21,6 +21,7 @@ import { DeepRequired } from '../../interface/Common' import { IAppendElementListOption, IDrawImagePayload, + IGetImageOption, IGetValueOption, IPainterOption } from '../../interface/Draw' @@ -86,13 +87,7 @@ export class CommandAdapt { } public mode(payload: EditorMode) { - const mode = this.draw.getMode() - if (mode === payload) return this.draw.setMode(payload) - this.draw.render({ - isSetCursor: false, - isSubmitHistory: false - }) } public cut() { @@ -1648,7 +1643,10 @@ export class CommandAdapt { } const width = this.draw.getOriginalWidth() const height = this.draw.getOriginalHeight() - const base64List = await this.draw.getDataURL(printPixelRatio) + const base64List = await this.draw.getDataURL({ + pixelRatio: printPixelRatio, + mode: EditorMode.PRINT + }) printImageBase64(base64List, width, height) if (scale !== 1) { this.draw.setPageScale(scale) @@ -1685,8 +1683,8 @@ export class CommandAdapt { }) } - public getImage(pixelRatio?: number): Promise { - return this.draw.getDataURL(pixelRatio) + public getImage(payload?: IGetImageOption): Promise { + return this.draw.getDataURL(payload) } public getValue(options?: IGetValueOption): IEditorResult { diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 2db8be4..5417244 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -6,6 +6,7 @@ import { IDrawOption, IDrawPagePayload, IDrawRowPayload, + IGetImageOption, IGetValueOption, IPainterOption } from '../../interface/Draw' @@ -142,6 +143,7 @@ export class Draw { private visiblePageNoList: number[] private intersectionPageNo: number private lazyRenderIntersectionObserver: IntersectionObserver | null + private printModeData: Required | null constructor( rootContainer: HTMLElement, @@ -217,6 +219,7 @@ export class Draw { this.visiblePageNoList = [] this.intersectionPageNo = 0 this.lazyRenderIntersectionObserver = null + this.printModeData = null this.render({ isInit: true, @@ -229,12 +232,34 @@ export class Draw { } public setMode(payload: EditorMode) { + if (this.mode === payload) return + // 设置打印模式 + if (payload === EditorMode.PRINT) { + this.printModeData = { + header: this.header.getElementList(), + main: this.elementList, + footer: this.footer.getElementList() + } + this.setEditorData( + this.control.filterAssistElement(deepClone(this.printModeData)) + ) + } + // 取消打印模式 + if (this.mode === EditorMode.PRINT && this.printModeData) { + this.setEditorData(this.printModeData) + this.printModeData = null + } this.mode = payload + this.render({ + isSetCursor: false, + isSubmitHistory: false + }) } public isReadonly() { switch (this.mode) { case EditorMode.READONLY: + case EditorMode.PRINT: return true case EditorMode.FORM: return !this.control.isRangeWithinControl() @@ -650,10 +675,18 @@ export class Draw { return this.rowList.length } - public async getDataURL(pixelRatio?: number): Promise { + public async getDataURL(payload: IGetImageOption = {}): Promise { + const { pixelRatio, mode } = payload + // 放大像素比 if (pixelRatio) { this.setPagePixelRatio(pixelRatio) } + // 不同模式 + const currentMode = this.mode + const isSwitchMode = !!mode && currentMode !== mode + if (isSwitchMode) { + this.setMode(mode) + } this.render({ isLazy: false, isCompute: false, @@ -662,9 +695,13 @@ export class Draw { }) await this.imageObserver.allSettled() const dataUrlList = this.pageList.map(c => c.toDataURL()) + // 还原 if (pixelRatio) { this.setPagePixelRatio(null) } + if (isSwitchMode) { + this.setMode(currentMode) + } return dataUrlList } @@ -869,29 +906,36 @@ export class Draw { public setValue(payload: Partial) { const { header, main, footer } = payload if (!header && !main && !footer) return - if (header) { - formatElementList(header, { + const pageComponentData = [header, main, footer] + pageComponentData.forEach(data => { + if (!data) return + formatElementList(data, { editorOptions: this.options }) + }) + this.setEditorData({ + header, + main, + footer + }) + // 渲染&计算&清空历史记录 + this.historyManager.recovery() + this.render({ + isSetCursor: false + }) + } + + public setEditorData(payload: Partial) { + const { header, main, footer } = payload + if (header) { this.header.setElementList(header) } if (main) { - formatElementList(main, { - editorOptions: this.options - }) this.elementList = main } if (footer) { - formatElementList(footer, { - editorOptions: this.options - }) this.footer.setElementList(footer) } - // 渲染&计算&清空历史记录 - this.historyManager.recovery() - this.render({ - isSetCursor: false - }) } private _wrapContainer(rootContainer: HTMLElement): HTMLDivElement { @@ -1398,6 +1442,7 @@ export class Draw { public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) { const { rowList, pageNo, elementList, positionList, startIndex, zone } = payload + const isPrintMode = this.mode === EditorMode.PRINT const { scale, tdPadding } = this.options const { isCrossRowCol, tableId } = this.range.getRange() let index = startIndex @@ -1472,7 +1517,7 @@ export class Draw { } else if (element.type === ElementType.SEPARATOR) { this.separatorParticle.render(ctx, element, x, y) } else if (element.type === ElementType.PAGE_BREAK) { - if (this.mode !== EditorMode.CLEAN) { + if (this.mode !== EditorMode.CLEAN && !isPrintMode) { this.pageBreakParticle.render(ctx, element, x, y) } } else if ( @@ -1592,21 +1637,23 @@ export class Draw { // 绘制富文本及文字 this._drawRichText(ctx) // 绘制选区 - if (rangeRecord.width && rangeRecord.height) { - const { x, y, width, height } = rangeRecord - this.range.render(ctx, x, y, width, height) - } - if ( - isCrossRowCol && - tableRangeElement && - tableRangeElement.id === tableId - ) { - const { - coordinate: { - leftTop: [x, y] - } - } = positionList[curRow.startIndex] - this.tableParticle.drawRange(ctx, tableRangeElement, x, y) + if (!isPrintMode) { + if (rangeRecord.width && rangeRecord.height) { + const { x, y, width, height } = rangeRecord + this.range.render(ctx, x, y, width, height) + } + if ( + isCrossRowCol && + tableRangeElement && + tableRangeElement.id === tableId + ) { + const { + coordinate: { + leftTop: [x, y] + } + } = positionList[curRow.startIndex] + this.tableParticle.drawRange(ctx, tableRangeElement, x, y) + } } } } diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index 4d390e4..b8f1704 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -6,6 +6,7 @@ import { IControlInstance, IControlOption } from '../../../interface/Control' +import { IEditorData } from '../../../interface/Editor' import { IElement, IElementPosition } from '../../../interface/Element' import { EventBusMap } from '../../../interface/EventBus' import { IRange } from '../../../interface/Range' @@ -49,6 +50,24 @@ export class Control { return this.draw } + // 过滤控件辅助元素(前后缀、背景提示) + public filterAssistElement( + payload: Required + ): Required { + const editorDataKeys: (keyof IEditorData)[] = ['header', 'main', 'footer'] + editorDataKeys.forEach(key => { + payload[key] = payload[key].filter(element => { + if (element.type !== ElementType.CONTROL) return true + return ( + element.controlComponent !== ControlComponent.PREFIX && + element.controlComponent !== ControlComponent.POSTFIX && + element.controlComponent !== ControlComponent.PLACEHOLDER + ) + }) + }) + return payload + } + // 判断选区部分在控件边界外 public isPartRangeInControlOutside(): boolean { const { startIndex, endIndex } = this.getRange() diff --git a/src/editor/dataset/enum/Editor.ts b/src/editor/dataset/enum/Editor.ts index 0c74645..175f4e9 100644 --- a/src/editor/dataset/enum/Editor.ts +++ b/src/editor/dataset/enum/Editor.ts @@ -14,10 +14,11 @@ export enum EditorContext { } export enum EditorMode { - EDIT = 'edit', - CLEAN = 'clean', - READONLY = 'readonly', - FORM = 'form' + EDIT = 'edit', // 编辑模式(文档可编辑、辅助元素均存在) + CLEAN = 'clean', // 清洁模式(隐藏辅助元素) + READONLY = 'readonly', // 只读模式(文档不可编辑) + FORM = 'form', // 表单模式(仅控件内可编辑) + PRINT = 'print' // 打印模式(文档不可编辑、隐藏辅助元素、选区、未书写控件及边框) } export enum EditorZone { diff --git a/src/editor/interface/Draw.ts b/src/editor/interface/Draw.ts index 6b1cf20..0cf79ed 100644 --- a/src/editor/interface/Draw.ts +++ b/src/editor/interface/Draw.ts @@ -1,4 +1,4 @@ -import { EditorZone } from '../dataset/enum/Editor' +import { EditorMode, EditorZone } from '../dataset/enum/Editor' import { IElement, IElementPosition } from './Element' import { IRow } from './Row' @@ -45,3 +45,8 @@ export interface IGetValueOption { export interface IAppendElementListOption { isPrepend?: boolean } + +export interface IGetImageOption { + pixelRatio?: number + mode?: EditorMode +} diff --git a/src/main.ts b/src/main.ts index 2981c59..e32f3c7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1208,6 +1208,10 @@ window.onload = function () { { mode: EditorMode.FORM, name: '表单模式' + }, + { + mode: EditorMode.PRINT, + name: '打印模式' } ] const modeElement = document.querySelector('.editor-mode')!