feat: add print mode #236

pr675
Hufe921 3 years ago
parent b54b66d3d4
commit fd31b3e78c

@ -34,7 +34,7 @@ Feature: Gets the base64 string of the current page image
Usage: Usage:
```javascript ```javascript
const base64StringList = await instance.command.getImage(pixelRatio?: number) const base64StringList = await instance.command.getImage(option?: IGetImageOption)
``` ```
## getWordCount ## getWordCount

@ -14,7 +14,7 @@ new Editor(container, IEditorData | IElement[], {
```typescript ```typescript
interface IEditorOption { 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 defaultType?: string // Default element type. default: TEXT
defaultFont?: string // Default font. default: Yahei defaultFont?: string // Default font. default: Yahei
defaultSize?: number // Default font size. default: 16 defaultSize?: number // Default font size. default: 16

@ -34,7 +34,7 @@ const {
用法: 用法:
```javascript ```javascript
const base64StringList = await instance.command.getImage(pixelRatio?: number) const base64StringList = await instance.command.getImage(option?: IGetImageOption)
``` ```
## getWordCount ## getWordCount

@ -14,7 +14,7 @@ new Editor(container, IEditorData | IElement[], {
```typescript ```typescript
interface IEditorOption { interface IEditorOption {
mode?: EditorMode // 编辑器模式:编辑、清洁(不显示视觉辅助元素。如:分页符)、只读、表单(仅控件内可编辑)。默认:编辑 mode?: EditorMode // 编辑器模式:编辑、清洁(不显示视觉辅助元素。如:分页符)、只读、表单(仅控件内可编辑)、打印(不显示辅助元素、未书写控件及前后括号)。默认:编辑
defaultType?: string // 默认元素类型。默认TEXT defaultType?: string // 默认元素类型。默认TEXT
defaultFont?: string // 默认字体。默认Yahei defaultFont?: string // 默认字体。默认Yahei
defaultSize?: number // 默认字号。默认16 defaultSize?: number // 默认字号。默认16

@ -21,6 +21,7 @@ import { DeepRequired } from '../../interface/Common'
import { import {
IAppendElementListOption, IAppendElementListOption,
IDrawImagePayload, IDrawImagePayload,
IGetImageOption,
IGetValueOption, IGetValueOption,
IPainterOption IPainterOption
} from '../../interface/Draw' } from '../../interface/Draw'
@ -86,13 +87,7 @@ export class CommandAdapt {
} }
public mode(payload: EditorMode) { public mode(payload: EditorMode) {
const mode = this.draw.getMode()
if (mode === payload) return
this.draw.setMode(payload) this.draw.setMode(payload)
this.draw.render({
isSetCursor: false,
isSubmitHistory: false
})
} }
public cut() { public cut() {
@ -1648,7 +1643,10 @@ export class CommandAdapt {
} }
const width = this.draw.getOriginalWidth() const width = this.draw.getOriginalWidth()
const height = this.draw.getOriginalHeight() 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) printImageBase64(base64List, width, height)
if (scale !== 1) { if (scale !== 1) {
this.draw.setPageScale(scale) this.draw.setPageScale(scale)
@ -1685,8 +1683,8 @@ export class CommandAdapt {
}) })
} }
public getImage(pixelRatio?: number): Promise<string[]> { public getImage(payload?: IGetImageOption): Promise<string[]> {
return this.draw.getDataURL(pixelRatio) return this.draw.getDataURL(payload)
} }
public getValue(options?: IGetValueOption): IEditorResult { public getValue(options?: IGetValueOption): IEditorResult {

@ -6,6 +6,7 @@ import {
IDrawOption, IDrawOption,
IDrawPagePayload, IDrawPagePayload,
IDrawRowPayload, IDrawRowPayload,
IGetImageOption,
IGetValueOption, IGetValueOption,
IPainterOption IPainterOption
} from '../../interface/Draw' } from '../../interface/Draw'
@ -142,6 +143,7 @@ export class Draw {
private visiblePageNoList: number[] private visiblePageNoList: number[]
private intersectionPageNo: number private intersectionPageNo: number
private lazyRenderIntersectionObserver: IntersectionObserver | null private lazyRenderIntersectionObserver: IntersectionObserver | null
private printModeData: Required<IEditorData> | null
constructor( constructor(
rootContainer: HTMLElement, rootContainer: HTMLElement,
@ -217,6 +219,7 @@ export class Draw {
this.visiblePageNoList = [] this.visiblePageNoList = []
this.intersectionPageNo = 0 this.intersectionPageNo = 0
this.lazyRenderIntersectionObserver = null this.lazyRenderIntersectionObserver = null
this.printModeData = null
this.render({ this.render({
isInit: true, isInit: true,
@ -229,12 +232,34 @@ export class Draw {
} }
public setMode(payload: EditorMode) { 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.mode = payload
this.render({
isSetCursor: false,
isSubmitHistory: false
})
} }
public isReadonly() { public isReadonly() {
switch (this.mode) { switch (this.mode) {
case EditorMode.READONLY: case EditorMode.READONLY:
case EditorMode.PRINT:
return true return true
case EditorMode.FORM: case EditorMode.FORM:
return !this.control.isRangeWithinControl() return !this.control.isRangeWithinControl()
@ -650,10 +675,18 @@ export class Draw {
return this.rowList.length return this.rowList.length
} }
public async getDataURL(pixelRatio?: number): Promise<string[]> { public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {
const { pixelRatio, mode } = payload
// 放大像素比
if (pixelRatio) { if (pixelRatio) {
this.setPagePixelRatio(pixelRatio) this.setPagePixelRatio(pixelRatio)
} }
// 不同模式
const currentMode = this.mode
const isSwitchMode = !!mode && currentMode !== mode
if (isSwitchMode) {
this.setMode(mode)
}
this.render({ this.render({
isLazy: false, isLazy: false,
isCompute: false, isCompute: false,
@ -662,9 +695,13 @@ export class Draw {
}) })
await this.imageObserver.allSettled() await this.imageObserver.allSettled()
const dataUrlList = this.pageList.map(c => c.toDataURL()) const dataUrlList = this.pageList.map(c => c.toDataURL())
// 还原
if (pixelRatio) { if (pixelRatio) {
this.setPagePixelRatio(null) this.setPagePixelRatio(null)
} }
if (isSwitchMode) {
this.setMode(currentMode)
}
return dataUrlList return dataUrlList
} }
@ -869,29 +906,36 @@ export class Draw {
public setValue(payload: Partial<IEditorData>) { public setValue(payload: Partial<IEditorData>) {
const { header, main, footer } = payload const { header, main, footer } = payload
if (!header && !main && !footer) return if (!header && !main && !footer) return
if (header) { const pageComponentData = [header, main, footer]
formatElementList(header, { pageComponentData.forEach(data => {
if (!data) return
formatElementList(data, {
editorOptions: this.options editorOptions: this.options
}) })
})
this.setEditorData({
header,
main,
footer
})
// 渲染&计算&清空历史记录
this.historyManager.recovery()
this.render({
isSetCursor: false
})
}
public setEditorData(payload: Partial<IEditorData>) {
const { header, main, footer } = payload
if (header) {
this.header.setElementList(header) this.header.setElementList(header)
} }
if (main) { if (main) {
formatElementList(main, {
editorOptions: this.options
})
this.elementList = main this.elementList = main
} }
if (footer) { if (footer) {
formatElementList(footer, {
editorOptions: this.options
})
this.footer.setElementList(footer) this.footer.setElementList(footer)
} }
// 渲染&计算&清空历史记录
this.historyManager.recovery()
this.render({
isSetCursor: false
})
} }
private _wrapContainer(rootContainer: HTMLElement): HTMLDivElement { private _wrapContainer(rootContainer: HTMLElement): HTMLDivElement {
@ -1398,6 +1442,7 @@ export class Draw {
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) { public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
const { rowList, pageNo, elementList, positionList, startIndex, zone } = const { rowList, pageNo, elementList, positionList, startIndex, zone } =
payload payload
const isPrintMode = this.mode === EditorMode.PRINT
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
@ -1472,7 +1517,7 @@ export class Draw {
} else if (element.type === ElementType.SEPARATOR) { } else if (element.type === ElementType.SEPARATOR) {
this.separatorParticle.render(ctx, element, x, y) this.separatorParticle.render(ctx, element, x, y)
} else if (element.type === ElementType.PAGE_BREAK) { } 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) this.pageBreakParticle.render(ctx, element, x, y)
} }
} else if ( } else if (
@ -1592,21 +1637,23 @@ export class Draw {
// 绘制富文本及文字 // 绘制富文本及文字
this._drawRichText(ctx) this._drawRichText(ctx)
// 绘制选区 // 绘制选区
if (rangeRecord.width && rangeRecord.height) { if (!isPrintMode) {
const { x, y, width, height } = rangeRecord if (rangeRecord.width && rangeRecord.height) {
this.range.render(ctx, x, y, width, height) const { x, y, width, height } = rangeRecord
} this.range.render(ctx, x, y, width, height)
if ( }
isCrossRowCol && if (
tableRangeElement && isCrossRowCol &&
tableRangeElement.id === tableId tableRangeElement &&
) { tableRangeElement.id === tableId
const { ) {
coordinate: { const {
leftTop: [x, y] coordinate: {
} leftTop: [x, y]
} = positionList[curRow.startIndex] }
this.tableParticle.drawRange(ctx, tableRangeElement, x, y) } = positionList[curRow.startIndex]
this.tableParticle.drawRange(ctx, tableRangeElement, x, y)
}
} }
} }
} }

@ -6,6 +6,7 @@ import {
IControlInstance, IControlInstance,
IControlOption IControlOption
} from '../../../interface/Control' } from '../../../interface/Control'
import { IEditorData } from '../../../interface/Editor'
import { IElement, IElementPosition } from '../../../interface/Element' import { IElement, IElementPosition } from '../../../interface/Element'
import { EventBusMap } from '../../../interface/EventBus' import { EventBusMap } from '../../../interface/EventBus'
import { IRange } from '../../../interface/Range' import { IRange } from '../../../interface/Range'
@ -49,6 +50,24 @@ export class Control {
return this.draw return this.draw
} }
// 过滤控件辅助元素(前后缀、背景提示)
public filterAssistElement(
payload: Required<IEditorData>
): Required<IEditorData> {
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 { public isPartRangeInControlOutside(): boolean {
const { startIndex, endIndex } = this.getRange() const { startIndex, endIndex } = this.getRange()

@ -14,10 +14,11 @@ export enum EditorContext {
} }
export enum EditorMode { export enum EditorMode {
EDIT = 'edit', EDIT = 'edit', // 编辑模式(文档可编辑、辅助元素均存在)
CLEAN = 'clean', CLEAN = 'clean', // 清洁模式(隐藏辅助元素)
READONLY = 'readonly', READONLY = 'readonly', // 只读模式(文档不可编辑)
FORM = 'form' FORM = 'form', // 表单模式(仅控件内可编辑)
PRINT = 'print' // 打印模式(文档不可编辑、隐藏辅助元素、选区、未书写控件及边框)
} }
export enum EditorZone { export enum EditorZone {

@ -1,4 +1,4 @@
import { EditorZone } from '../dataset/enum/Editor' import { EditorMode, EditorZone } from '../dataset/enum/Editor'
import { IElement, IElementPosition } from './Element' import { IElement, IElementPosition } from './Element'
import { IRow } from './Row' import { IRow } from './Row'
@ -45,3 +45,8 @@ export interface IGetValueOption {
export interface IAppendElementListOption { export interface IAppendElementListOption {
isPrepend?: boolean isPrepend?: boolean
} }
export interface IGetImageOption {
pixelRatio?: number
mode?: EditorMode
}

@ -1208,6 +1208,10 @@ window.onload = function () {
{ {
mode: EditorMode.FORM, mode: EditorMode.FORM,
name: '表单模式' name: '表单模式'
},
{
mode: EditorMode.PRINT,
name: '打印模式'
} }
] ]
const modeElement = document.querySelector<HTMLDivElement>('.editor-mode')! const modeElement = document.querySelector<HTMLDivElement>('.editor-mode')!

Loading…
Cancel
Save