feat: add print mode #236

This commit is contained in:
Hufe921
2023-08-10 23:56:50 +08:00
parent b54b66d3d4
commit fd31b3e78c
10 changed files with 125 additions and 51 deletions
+7 -9
View File
@@ -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<string[]> {
return this.draw.getDataURL(pixelRatio)
public getImage(payload?: IGetImageOption): Promise<string[]> {
return this.draw.getDataURL(payload)
}
public getValue(options?: IGetValueOption): IEditorResult {
+80 -33
View File
@@ -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<IEditorData> | 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<string[]> {
public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {
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,24 +906,18 @@ export class Draw {
public setValue(payload: Partial<IEditorData>) {
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.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.setEditorData({
header,
main,
footer
})
// 渲染&计算&清空历史记录
this.historyManager.recovery()
this.render({
@@ -894,6 +925,19 @@ export class Draw {
})
}
public setEditorData(payload: Partial<IEditorData>) {
const { header, main, footer } = payload
if (header) {
this.header.setElementList(header)
}
if (main) {
this.elementList = main
}
if (footer) {
this.footer.setElementList(footer)
}
}
private _wrapContainer(rootContainer: HTMLElement): HTMLDivElement {
const container = document.createElement('div')
rootContainer.append(container)
@@ -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)
}
}
}
}
+19
View File
@@ -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<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 {
const { startIndex, endIndex } = this.getRange()
+5 -4
View File
@@ -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 {
+6 -1
View File
@@ -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
}
+4
View File
@@ -1208,6 +1208,10 @@ window.onload = function () {
{
mode: EditorMode.FORM,
name: '表单模式'
},
{
mode: EditorMode.PRINT,
name: '打印模式'
}
]
const modeElement = document.querySelector<HTMLDivElement>('.editor-mode')!