feat:content block core
This commit is contained in:
@@ -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;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@import './control/select.css';
|
@import './control/select.css';
|
||||||
@import './date/datePicker.css';
|
@import './date/datePicker.css';
|
||||||
|
@import './block/block.css';
|
||||||
|
|
||||||
.inputarea {
|
.inputarea {
|
||||||
width: 0;
|
width: 0;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { WorkerManager } from '../worker/WorkerManager'
|
|||||||
import { Previewer } from './particle/previewer/Previewer'
|
import { Previewer } from './particle/previewer/Previewer'
|
||||||
import { DateParticle } from './particle/date/DateParticle'
|
import { DateParticle } from './particle/date/DateParticle'
|
||||||
import { IMargin } from '../../interface/Margin'
|
import { IMargin } from '../../interface/Margin'
|
||||||
|
import { BlockParticle } from './particle/block/BlockParticle'
|
||||||
|
|
||||||
export class Draw {
|
export class Draw {
|
||||||
|
|
||||||
@@ -86,6 +87,7 @@ export class Draw {
|
|||||||
private superscriptParticle: SuperscriptParticle
|
private superscriptParticle: SuperscriptParticle
|
||||||
private subscriptParticle: SubscriptParticle
|
private subscriptParticle: SubscriptParticle
|
||||||
private checkboxParticle: CheckboxParticle
|
private checkboxParticle: CheckboxParticle
|
||||||
|
private blockParticle: BlockParticle
|
||||||
private control: Control
|
private control: Control
|
||||||
private workerManager: WorkerManager
|
private workerManager: WorkerManager
|
||||||
|
|
||||||
@@ -138,6 +140,7 @@ export class Draw {
|
|||||||
this.superscriptParticle = new SuperscriptParticle()
|
this.superscriptParticle = new SuperscriptParticle()
|
||||||
this.subscriptParticle = new SubscriptParticle()
|
this.subscriptParticle = new SubscriptParticle()
|
||||||
this.checkboxParticle = new CheckboxParticle(this)
|
this.checkboxParticle = new CheckboxParticle(this)
|
||||||
|
this.blockParticle = new BlockParticle(this)
|
||||||
this.control = new Control(this)
|
this.control = new Control(this)
|
||||||
|
|
||||||
new ScrollObserver(this)
|
new ScrollObserver(this)
|
||||||
@@ -707,6 +710,11 @@ export class Draw {
|
|||||||
metrics.height = defaultSize * scale
|
metrics.height = defaultSize * scale
|
||||||
metrics.boundingBoxDescent = 0
|
metrics.boundingBoxDescent = 0
|
||||||
metrics.boundingBoxAscent = metrics.height
|
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 {
|
} else {
|
||||||
// 设置上下标真实字体尺寸
|
// 设置上下标真实字体尺寸
|
||||||
const size = element.size || this.options.defaultSize
|
const size = element.size || this.options.defaultSize
|
||||||
@@ -739,6 +747,7 @@ export class Draw {
|
|||||||
const preElement = elementList[i - 1]
|
const preElement = elementList[i - 1]
|
||||||
if (
|
if (
|
||||||
preElement?.type === ElementType.TABLE
|
preElement?.type === ElementType.TABLE
|
||||||
|
|| preElement?.type === ElementType.BLOCK
|
||||||
|| preElement?.imgDisplay === ImageDisplay.INLINE
|
|| preElement?.imgDisplay === ImageDisplay.INLINE
|
||||||
|| element.imgDisplay === ImageDisplay.INLINE
|
|| element.imgDisplay === ImageDisplay.INLINE
|
||||||
|| curRow.width + metrics.width > innerWidth
|
|| curRow.width + metrics.width > innerWidth
|
||||||
@@ -880,6 +889,9 @@ export class Draw {
|
|||||||
// 如果是两端对齐,因canvas目前不支持letterSpacing需单独绘制文本
|
// 如果是两端对齐,因canvas目前不支持letterSpacing需单独绘制文本
|
||||||
this.textParticle.record(ctx, element, x, y + offsetY)
|
this.textParticle.record(ctx, element, x, y + offsetY)
|
||||||
this._drawRichText(ctx)
|
this._drawRichText(ctx)
|
||||||
|
} else if (element.type === ElementType.BLOCK) {
|
||||||
|
this._drawRichText(ctx)
|
||||||
|
this.blockParticle.render(pageNo, element, x, y)
|
||||||
} else {
|
} else {
|
||||||
this.textParticle.record(ctx, element, x, y + offsetY)
|
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',
|
'valueList',
|
||||||
'control',
|
'control',
|
||||||
'checkbox',
|
'checkbox',
|
||||||
'dateFormat'
|
'dateFormat',
|
||||||
|
'block'
|
||||||
]
|
]
|
||||||
|
|
||||||
export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [
|
export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum BlockType {
|
||||||
|
IFRAME = 'iframe'
|
||||||
|
}
|
||||||
@@ -11,5 +11,6 @@ export enum ElementType {
|
|||||||
CHECKBOX = 'checkbox',
|
CHECKBOX = 'checkbox',
|
||||||
LATEX = 'latex',
|
LATEX = 'latex',
|
||||||
TAB = 'tab',
|
TAB = 'tab',
|
||||||
DATE = 'date'
|
DATE = 'date',
|
||||||
|
BLOCK = 'block'
|
||||||
}
|
}
|
||||||
+3
-1
@@ -26,6 +26,7 @@ import { DeepRequired } from './interface/Common'
|
|||||||
import { INavigateInfo } from './core/draw/interactive/Search'
|
import { INavigateInfo } from './core/draw/interactive/Search'
|
||||||
import { Shortcut } from './core/shortcut/Shortcut'
|
import { Shortcut } from './core/shortcut/Shortcut'
|
||||||
import { KeyMap } from './dataset/enum/KeyMap'
|
import { KeyMap } from './dataset/enum/KeyMap'
|
||||||
|
import { BlockType } from './dataset/enum/Block'
|
||||||
|
|
||||||
export default class Editor {
|
export default class Editor {
|
||||||
|
|
||||||
@@ -125,7 +126,8 @@ export {
|
|||||||
PageMode,
|
PageMode,
|
||||||
ImageDisplay,
|
ImageDisplay,
|
||||||
Command,
|
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 { ControlComponent, ImageDisplay } from '../dataset/enum/Control'
|
||||||
import { ElementType } from '../dataset/enum/Element'
|
import { ElementType } from '../dataset/enum/Element'
|
||||||
import { RowFlex } from '../dataset/enum/Row'
|
import { RowFlex } from '../dataset/enum/Row'
|
||||||
|
import { IBlock } from './Block'
|
||||||
import { ICheckbox } from './Checkbox'
|
import { ICheckbox } from './Checkbox'
|
||||||
import { IControl } from './Control'
|
import { IControl } from './Control'
|
||||||
import { IColgroup } from './table/Colgroup'
|
import { IColgroup } from './table/Colgroup'
|
||||||
@@ -78,6 +79,10 @@ export interface IImageElement {
|
|||||||
imgDisplay?: ImageDisplay
|
imgDisplay?: ImageDisplay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBlockElement {
|
||||||
|
block?: IBlock;
|
||||||
|
}
|
||||||
|
|
||||||
export type IElement = IElementBasic
|
export type IElement = IElementBasic
|
||||||
& IElementStyle
|
& IElementStyle
|
||||||
& ITable
|
& ITable
|
||||||
@@ -89,6 +94,7 @@ export type IElement = IElementBasic
|
|||||||
& ILaTexElement
|
& ILaTexElement
|
||||||
& IDateElement
|
& IDateElement
|
||||||
& IImageElement
|
& IImageElement
|
||||||
|
& IBlockElement
|
||||||
|
|
||||||
export interface IElementMetrics {
|
export interface IElementMetrics {
|
||||||
width: number;
|
width: number;
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
|
|||||||
if (el.value === '\n') {
|
if (el.value === '\n') {
|
||||||
el.value = ZERO
|
el.value = ZERO
|
||||||
}
|
}
|
||||||
if (el.type === ElementType.IMAGE) {
|
if (el.type === ElementType.IMAGE || el.type === ElementType.BLOCK) {
|
||||||
el.id = getUUID()
|
el.id = getUUID()
|
||||||
}
|
}
|
||||||
if (el.type === ElementType.LATEX) {
|
if (el.type === ElementType.LATEX) {
|
||||||
|
|||||||
+15
-1
@@ -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体格检查:\nT:39.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10/L(偏高)参考值:0.1~0.6;\n门诊诊断:\n1.高血压\n2.糖尿病\n3.病毒性感冒\n4.过敏性鼻炎\n5.过敏性鼻息肉\n处置治疗:\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名:【】\n其他记录:`
|
const text = `人民医院门诊病历\n主诉:\n发热三天,咳嗽五天。\n现病史:\n患者于三天前无明显诱因,感冒后发现面部水肿,无皮疹,尿量减少,出现乏力,在外治疗无好转,现来我院就诊。\n既往史:\n有糖尿病10年,有高血压2年,有传染性疾病1年。报告其他既往疾病。\n流行病史:\n否认14天内接触过确诊患者、疑似患者、无症状感染者及其密切接触者;否认14天内去过以下场所:水产、肉类批发市场,农贸市场,集市,大型超市,夜市;否认14天内与以下场所工作人员密切接触:水产、肉类批发市场,农贸市场,集市,大型超市;否认14天内周围(如家庭、办公室)有2例以上聚集性发病;否认14天内接触过有发热或呼吸道症状的人员;否认14天内自身有发热或呼吸道症状;否认14天内接触过纳入隔离观察的人员及其他可能与新冠肺炎关联的情形;陪同家属无以上情况。\n体格检查:\nT:39.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10/L(偏高)参考值:0.1~0.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`
|
value: `2022-08-10 17:30:01`
|
||||||
}],
|
}],
|
||||||
type: ElementType.DATE
|
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'
|
value: '\n'
|
||||||
}])
|
}])
|
||||||
|
|||||||
Reference in New Issue
Block a user