feat:content block core

pr675
Hufe921 3 years ago
parent 4118fd4be3
commit 8f7eb3e67f

@ -0,0 +1,7 @@
.block-item {
position: absolute;
z-index: 0;
overflow: hidden;
border-radius: 8px;
border: 1px solid rgb(235 236 240);
}

@ -5,6 +5,7 @@
left: 0;
right: 0;
position: absolute;
z-index: 1;
color: #606266;
background: #ffffff;
border-radius: 4px;

@ -1,5 +1,6 @@
@import './control/select.css';
@import './date/datePicker.css';
@import './block/block.css';
.inputarea {
width: 0;

@ -46,6 +46,7 @@ import { WorkerManager } from '../worker/WorkerManager'
import { Previewer } from './particle/previewer/Previewer'
import { DateParticle } from './particle/date/DateParticle'
import { IMargin } from '../../interface/Margin'
import { BlockParticle } from './particle/block/BlockParticle'
export class Draw {
@ -86,6 +87,7 @@ export class Draw {
private superscriptParticle: SuperscriptParticle
private subscriptParticle: SubscriptParticle
private checkboxParticle: CheckboxParticle
private blockParticle: BlockParticle
private control: Control
private workerManager: WorkerManager
@ -138,6 +140,7 @@ export class Draw {
this.superscriptParticle = new SuperscriptParticle()
this.subscriptParticle = new SubscriptParticle()
this.checkboxParticle = new CheckboxParticle(this)
this.blockParticle = new BlockParticle(this)
this.control = new Control(this)
new ScrollObserver(this)
@ -707,6 +710,11 @@ export class Draw {
metrics.height = defaultSize * scale
metrics.boundingBoxDescent = 0
metrics.boundingBoxAscent = metrics.height
} else if (element.type === ElementType.BLOCK) {
metrics.width = element.width! * scale
metrics.height = element.height! * scale
metrics.boundingBoxDescent = metrics.height
metrics.boundingBoxAscent = 0
} else {
// 设置上下标真实字体尺寸
const size = element.size || this.options.defaultSize
@ -739,6 +747,7 @@ export class Draw {
const preElement = elementList[i - 1]
if (
preElement?.type === ElementType.TABLE
|| preElement?.type === ElementType.BLOCK
|| preElement?.imgDisplay === ImageDisplay.INLINE
|| element.imgDisplay === ImageDisplay.INLINE
|| curRow.width + metrics.width > innerWidth
@ -880,6 +889,9 @@ export class Draw {
// 如果是两端对齐因canvas目前不支持letterSpacing需单独绘制文本
this.textParticle.record(ctx, element, x, y + offsetY)
this._drawRichText(ctx)
} else if (element.type === ElementType.BLOCK) {
this._drawRichText(ctx)
this.blockParticle.render(pageNo, element, x, y)
} else {
this.textParticle.record(ctx, element, x, y + offsetY)
}

@ -0,0 +1,47 @@
import { IRowElement } from '../../../../interface/Row'
import { Draw } from '../../Draw'
import { BaseBlock } from './modules/BaseBlock'
export class BlockParticle {
private draw: Draw
private container: HTMLDivElement
private blockContainer: HTMLDivElement
private blockMap: Map<string, BaseBlock>
constructor(draw: Draw) {
this.draw = draw
this.container = draw.getContainer()
this.blockMap = new Map()
this.blockContainer = this._createBlockContainer()
this.container.append(this.blockContainer)
}
private _createBlockContainer(): HTMLDivElement {
const blockContainer = document.createElement('div')
blockContainer.classList.add('block-container')
return blockContainer
}
public getDraw(): Draw {
return this.draw
}
public getBlockContainer(): HTMLDivElement {
return this.blockContainer
}
public render(pageNo: number, element: IRowElement, x: number, y: number) {
const id = element.id!
const cacheBlock = this.blockMap.get(id)
if (cacheBlock) {
cacheBlock.setClientRects(pageNo, x, y)
} else {
const newBlock = new BaseBlock(this, element)
newBlock.render()
newBlock.setClientRects(pageNo, x, y)
this.blockMap.set(id, newBlock)
}
}
}

@ -0,0 +1,51 @@
import { BlockType } from '../../../../../dataset/enum/Block'
import { IRowElement } from '../../../../../interface/Row'
import { Draw } from '../../../Draw'
import { BlockParticle } from '../BlockParticle'
import { IFrameBlock } from './IFrameBlock'
export class BaseBlock {
private draw: Draw
private element: IRowElement
private block: IFrameBlock | null
private blockContainer: HTMLDivElement
private blockItem: HTMLDivElement
constructor(blockParticle: BlockParticle, element: IRowElement) {
this.draw = blockParticle.getDraw()
this.blockContainer = blockParticle.getBlockContainer()
this.element = element
this.block = null
this.blockItem = this._createBlockItem()
this.blockContainer.append(this.blockItem)
}
private _createBlockItem(): HTMLDivElement {
const blockItem = document.createElement('div')
blockItem.classList.add('block-item')
return blockItem
}
public render() {
const block = this.element.block!
if (block.type === BlockType.IFRAME) {
this.block = new IFrameBlock(this.element)
this.block.render(this.blockItem)
}
}
public setClientRects(pageNo: number, x: number, y: number) {
const scale = this.draw.getOptions().scale
const height = this.draw.getHeight()
const pageGap = this.draw.getPageGap()
const preY = pageNo * (height + pageGap)
// 尺寸
this.blockItem.style.width = `${this.element.width! * scale}px`
this.blockItem.style.height = `${this.element.height! * scale}px`
// 位置
this.blockItem.style.left = `${x}px`
this.blockItem.style.top = `${preY + y}px`
}
}

@ -0,0 +1,28 @@
import { IRowElement } from '../../../../../interface/Row'
export class IFrameBlock {
private static readonly sandbox = [
'allow-forms',
'allow-scripts',
'allow-same-origin',
'allow-popups'
]
private element: IRowElement
constructor(element: IRowElement) {
this.element = element
}
public render(blockItemContainer: HTMLDivElement) {
const block = this.element.block!
const iframe = document.createElement('iframe')
iframe.sandbox.add(...IFrameBlock.sandbox)
iframe.style.border = 'none'
iframe.style.width = '100%'
iframe.style.height = '100%'
iframe.src = block.iframeBlock?.src || ''
blockItemContainer.append(iframe)
}
}

@ -50,7 +50,8 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array<keyof IElement> = [
'valueList',
'control',
'checkbox',
'dateFormat'
'dateFormat',
'block'
]
export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [

@ -0,0 +1,3 @@
export enum BlockType {
IFRAME = 'iframe'
}

@ -11,5 +11,6 @@ export enum ElementType {
CHECKBOX = 'checkbox',
LATEX = 'latex',
TAB = 'tab',
DATE = 'date'
DATE = 'date',
BLOCK = 'block'
}

@ -26,6 +26,7 @@ import { DeepRequired } from './interface/Common'
import { INavigateInfo } from './core/draw/interactive/Search'
import { Shortcut } from './core/shortcut/Shortcut'
import { KeyMap } from './dataset/enum/KeyMap'
import { BlockType } from './dataset/enum/Block'
export default class Editor {
@ -125,7 +126,8 @@ export {
PageMode,
ImageDisplay,
Command,
KeyMap
KeyMap,
BlockType
}
// 对外类型

@ -0,0 +1,10 @@
import { BlockType } from '../dataset/enum/Block'
export interface IIFrameBlock {
src: string;
}
export interface IBlock {
type: BlockType;
iframeBlock?: IIFrameBlock;
}

@ -1,6 +1,7 @@
import { ControlComponent, ImageDisplay } from '../dataset/enum/Control'
import { ElementType } from '../dataset/enum/Element'
import { RowFlex } from '../dataset/enum/Row'
import { IBlock } from './Block'
import { ICheckbox } from './Checkbox'
import { IControl } from './Control'
import { IColgroup } from './table/Colgroup'
@ -78,6 +79,10 @@ export interface IImageElement {
imgDisplay?: ImageDisplay
}
export interface IBlockElement {
block?: IBlock;
}
export type IElement = IElementBasic
& IElementStyle
& ITable
@ -89,6 +94,7 @@ export type IElement = IElementBasic
& ILaTexElement
& IDateElement
& IImageElement
& IBlockElement
export interface IElementMetrics {
width: number;

@ -237,7 +237,7 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
if (el.value === '\n') {
el.value = ZERO
}
if (el.type === ElementType.IMAGE) {
if (el.type === ElementType.IMAGE || el.type === ElementType.BLOCK) {
el.id = getUUID()
}
if (el.type === ElementType.LATEX) {

@ -1,4 +1,4 @@
import { ControlType, ElementType, IEditorOption, IElement, RowFlex } from './editor'
import { BlockType, ControlType, ElementType, IEditorOption, IElement, RowFlex } 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其他记录`
@ -289,6 +289,20 @@ elementList.push(...<IElement[]>[{
value: `2022-08-10 17:30:01`
}],
type: ElementType.DATE
}])
// 内容快
elementList.push(...<IElement[]>[{
value: '',
type: ElementType.BLOCK,
width: 520,
height: 400,
block: {
type: BlockType.IFRAME,
iframeBlock: {
src: 'https://hufe.club'
}
}
}, {
value: '\n'
}])

Loading…
Cancel
Save