feat: add print mode #236
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user