feat:edit page header

pr675
Hufe921 3 years ago
parent da2dfd3a16
commit 6082ab26d1

@ -62,8 +62,9 @@ export class Cursor {
// 设置光标代理
const height = this.draw.getHeight()
const pageGap = this.draw.getPageGap()
const { metrics, coordinate: { leftTop, rightTop }, ascent, pageNo } = cursorPosition
const preY = pageNo * (height + pageGap)
const { metrics, coordinate: { leftTop, rightTop }, ascent } = cursorPosition
const curPageNo = this.draw.getPageNo()
const preY = curPageNo * (height + pageGap)
// 增加1/4字体大小
const offsetHeight = metrics.height / 4
const cursorHeight = metrics.height + offsetHeight * 2

@ -1,9 +1,9 @@
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 { IEditorDrawData, IEditorOption, IEditorResult } from '../../interface/Editor'
import { IElement, IElementMetrics, IElementPosition, IElementFillRect, IElementStyle } from '../../interface/Element'
import { IDrawOption, IDrawPagePayload, IDrawRowPayload, IPainterOptions } from '../../interface/Draw'
import { IEditorData, IEditorOption, IEditorResult } from '../../interface/Editor'
import { IElement, IElementMetrics, IElementFillRect, IElementStyle } from '../../interface/Element'
import { IRow, IRowElement } from '../../interface/Row'
import { deepClone, getUUID, nextTick } from '../../utils'
import { Cursor } from '../cursor/Cursor'
@ -35,7 +35,7 @@ import { SubscriptParticle } from './particle/Subscript'
import { SeparatorParticle } from './particle/Separator'
import { PageBreakParticle } from './particle/PageBreak'
import { Watermark } from './frame/Watermark'
import { EditorComponent, EditorMode, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { EditorComponent, EditorMode, EditorZone, PageMode, PaperDirection } from '../../dataset/enum/Editor'
import { Control } from './control/Control'
import { zipElementList } from '../../utils/element'
import { CheckboxParticle } from './particle/CheckboxParticle'
@ -50,6 +50,7 @@ import { BlockParticle } from './particle/block/BlockParticle'
import { EDITOR_COMPONENT, EDITOR_PREFIX } from '../../dataset/constant/Editor'
import { I18n } from '../i18n/I18n'
import { ImageObserver } from '../observer/ImageObserver'
import { Zone } from '../zone/Zone'
export class Draw {
@ -61,6 +62,7 @@ export class Draw {
private mode: EditorMode
private options: DeepRequired<IEditorOption>
private position: Position
private zone: Zone
private headerElementList: IElement[]
private elementList: IElement[]
private footerElementList: IElement[]
@ -112,7 +114,7 @@ export class Draw {
constructor(
rootContainer: HTMLElement,
options: DeepRequired<IEditorOption>,
data: IEditorDrawData,
data: IEditorData,
listener: Listener
) {
this.container = this._wrapContainer(rootContainer)
@ -133,6 +135,7 @@ export class Draw {
this.i18n = new I18n()
this.historyManager = new HistoryManager()
this.position = new Position(this)
this.zone = new Zone()
this.range = new RangeManager(this)
this.margin = new Margin(this)
this.background = new Background(this)
@ -212,6 +215,12 @@ export class Draw {
return Math.floor(this.getOriginalHeight() * this.options.scale)
}
public getOriginalMainHeight(): number {
const mainHeight = this.getOriginalHeight()
const extraHeight = this.header.getExtraHeight()
return mainHeight - extraHeight
}
public getCanvasWidth(pageNo = -1): number {
const page = this.getPage(pageNo)
return page.width
@ -343,6 +352,10 @@ export class Draw {
return this.position
}
public getZone(): Zone {
return this.zone
}
public getRange(): RangeManager {
return this.range
}
@ -351,12 +364,35 @@ export class Draw {
return this.headerElementList
}
public getTableElementList(sourceElementList: IElement[]): IElement[] {
const positionContext = this.position.getPositionContext()
const { index, trIndex, tdIndex } = positionContext
return sourceElementList[index!].trList![trIndex!].tdList[tdIndex!].value
}
public getElementList(): IElement[] {
const positionContext = this.position.getPositionContext()
if (positionContext.isTable) {
const { index, trIndex, tdIndex } = positionContext
return this.elementList[index!].trList![trIndex!].tdList[tdIndex!].value
}
const elementList = this.getOriginalElementList()
return positionContext.isTable
? this.getTableElementList(elementList)
: elementList
}
public getMainElementList(): IElement[] {
const positionContext = this.position.getPositionContext()
return positionContext.isTable
? this.getTableElementList(this.elementList)
: this.elementList
}
public getOriginalElementList() {
const zoneManager = this.getZone()
return zoneManager.isHeaderActive()
? this.header.getElementList()
: this.elementList
}
public getOriginalMainElementList(): IElement[] {
return this.elementList
}
@ -406,10 +442,6 @@ export class Draw {
}
}
public getOriginalElementList() {
return this.elementList
}
public getCanvasEvent(): CanvasEvent {
return this.canvasEvent
}
@ -434,6 +466,10 @@ export class Draw {
return this.tableTool
}
public getHeader(): Header {
return this.header
}
public getHyperlinkParticle(): HyperlinkParticle {
return this.hyperlinkParticle
}
@ -610,7 +646,7 @@ export class Draw {
// 配置
const { width, height, margins, watermark } = this.options
// 数据
const data: IEditorDrawData = {
const data: IEditorData = {
header: zipElementList(this.headerElementList),
main: zipElementList(this.elementList)
}
@ -768,7 +804,7 @@ export class Draw {
metrics.boundingBoxAscent = 0
// 表格分页处理(拆分表格)
const margins = this.getMargins()
const height = this.getHeight()
const height = this.getOriginalMainHeight()
const marginHeight = margins[0] + margins[2]
let curPagePreHeight = marginHeight
for (let r = 0; r < rowList.length; r++) {
@ -826,13 +862,13 @@ export class Draw {
} else if (element.type === ElementType.SEPARATOR) {
element.width = innerWidth
metrics.width = innerWidth
metrics.height = this.options.defaultSize
metrics.height = defaultSize
metrics.boundingBoxAscent = -rowMargin
metrics.boundingBoxDescent = -rowMargin
} else if (element.type === ElementType.PAGE_BREAK) {
element.width = innerWidth
metrics.width = innerWidth
metrics.height = this.options.defaultSize
metrics.height = defaultSize
} else if (
element.type === ElementType.CHECKBOX ||
element.controlComponent === ControlComponent.CHECKBOX
@ -860,7 +896,7 @@ export class Draw {
metrics.boundingBoxAscent = 0
} else {
// 设置上下标真实字体尺寸
const size = element.size || this.options.defaultSize
const size = element.size || defaultSize
if (element.type === ElementType.SUPERSCRIPT || element.type === ElementType.SUBSCRIPT) {
element.actualSize = Math.ceil(size * 0.6)
}
@ -934,7 +970,7 @@ export class Draw {
private _computePageList(): IRow[][] {
const pageRowList: IRow[][] = [[]]
const { pageMode } = this.options
const height = this.getHeight()
const height = this.getOriginalMainHeight()
const margins = this.getMargins()
const marginHeight = margins[0] + margins[2]
let pageHeight = marginHeight
@ -979,7 +1015,7 @@ export class Draw {
}
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
const { rowList, pageNo, positionList, startIndex } = payload
const { rowList, pageNo, elementList, positionList, startIndex, zone } = payload
const { scale, tdPadding } = this.options
const { isCrossRowCol, tableId } = this.range.getRange()
let index = startIndex
@ -1077,11 +1113,11 @@ export class Draw {
this.highlight.render(ctx)
}
// 选区记录
const { startIndex, endIndex } = this.range.getRange()
if (startIndex !== endIndex && startIndex <= index && index <= endIndex) {
const { zone: currentZone, startIndex, endIndex } = this.range.getRange()
if (currentZone === zone && startIndex !== endIndex && startIndex <= index && index <= endIndex) {
// 从行尾开始-绘制最小宽度
if (startIndex === index) {
const nextElement = this.elementList[startIndex + 1]
const nextElement = elementList[startIndex + 1]
if (nextElement && nextElement.value === ZERO) {
rangeRecord.x = x + metrics.width
rangeRecord.y = y
@ -1119,11 +1155,13 @@ export class Draw {
for (let d = 0; d < tr.tdList!.length; d++) {
const td = tr.tdList[d]
this.drawRow(ctx, {
elementList: td.value,
positionList: td.positionList!,
rowList: td.rowList!,
pageNo,
startIndex: 0,
innerWidth: (td.width! - tdGap) * scale
innerWidth: (td.width! - tdGap) * scale,
zone
})
}
}
@ -1150,10 +1188,13 @@ export class Draw {
this.blockParticle.clear()
}
private _drawPage(positionList: IElementPosition[], rowList: IRow[], pageNo: number) {
const { pageMode } = this.options
private _drawPage(payload: IDrawPagePayload) {
const { elementList, positionList, rowList, pageNo } = payload
const { inactiveAlpha, pageMode } = this.options
const innerWidth = this.getInnerWidth()
const ctx = this.ctxList[pageNo]
// 判断当前激活区域-激活页眉时主题元素透明度降低
ctx.globalAlpha = this.zone.isHeaderActive() ? inactiveAlpha : 1
this._clearPage(pageNo)
// 绘制背景
this.background.render(ctx)
@ -1162,14 +1203,16 @@ export class Draw {
// 渲染元素
const index = rowList[0].startIndex
this.drawRow(ctx, {
elementList,
positionList,
rowList,
pageNo,
startIndex: index,
innerWidth
innerWidth,
zone: EditorZone.MAIN
})
// 绘制页眉
this.header.render(ctx)
this.header.render(ctx, pageNo)
// 绘制页码
this.pageNumber.render(ctx, pageNo)
// 搜索匹配绘制
@ -1183,14 +1226,20 @@ export class Draw {
}
private _lazyRender() {
const positionList = this.position.getOriginalPositionList()
const positionList = this.position.getOriginalMainPositionList()
const elementList = this.getOriginalMainElementList()
this.lazyRenderIntersectionObserver?.disconnect()
this.lazyRenderIntersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const index = Number((<HTMLCanvasElement>entry.target).dataset.index)
this.header.render(this.ctxList[index])
this._drawPage(positionList, this.pageRowList[index], index)
this.header.render(this.ctxList[index], index)
this._drawPage({
elementList,
positionList,
rowList: this.pageRowList[index],
pageNo: index
})
}
})
})
@ -1200,9 +1249,15 @@ export class Draw {
}
private _immediateRender() {
const positionList = this.position.getOriginalPositionList()
const positionList = this.position.getOriginalMainPositionList()
const elementList = this.getOriginalMainElementList()
for (let i = 0; i < this.pageRowList.length; i++) {
this._drawPage(positionList, this.pageRowList[i], i)
this._drawPage({
elementList,
positionList,
rowList: this.pageRowList[i],
pageNo: i
})
}
}
@ -1236,7 +1291,6 @@ export class Draw {
this.imageObserver.clearAll()
this.cursor.recoveryCursor()
// 创建纸张
const positionList = this.position.getOriginalPositionList()
for (let i = 0; i < this.pageRowList.length; i++) {
if (!this.pageList[i]) {
this._createPage(i)
@ -1260,20 +1314,19 @@ export class Draw {
}
// 光标重绘
if (isSetCursor) {
const positionList = this.position.getPositionList()
const positionContext = this.position.getPositionContext()
if (positionContext.isTable) {
const { index, trIndex, tdIndex } = positionContext
const tablePositionList = this.elementList[index!].trList?.[trIndex!].tdList[tdIndex!].positionList
const elementList = this.getElementList()
const tablePositionList = elementList[index!].trList?.[trIndex!].tdList[tdIndex!].positionList
if (curIndex === undefined && tablePositionList) {
curIndex = tablePositionList.length - 1
}
const tablePosition = tablePositionList?.[curIndex!]
this.position.setCursorPosition(tablePosition || null)
} else {
if (curIndex === undefined) {
curIndex = positionList.length - 1
}
this.position.setCursorPosition(positionList[curIndex!] || null)
this.position.setCursorPosition(curIndex !== undefined ? positionList[curIndex] : null)
}
this.cursor.drawCursor()
}
@ -1281,12 +1334,16 @@ export class Draw {
if (isSubmitHistory) {
const self = this
const oldElementList = deepClone(this.elementList)
const oldHeaderElementList = deepClone(this.header.getElementList())
const { startIndex, endIndex } = this.range.getRange()
const pageNo = this.pageNo
const oldPositionContext = deepClone(this.position.getPositionContext())
const zone = this.zone.getZone()
this.historyManager.execute(function () {
self.zone.setZone(zone)
self.setPageNo(pageNo)
self.position.setPositionContext(oldPositionContext)
self.header.setElementList(oldHeaderElementList)
self.elementList = deepClone(oldElementList)
self.range.setRange(startIndex, endIndex)
self.render({ curIndex, isSubmitHistory: false })

@ -1,3 +1,5 @@
import { maxHeightRadioMapping } from '../../../dataset/constant/Header'
import { EditorZone } from '../../../dataset/enum/Editor'
import { DeepRequired } from '../../../interface/Common'
import { IEditorOption } from '../../../interface/Editor'
import { IElement, IElementPosition } from '../../../interface/Element'
@ -25,6 +27,18 @@ export class Header {
this.positionList = []
}
public setElementList(elementList: IElement[]) {
this.elementList = elementList
}
public getElementList(): IElement[] {
return this.elementList
}
public getPositionList(): IElementPosition[] {
return this.positionList
}
public compute() {
this._recovery()
this._computeRowList()
@ -46,7 +60,7 @@ export class Header {
const innerWidth = this.draw.getInnerWidth()
const margins = this.draw.getMargins()
const startX = margins[3]
const startY = margins[0] + top
const startY = top
this.position.computePageRowPosition({
positionList: this.positionList,
rowList: this.rowList,
@ -58,14 +72,53 @@ export class Header {
})
}
public render(ctx: CanvasRenderingContext2D) {
public getMaxHeight(): number {
const { header: { maxHeightRadio }, height } = this.options
return height * maxHeightRadioMapping[maxHeightRadio]
}
public getHeight(): number {
const maxHeight = this.getMaxHeight()
const rowHeight = this.getRowHeight()
return rowHeight > maxHeight ? maxHeight : rowHeight
}
public getRowHeight(): number {
return this.rowList.reduce((pre, cur) => pre + cur.height, 0)
}
public getExtraHeight(): number {
const { header: { top: headerTop } } = this.options
// 页眉上边距 + 实际高 - 页面上边距
const rowHeight = this.getRowHeight()
const margins = this.draw.getOriginalMargins()
const extraHeight = headerTop + rowHeight - margins[0]
return extraHeight <= 0 ? 0 : extraHeight
}
public render(ctx: CanvasRenderingContext2D, pageNo: number) {
ctx.globalAlpha = 1
const innerWidth = this.draw.getInnerWidth()
const maxHeight = this.getMaxHeight()
// 超出最大高度不渲染
const rowList: IRow[] = []
let curRowHeight = 0
for (let r = 0; r < this.rowList.length; r++) {
const row = this.rowList[r]
if (curRowHeight + row.height > maxHeight) {
break
}
rowList.push(row)
curRowHeight += row.height
}
this.draw.drawRow(ctx, {
elementList: this.elementList,
positionList: this.positionList,
rowList: this.rowList,
pageNo: 0,
rowList,
pageNo,
startIndex: 0,
innerWidth
innerWidth,
zone: EditorZone.HEADER
})
}

@ -147,8 +147,8 @@ export class CanvasEvent {
keydown(evt, this)
}
public dblclick() {
click.dblclick(this)
public dblclick(evt: MouseEvent) {
click.dblclick(this, evt)
}
public threeClick() {

@ -2,9 +2,25 @@ import { ZERO } from '../../../dataset/constant/Common'
import { LETTER_REG, NUMBER_LIKE_REG } from '../../../dataset/constant/Regular'
import { CanvasEvent } from '../CanvasEvent'
function dblclick(host: CanvasEvent) {
function dblclick(host: CanvasEvent, evt: MouseEvent) {
// 切换区域
const draw = host.getDraw()
const position = draw.getPosition()
const positionContext = position.getPositionByXY({
x: evt.offsetX,
y: evt.offsetY
})
if (!~positionContext.index && positionContext.zone) {
const zoneManager = draw.getZone()
zoneManager.setZone(positionContext.zone)
draw.render({
isSubmitHistory: false,
isSetCursor: false,
isCompute: false
})
return
}
// 自动扩选文字
const cursorPosition = position.getCursorPosition()
if (!cursorPosition) return
const { value, index } = cursorPosition

@ -21,10 +21,12 @@ function dragover(evt: DragEvent | MouseEvent, host: CanvasEvent) {
draw.setPageNo(Number(pageIndex))
}
const position = draw.getPosition()
const { isTable, tdValueIndex, index } = position.adjustPositionContext({
const positionContext = position.adjustPositionContext({
x: evt.offsetX,
y: evt.offsetY
})
if (!positionContext) return
const { isTable, tdValueIndex, index } = positionContext
// 设置选区及光标位置
const positionList = position.getPositionList()
const curIndex = isTable ? tdValueIndex! : index

@ -36,6 +36,7 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
x: evt.offsetX,
y: evt.offsetY
})
if (!positionResult) return
const {
index,
isDirectHit,

@ -32,6 +32,7 @@ export function mousemove(evt: MouseEvent, host: CanvasEvent) {
x: evt.offsetX,
y: evt.offsetY
})
if (!~positionResult.index) return
const {
index,
isTable,

@ -3,9 +3,10 @@ import { ZERO } from '../../dataset/constant/Common'
import { ControlComponent, ImageDisplay } from '../../dataset/enum/Control'
import { IComputePageRowPositionPayload, IComputePageRowPositionResult } from '../../interface/Position'
import { IEditorOption } from '../../interface/Editor'
import { IElementPosition } from '../../interface/Element'
import { IElement, IElementPosition } from '../../interface/Element'
import { ICurrentPosition, IGetPositionByXYPayload, IPositionContext } from '../../interface/Position'
import { Draw } from '../draw/Draw'
import { EditorZone } from '../../dataset/enum/Editor'
export class Position {
@ -28,17 +29,32 @@ export class Position {
this.options = draw.getOptions()
}
public getOriginalPositionList(): IElementPosition[] {
return this.positionList
public getTablePositionList(sourceElementList: IElement[]): IElementPosition[] {
const { index, trIndex, tdIndex } = this.positionContext
return sourceElementList[index!].trList![trIndex!].tdList[tdIndex!].positionList || []
}
public getPositionList(): IElementPosition[] {
const { isTable } = this.positionContext
if (isTable) {
const { index, trIndex, tdIndex } = this.positionContext
const elementList = this.draw.getOriginalElementList()
return elementList[index!].trList![trIndex!].tdList[tdIndex!].positionList || []
}
const elementList = this.draw.getElementList()
return this.positionContext.isTable
? this.getTablePositionList(elementList)
: this.getOriginalPositionList()
}
public getMainPositionList(): IElementPosition[] {
const elementList = this.draw.getMainElementList()
return this.positionContext.isTable
? this.getTablePositionList(elementList)
: this.positionList
}
public getOriginalPositionList(): IElementPosition[] {
const zoneManager = this.draw.getZone()
const header = this.draw.getHeader()
return zoneManager.isHeaderActive() ? header.getPositionList() : this.positionList
}
public getOriginalMainPositionList(): IElementPosition[] {
return this.positionList
}
@ -130,7 +146,10 @@ export class Position {
const pageRowList = this.draw.getPageRowList()
const margins = this.draw.getMargins()
const startX = margins[3]
const startY = margins[0]
// 起始位置受页眉影响
const header = this.draw.getHeader()
const extraHeight = header.getExtraHeight()
const startY = margins[0] + extraHeight
for (let i = 0; i < pageRowList.length; i++) {
const rowList = pageRowList[i]
const startIndex = rowList[0].startIndex
@ -169,12 +188,14 @@ export class Position {
elementList = this.draw.getOriginalElementList()
}
if (!positionList) {
positionList = this.positionList
positionList = this.getOriginalPositionList()
}
const zoneManager = this.draw.getZone()
const curPageNo = this.draw.getPageNo()
const positionNo = zoneManager.isMainActive() ? curPageNo : 0
for (let j = 0; j < positionList.length; j++) {
const { index, pageNo, coordinate: { leftTop, rightTop, leftBottom } } = positionList[j]
if (curPageNo !== pageNo) continue
if (positionNo !== pageNo) continue
// 命中元素
if (leftTop[0] <= x && rightTop[0] >= x && leftTop[1] <= y && leftBottom[1] >= y) {
let curPositionIndex = j
@ -267,15 +288,15 @@ export class Position {
}
}
// 判断所属行是否存在元素
const firstLetterList = positionList.filter(p => p.isLastLetter && p.pageNo === curPageNo)
const firstLetterList = positionList.filter(p => p.isLastLetter && p.pageNo === positionNo)
for (let j = 0; j < firstLetterList.length; j++) {
const { index, pageNo, coordinate: { leftTop, leftBottom } } = firstLetterList[j]
if (curPageNo !== pageNo) continue
if (positionNo !== pageNo) continue
if (y > leftTop[1] && y <= leftBottom[1]) {
const isHead = x < this.options.margins[3]
// 是否在头部
if (isHead) {
const headIndex = positionList.findIndex(p => p.pageNo === curPageNo && p.rowNo === firstLetterList[j].rowNo)
const headIndex = positionList.findIndex(p => p.pageNo === positionNo && p.rowNo === firstLetterList[j].rowNo)
curPositionIndex = ~headIndex ? headIndex - 1 : index
} else {
curPositionIndex = index
@ -285,8 +306,28 @@ export class Position {
}
}
if (!isLastArea) {
// 判断所属位置是否属于header区域当前位置小于第一行的上边距
if (zoneManager.isMainActive()) {
if (y < firstLetterList[0].coordinate.leftTop[1]) {
return {
index: -1,
zone: EditorZone.HEADER
}
}
}
// 判断所属位置是否属于main区域当前位置大于第一行的上边距
if (zoneManager.isHeaderActive()) {
if (y > firstLetterList[0].coordinate.leftTop[1]) {
return {
index: -1,
zone: EditorZone.MAIN
}
}
}
// 当前页最后一行
return { index: firstLetterList[firstLetterList.length - 1]?.index || positionList.length - 1 }
return {
index: firstLetterList[firstLetterList.length - 1]?.index || positionList.length - 1,
}
}
return {
index: curPositionIndex,
@ -294,13 +335,10 @@ export class Position {
}
}
public adjustPositionContext(payload: Pick<IGetPositionByXYPayload, 'x' | 'y'>): ICurrentPosition {
public adjustPositionContext(payload: IGetPositionByXYPayload): ICurrentPosition | null {
const isReadonly = this.draw.isReadonly()
const { x, y } = payload
const positionResult = this.getPositionByXY({
x,
y
})
const positionResult = this.getPositionByXY(payload)
if (!~positionResult.index) return null
// 移动控件内光标
if (positionResult.isControl && !isReadonly) {
const {

@ -90,6 +90,7 @@ export class RangeManager {
this.range.startTrIndex = startTrIndex
this.range.endTrIndex = endTrIndex
this.range.isCrossRowCol = !!(startTdIndex || endTdIndex || startTrIndex || endTrIndex)
this.range.zone = this.draw.getZone().getZone()
// 激活控件
const control = this.draw.getControl()
if (~startIndex && ~endIndex) {

@ -0,0 +1,27 @@
import { EditorZone } from '../../dataset/enum/Editor'
export class Zone {
private currentZone: EditorZone
constructor() {
this.currentZone = EditorZone.MAIN
}
public isHeaderActive(): boolean {
return this.getZone() === EditorZone.HEADER
}
public isMainActive(): boolean {
return this.getZone() === EditorZone.MAIN
}
public getZone(): EditorZone {
return this.currentZone
}
public setZone(payload: EditorZone) {
this.currentZone = payload
}
}

@ -2,6 +2,12 @@ import { IHeader } from '../../interface/Header'
import { HeaderMaxHeightRatio } from '../enum/Header'
export const defaultHeaderOption: Readonly<Required<IHeader>> = {
top: -50,
top: 30,
maxHeightRadio: HeaderMaxHeightRatio.HALF
}
export const maxHeightRadioMapping: Record<HeaderMaxHeightRatio, number> = {
[HeaderMaxHeightRatio.HALF]: 1 / 2,
[HeaderMaxHeightRatio.ONE_THIRD]: 1 / 3,
[HeaderMaxHeightRatio.QUARTER]: 1 / 4
}

@ -39,7 +39,7 @@ export default class Editor {
public register: Register
public destroy: Function
constructor(container: HTMLDivElement, data: IEditorData, options: IEditorOption = {}) {
constructor(container: HTMLDivElement, data: IEditorData | IElement[], options: IEditorOption = {}) {
const headerOptions: Required<IHeader> = {
...defaultHeaderOption,
...options.header
@ -96,6 +96,7 @@ export default class Editor {
defaultHyperlinkColor: '#0000FF',
headerTop: 50,
paperDirection: PaperDirection.VERTICAL,
inactiveAlpha: 0.6,
...options,
header: headerOptions,
watermark: waterMarkOptions,

@ -1,4 +1,5 @@
import { IElementPosition } from './Element'
import { EditorZone } from '../dataset/enum/Editor'
import { IElement, IElementPosition } from './Element'
import { IRow } from './Row'
export interface IDrawOption {
@ -16,11 +17,20 @@ export interface IDrawImagePayload {
}
export interface IDrawRowPayload {
elementList: IElement[];
positionList: IElementPosition[];
rowList: IRow[];
pageNo: number;
startIndex: number;
innerWidth: number;
zone: EditorZone;
}
export interface IDrawPagePayload {
elementList: IElement[];
positionList: IElementPosition[];
rowList: IRow[];
pageNo: number;
}
export interface IPainterOptions {

@ -7,14 +7,12 @@ import { IHeader } from './Header'
import { IMargin } from './Margin'
import { IWatermark } from './Watermark'
export interface IEditorDrawData {
export interface IEditorData {
header?: IElement[];
main: IElement[];
footer?: IElement[];
}
export type IEditorData = IEditorDrawData | IElement[]
export interface IEditorOption {
mode?: EditorMode;
defaultType?: string;
@ -50,6 +48,7 @@ export interface IEditorOption {
defaultHyperlinkColor?: string;
headerTop?: number;
paperDirection?: PaperDirection;
inactiveAlpha?: number;
header?: IHeader;
watermark?: IWatermark;
control?: IControlOption;

@ -1,4 +1,5 @@
import { IElement } from '..'
import { EditorZone } from '../dataset/enum/Editor'
import { IElementPosition } from './Element'
import { IRow } from './Row'
import { ITd } from './table/Td'
@ -16,6 +17,7 @@ export interface ICurrentPosition {
tdId?: string;
trId?: string;
tableId?: string;
zone?: EditorZone;
}
export interface IGetPositionByXYPayload {

@ -1,3 +1,5 @@
import { EditorZone } from '../dataset/enum/Editor'
export interface IRange {
startIndex: number;
endIndex: number;
@ -7,6 +9,7 @@ export interface IRange {
endTdIndex?: number;
startTrIndex?: number;
endTrIndex?: number;
zone?: EditorZone;
}
export type RangeRowMap = Map<number, Set<number>>

@ -15,10 +15,16 @@ window.onload = function () {
container,
{
header: [{
value: '人民医院门诊',
size: 14,
color: '#AAAAAA',
value: '第一人民医院',
size: 32,
rowFlex: RowFlex.CENTER
}, {
value: '\n门诊病历',
size: 18,
rowFlex: RowFlex.CENTER
}, {
value: '\n',
type: ElementType.SEPARATOR
}],
main: <IElement[]>data
},

@ -1,13 +1,6 @@
import { ControlType, ElementType, IEditorOption, IElement, RowFlex } from './editor'
import { ControlType, ElementType, IEditorOption, IElement } from './editor'
const text = `人民医院门诊病历\n主诉\n发热三天咳嗽五天。\n现病史\n患者于三天前无明显诱因感冒后发现面部水肿无皮疹尿量减少出现乏力在外治疗无好转现来我院就诊。\n既往史\n有糖尿病10年有高血压2年有传染性疾病1年。报告其他既往疾病。\n流行病史\n否认14天内接触过确诊患者、疑似患者、无症状感染者及其密切接触者否认14天内去过以下场所水产、肉类批发市场农贸市场集市大型超市夜市否认14天内与以下场所工作人员密切接触水产、肉类批发市场农贸市场集市大型超市否认14天内周围如家庭、办公室有2例以上聚集性发病否认14天内接触过有发热或呼吸道症状的人员否认14天内自身有发热或呼吸道症状否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形陪同家属无以上情况。\n体格检查\nT39.5℃P80bpmR20次/分BP120/80mmHg\n辅助检查\n2020年6月10日普放血细胞比容36.50%偏低4050单核细胞绝对值0.75*10/L偏高参考值0.10.6\n门诊诊断\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名【】\n其他记录`
// 模拟行居中
const centerText = ['人民医院门诊病历']
const centerIndex: number[] = centerText.map(c => {
const i = text.indexOf(c)
return ~i ? Array(c.length).fill(i).map((_, j) => i + j) : []
}).flat()
const text = `主诉:\n发热三天咳嗽五天。\n现病史\n患者于三天前无明显诱因感冒后发现面部水肿无皮疹尿量减少出现乏力在外治疗无好转现来我院就诊。\n既往史\n有糖尿病10年有高血压2年有传染性疾病1年。报告其他既往疾病。\n流行病史\n否认14天内接触过确诊患者、疑似患者、无症状感染者及其密切接触者否认14天内去过以下场所水产、肉类批发市场农贸市场集市大型超市夜市否认14天内与以下场所工作人员密切接触水产、肉类批发市场农贸市场集市大型超市否认14天内周围如家庭、办公室有2例以上聚集性发病否认14天内接触过有发热或呼吸道症状的人员否认14天内自身有发热或呼吸道症状否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形陪同家属无以上情况。\n体格检查\nT39.5℃P80bpmR20次/分BP120/80mmHg\n辅助检查\n2020年6月10日普放血细胞比容36.50%偏低4050单核细胞绝对值0.75*10/L偏高参考值0.10.6\n门诊诊断\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名【】\n其他记录`
// 模拟加粗字
const boldText = ['主诉:', '现病史:', '既往史:', '流行病史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:', '电子签名:', '其他记录:']
@ -32,13 +25,6 @@ const highlightIndex: number[] = highlightText.map(b => {
// 组合纯文本数据
const elementList: IElement[] = text.split('').map((value, index) => {
if (centerIndex.includes(index)) {
return {
value,
size: 32,
rowFlex: RowFlex.CENTER
}
}
if (boldIndex.includes(index)) {
return {
value,
@ -65,14 +51,8 @@ const elementList: IElement[] = text.split('').map((value, index) => {
}
})
// 模拟分隔符
elementList.splice(8, 0, {
value: '\n',
type: ElementType.SEPARATOR
})
// 模拟文本控件
elementList.splice(24, 0, {
elementList.splice(14, 0, {
type: ElementType.CONTROL,
value: '',
control: {
@ -85,7 +65,7 @@ elementList.splice(24, 0, {
})
// 模拟下拉控件
elementList.splice(112, 0, {
elementList.splice(102, 0, {
type: ElementType.CONTROL,
value: '',
control: {
@ -109,7 +89,7 @@ elementList.splice(112, 0, {
})
// 模拟超链接
elementList.splice(138, 0, {
elementList.splice(128, 0, {
type: ElementType.HYPERLINK,
value: '',
valueList: [{
@ -129,20 +109,20 @@ elementList.splice(138, 0, {
})
// 模拟下标
elementList.splice(371, 0, {
elementList.splice(361, 0, {
value: '∆',
color: '#FF0000',
type: ElementType.SUBSCRIPT
})
// 模拟上标
elementList.splice(459, 0, {
elementList.splice(449, 0, {
value: '9',
type: ElementType.SUPERSCRIPT
})
// 模拟图片
elementList.splice(585, 0, {
elementList.splice(575, 0, {
value: `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAAAgCAYAAAB5JtSmAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQ0SURBVGhD7dhrUSNBFAVgvKACEVjAAhJQgAIUYAABGEAABvgfAdn6UnWou01PppOZhIXNj1P9vo9zH5PK1Waz2V5wWlxIPgMuJJ8Bi0h+fn7eXl9fb29ubrYPDw/dO/8DHh8fu/vB4kym4Orqaofb29vund8OSSbhemewSrugBMnG3vlvw9vb265yn56edmtz/t/f33+5C8MkixQSZSsl9UzLOHUmcwTYAN/Rpl5eXnY+pnIB0Xd3d7s5m3rvDsrkCGszNiQ7r/tr4v39fSc/uipOqRcqufTHBiO78GGdzG5xcLtIFmVde7L9NsvXRo9s84+Pj+79pUAwn5GcD1wIz5r+fYGeJdnjGiF9hwL7iWAcfX19/evtKVHJXrtN8Rf4A3TVczqhrut5i1mSZQgnIriSWtdzP2N+EvIhi3/GWqHWtWXuy2IYbheiKarJZIZknkxyrryc2Utrgal+9S8iScUXIx/3kcxfe/jotcuDezLFlIbARDrzHpytXdKnQr4xyc74Vu9YV5Ih2Q/tT7mDSEYw5ZU4wu3nJx64k/1z9umlUG0hah/JSbC6Jzi5exDJWoTHERoBxu8uf/pT1j3HDkUIJitjbRfRA/iwVzlgy1RCfSF5ili9xj7BUWKs9wJZ3MpditYu+lsc+/PRx53cVF9Pdg/syE9Hb6cS75PkmhUEUFofmTvLGEXKimHueJP9Y3swWQwGLUiA9xEbHKuvgs4pPe1+1myTAKlw81buJ8kigjAXKauXPLQPhEYgJSEYsgdTUR0BmTVgc6C359wcvKGnBrGO8dO5VlD1ZZ519nrBHvrwKVMCas9hgL0YUI2wV98fC4FqCWizzXyqF44A0ZKLHkilgvPs1zbiTuZIdZ414KvqGCKZYx4zple+MSrrJVncAyL02/TOqncJwVMglx5zI4QDZ5WPvBGEcNP+7TlEcqJIAQFGsIdQjmZt7MlYA5yiI3pOQTCQXUm2TuVmXgmewxDJQDgl6deJJoU5y7p9uwZagmu1mCvbNoOOBfkhOf6lRZjzPb8qRjBMMiUhM9GNMZQq5/oRXBP7Mlj/i12A7EMIaJGqDcl8I79+/N1xTvdINQ2TDAQSvI9Md479vdqCHKSFQKAfEmgBqCTDkjaSgOZXQkg2jy1ti0xApnBQJo/0obQRipeQXbN3CmxKGQch5xgki4Efghl/kFqzPD//2DnXIodIRpaoETaXxcmwGNO7N4I2Oyuc6b+xK/tL9IH3kY/E+r1JdST4yM+7VUiuJbuPZHBeHZcNvXtziMMV9mRuvUOX8Vg9IFjRx9dUYM3s2oJyNx9ahFfSWwyRHKHG3nmL2q/mojyFVAWnEdi2Hg7OBXwUCCKr1QEtoe0+/9jI3xqIiuF2QRD0zqcwpfQnge9TVSI4tWrNe79shj98F0xDC0N4bTUVF5LPgAvJJ8dm+wcP2iJuZNdC5QAAAABJRU5ErkJggg==`,
width: 89,
height: 32,

Loading…
Cancel
Save