Merge pull request #1 from Hufe921/feature/image

Feature/image
pr675
Hufe 4 years ago committed by GitHub
commit a6f003f320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -96,6 +96,10 @@
</div> </div>
<div class="menu-divider"></div> <div class="menu-divider"></div>
<div class="menu-item"> <div class="menu-item">
<div class="menu-item__image">
<i></i>
<input type="file" id="image" accept=".png, .jpg, .jpeg">
</div>
<div class="menu-item__search"> <div class="menu-item__search">
<i></i> <i></i>
</div> </div>

@ -0,0 +1 @@
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 16 16" xml:space="preserve"><style>.st0{fill:#3d4757}</style><g id="_x30_0-公共_x2F_02工具栏_x2F_插入图片-16px-"><g id="Group-19" transform="translate(1 1)"><path id="Combined-Shape" class="st0" d="M1 0h12c.6 0 1 .4 1 1v11c0 .6-.4 1-1 1H1c-.6 0-1-.4-1-1V1c0-.6.4-1 1-1zm0 1v11h12V1H1z"/><circle id="椭圆形" class="st0" cx="10" cy="4" r="1"/><path id="Path" class="st0" d="M8.5 11.2l-4-4.1L1 10.7V9.2c1.7-1.6 2.7-2.5 3-2.8.4-.5.7-.4 1 0L8.5 10 11 7.3c.4-.5.6-.5 1-.1l2 2.8v1.5l-2.5-3.4-3 3.1z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 613 B

@ -1,4 +1,5 @@
import { RowFlex } from "../../dataset/enum/Row" import { RowFlex } from "../../dataset/enum/Row"
import { IDrawImagePayload } from "../../interface/Draw"
import { CommandAdapt } from "./CommandAdapt" import { CommandAdapt } from "./CommandAdapt"
export class Command { export class Command {
@ -20,6 +21,7 @@ export class Command {
private static center: Function private static center: Function
private static right: Function private static right: Function
private static rowMargin: Function private static rowMargin: Function
private static image: Function
private static search: Function private static search: Function
private static print: Function private static print: Function
@ -41,6 +43,7 @@ export class Command {
Command.center = adapt.rowFlex.bind(adapt) Command.center = adapt.rowFlex.bind(adapt)
Command.right = adapt.rowFlex.bind(adapt) Command.right = adapt.rowFlex.bind(adapt)
Command.rowMargin = adapt.rowMargin.bind(adapt) Command.rowMargin = adapt.rowMargin.bind(adapt)
Command.image = adapt.image.bind(adapt)
Command.search = adapt.search.bind(adapt) Command.search = adapt.search.bind(adapt)
Command.print = adapt.print.bind(adapt) Command.print = adapt.print.bind(adapt)
} }
@ -115,7 +118,11 @@ export class Command {
return Command.rowMargin(payload) return Command.rowMargin(payload)
} }
// 搜索、打印 // 图片上传、搜索、打印
public executeImage(payload: IDrawImagePayload) {
return Command.image(payload)
}
public executeSearch(payload: string | null) { public executeSearch(payload: string | null) {
return Command.search(payload) return Command.search(payload)
} }

@ -1,7 +1,11 @@
import { ZERO } from "../../dataset/constant/Common"
import { ElementType } from "../../dataset/enum/Element"
import { ElementStyleKey } from "../../dataset/enum/ElementStyle" import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
import { RowFlex } from "../../dataset/enum/Row" import { RowFlex } from "../../dataset/enum/Row"
import { IDrawImagePayload } from "../../interface/Draw"
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../interface/Editor"
import { IElementStyle } from "../../interface/Element" import { IElement, IElementStyle } from "../../interface/Element"
import { getUUID } from "../../utils"
import { printImageBase64 } from "../../utils/print" import { printImageBase64 } from "../../utils/print"
import { Draw } from "../draw/Draw" import { Draw } from "../draw/Draw"
import { HistoryManager } from "../history/HistoryManager" import { HistoryManager } from "../history/HistoryManager"
@ -205,10 +209,32 @@ export class CommandAdapt {
this.draw.render({ curIndex, isSetCursor }) this.draw.render({ curIndex, isSetCursor })
} }
public image(payload: IDrawImagePayload) {
const { startIndex, endIndex } = this.range.getRange()
if (startIndex === 0 && endIndex === 0) return
const elementList = this.draw.getElementList()
const { value, width, height } = payload
const element: IElement = {
value,
width,
height,
id: getUUID(),
type: ElementType.IMAGE
}
const curIndex = startIndex + 1
if (startIndex === endIndex) {
elementList.splice(curIndex, 0, element)
} else {
elementList.splice(curIndex, endIndex - startIndex, element)
}
this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex })
}
public search(payload: string | null) { public search(payload: string | null) {
if (payload) { if (payload) {
const elementList = this.draw.getElementList() const elementList = this.draw.getElementList()
const text = elementList.map(e => !e.type || e.type === 'TEXT' ? e.value : null) const text = elementList.map(e => !e.type || e.type === ElementType.TEXT ? e.value : ZERO)
.filter(Boolean) .filter(Boolean)
.join('') .join('')
const matchStartIndexList = [] const matchStartIndexList = []

@ -1,3 +1,4 @@
import { CURSOR_AGENT_HEIGHT } from "../../dataset/constant/Cursor"
import { Draw } from "../draw/Draw" import { Draw } from "../draw/Draw"
import { CanvasEvent } from "../event/CanvasEvent" import { CanvasEvent } from "../event/CanvasEvent"
import { Position } from "../position/Position" import { Position } from "../position/Position"
@ -48,18 +49,19 @@ export class Cursor {
if (!cursorPosition) return if (!cursorPosition) return
// 设置光标代理 // 设置光标代理
const { metrics, coordinate: { leftTop, rightTop }, ascent } = cursorPosition const { metrics, coordinate: { leftTop, rightTop }, ascent } = cursorPosition
const height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent const height = metrics.boundingBoxAscent + metrics.boundingBoxDescent
const agentCursorDom = this.cursorAgent.getAgentCursorDom() const agentCursorDom = this.cursorAgent.getAgentCursorDom()
setTimeout(() => { setTimeout(() => {
agentCursorDom.focus() agentCursorDom.focus()
agentCursorDom.setSelectionRange(0, 0) agentCursorDom.setSelectionRange(0, 0)
}) })
const curosrleft = `${rightTop[0]}px` const cursorTop = leftTop[1] + ascent - metrics.boundingBoxAscent
agentCursorDom.style.left = curosrleft const curosrleft = rightTop[0]
agentCursorDom.style.top = `${leftTop[1] + ascent - 12}px` agentCursorDom.style.left = `${curosrleft}px`
agentCursorDom.style.top = `${cursorTop + height - CURSOR_AGENT_HEIGHT}px`
// 模拟光标显示 // 模拟光标显示
this.cursorDom.style.left = curosrleft this.cursorDom.style.left = `${curosrleft}px`
this.cursorDom.style.top = `${leftTop[1] + ascent - metrics.fontBoundingBoxAscent}px` this.cursorDom.style.top = `${cursorTop}px`
this.cursorDom.style.display = 'block' this.cursorDom.style.display = 'block'
this.cursorDom.style.height = `${height}px` this.cursorDom.style.height = `${height}px`
setTimeout(() => { setTimeout(() => {

@ -2,8 +2,8 @@ import { ZERO } from "../../dataset/constant/Common"
import { RowFlex } from "../../dataset/enum/Row" import { RowFlex } from "../../dataset/enum/Row"
import { IDrawOption } from "../../interface/Draw" import { IDrawOption } from "../../interface/Draw"
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../interface/Editor"
import { IElement, IElementPosition, IElementStyle } from "../../interface/Element" import { IElement, IElementMetrics, IElementPosition, IElementStyle } from "../../interface/Element"
import { IRow } from "../../interface/Row" import { IRow, IRowElement } from "../../interface/Row"
import { deepClone } from "../../utils" import { deepClone } from "../../utils"
import { Cursor } from "../cursor/Cursor" import { Cursor } from "../cursor/Cursor"
import { CanvasEvent } from "../event/CanvasEvent" import { CanvasEvent } from "../event/CanvasEvent"
@ -12,12 +12,14 @@ import { HistoryManager } from "../history/HistoryManager"
import { Listener } from "../listener/Listener" import { Listener } from "../listener/Listener"
import { Position } from "../position/Position" import { Position } from "../position/Position"
import { RangeManager } from "../range/RangeManager" import { RangeManager } from "../range/RangeManager"
import { Background } from "./Background" import { Background } from "./frame/Background"
import { Highlight } from "./Highlight" import { Highlight } from "./richtext/Highlight"
import { Margin } from "./Margin" import { Margin } from "./frame/Margin"
import { Search } from "./Search" import { Search } from "./interactive/Search"
import { Strikeout } from "./Strikeout" import { Strikeout } from "./richtext/Strikeout"
import { Underline } from "./Underline" import { Underline } from "./richtext/Underline"
import { ElementType } from "../../dataset/enum/Element"
import { ImageParticle } from "./particle/ImageParticle"
export class Draw { export class Draw {
@ -37,6 +39,7 @@ export class Draw {
private strikeout: Strikeout private strikeout: Strikeout
private highlight: Highlight private highlight: Highlight
private historyManager: HistoryManager private historyManager: HistoryManager
private imageParticle: ImageParticle
private rowCount: number private rowCount: number
private painterStyle: IElementStyle | null private painterStyle: IElementStyle | null
@ -64,6 +67,7 @@ export class Draw {
this.underline = new Underline(ctx, options) this.underline = new Underline(ctx, options)
this.strikeout = new Strikeout(ctx, options) this.strikeout = new Strikeout(ctx, options)
this.highlight = new Highlight(ctx, options) this.highlight = new Highlight(ctx, options)
this.imageParticle = new ImageParticle(ctx)
const canvasEvent = new CanvasEvent(canvas, this) const canvasEvent = new CanvasEvent(canvas, this)
this.cursor = new Cursor(canvas, this, canvasEvent) this.cursor = new Cursor(canvas, this, canvasEvent)
@ -179,29 +183,55 @@ export class Draw {
this.ctx.save() this.ctx.save()
const curRow: IRow = rowList[rowList.length - 1] const curRow: IRow = rowList[rowList.length - 1]
const element = this.elementList[i] const element = this.elementList[i]
this.ctx.font = this.getFont(element)
const metrics = this.ctx.measureText(element.value)
const width = metrics.width
const rowMargin = defaultBasicRowMarginHeight * (element.rowMargin || defaultRowMargin) const rowMargin = defaultBasicRowMarginHeight * (element.rowMargin || defaultRowMargin)
const fontBoundingBoxAscent = metrics.fontBoundingBoxAscent + rowMargin let metrics: IElementMetrics = {
const fontBoundingBoxDescent = metrics.fontBoundingBoxDescent + rowMargin width: 0,
const height = fontBoundingBoxAscent + fontBoundingBoxDescent boundingBoxAscent: 0,
const lineText = { ...element, metrics } boundingBoxDescent: 0
if (curRow.width + width > rightTopPoint[0] - leftTopPoint[0] || (i !== 0 && element.value === ZERO)) { }
const innerWidth = rightTopPoint[0] - leftTopPoint[0]
if (element.type === ElementType.IMAGE) {
// 图片超出尺寸后自适应
if (curRow.width + element.width! > innerWidth) {
// 计算剩余大小
const surplusWidth = innerWidth - curRow.width
element.width = surplusWidth
element.height = element.height! * surplusWidth / element.width
}
metrics.width = element.width!
metrics.boundingBoxAscent = 0
metrics.boundingBoxDescent = element.height!
} else {
this.ctx.font = this.getFont(element)
const fontMetrics = this.ctx.measureText(element.value)
metrics.width = fontMetrics.width
metrics.boundingBoxAscent = fontMetrics.fontBoundingBoxAscent
metrics.boundingBoxDescent = fontMetrics.fontBoundingBoxDescent
}
const ascent = metrics.boundingBoxAscent + rowMargin
const descent = metrics.boundingBoxDescent + rowMargin
const height = ascent + descent
const rowElement: IRowElement = { ...element, metrics }
// 超过限定宽度
if (curRow.width + metrics.width > innerWidth || (i !== 0 && element.value === ZERO)) {
rowList.push({ rowList.push({
width, width: metrics.width,
height: this.options.defaultSize, height: this.options.defaultSize,
elementList: [lineText], elementList: [rowElement],
ascent: fontBoundingBoxAscent, ascent,
rowFlex: lineText.rowFlex rowFlex: rowElement.rowFlex
}) })
} else { } else {
curRow.width += width curRow.width += metrics.width
if (curRow.height < height) { if (curRow.height < height) {
curRow.height = height curRow.height = height
curRow.ascent = fontBoundingBoxAscent if (element.type === ElementType.IMAGE) {
curRow.ascent = element.height!
} else {
curRow.ascent = ascent
}
} }
curRow.elementList.push(lineText) curRow.elementList.push(rowElement)
} }
this.ctx.restore() this.ctx.restore()
} }
@ -224,16 +254,21 @@ export class Draw {
this.ctx.save() this.ctx.save()
const element = curRow.elementList[j] const element = curRow.elementList[j]
const metrics = element.metrics const metrics = element.metrics
this.ctx.font = this.getFont(element) if (!element.type || element.type === ElementType.TEXT) {
if (element.color) { this.ctx.font = this.getFont(element)
this.ctx.fillStyle = element.color if (element.color) {
this.ctx.fillStyle = element.color
}
} }
const offsetY = element.type === ElementType.IMAGE
? curRow.ascent - element.height!
: curRow.ascent
const positionItem: IElementPosition = { const positionItem: IElementPosition = {
index, index,
value: element.value, value: element.value,
rowNo: i, rowNo: i,
metrics, metrics,
ascent: curRow.ascent, ascent: offsetY,
lineHeight: curRow.height, lineHeight: curRow.height,
isLastLetter: j === curRow.elementList.length - 1, isLastLetter: j === curRow.elementList.length - 1,
coordinate: { coordinate: {
@ -252,12 +287,16 @@ export class Draw {
if (element.strikeout) { if (element.strikeout) {
this.strikeout.render(x, y + curRow.height / 2, metrics.width) this.strikeout.render(x, y + curRow.height / 2, metrics.width)
} }
// 文本高亮 // 元素高亮
if (element.highlight) { if (element.highlight) {
this.highlight.render(element.highlight, x, y, metrics.width, curRow.height) this.highlight.render(element.highlight, x, y, metrics.width, curRow.height)
} }
// 文本 // 元素绘制
this.ctx.fillText(element.value, x, y + curRow.ascent) if (element.type === ElementType.IMAGE) {
this.imageParticle.render(element, x, y + offsetY)
} else {
this.ctx.fillText(element.value, x, y + offsetY)
}
// 选区绘制 // 选区绘制
const { startIndex, endIndex } = this.range.getRange() const { startIndex, endIndex } = this.range.getRange()
if (startIndex !== endIndex && startIndex < index && index <= endIndex) { if (startIndex !== endIndex && startIndex < index && index <= endIndex) {

@ -1,4 +1,4 @@
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../../interface/Editor"
export class Margin { export class Margin {

@ -1,6 +1,6 @@
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../../interface/Editor"
import { Position } from "../position/Position" import { Position } from "../../position/Position"
import { Draw } from "./Draw" import { Draw } from "../Draw"
export class Search { export class Search {

@ -0,0 +1,33 @@
import { IElement } from "../../../interface/Element";
export class ImageParticle {
private ctx: CanvasRenderingContext2D
private imageCache: Map<string, HTMLImageElement>;
constructor(ctx: CanvasRenderingContext2D) {
this.ctx = ctx
this.imageCache = new Map()
}
public getImageCache(): Map<string, HTMLImageElement> {
return this.imageCache
}
render(element: IElement, x: number, y: number) {
const width = element.width!
const height = element.height!
if (this.imageCache.has(element.id!)) {
const img = this.imageCache.get(element.id!)!
this.ctx.drawImage(img, x, y, width, height)
} else {
const img = new Image()
img.src = element.value
img.onload = () => {
this.ctx.drawImage(img, x, y, width, height)
this.imageCache.set(element.id!, img)
}
}
}
}

@ -1,4 +1,4 @@
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../../interface/Editor"
export class Highlight { export class Highlight {

@ -1,4 +1,4 @@
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../../interface/Editor"
export class Strikeout { export class Strikeout {

@ -1,4 +1,4 @@
import { IEditorOption } from "../../interface/Editor" import { IEditorOption } from "../../../interface/Editor"
export class Underline { export class Underline {

@ -2,7 +2,7 @@ import { ZERO } from "../../dataset/constant/Common"
import { ElementStyleKey } from "../../dataset/enum/ElementStyle" import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
import { KeyMap } from "../../dataset/enum/Keymap" import { KeyMap } from "../../dataset/enum/Keymap"
import { IElement } from "../../interface/Element" import { IElement } from "../../interface/Element"
import { writeText } from "../../utils/clipboard" import { writeTextByElementList } from "../../utils/clipboard"
import { Cursor } from "../cursor/Cursor" import { Cursor } from "../cursor/Cursor"
import { Draw } from "../draw/Draw" import { Draw } from "../draw/Draw"
import { HistoryManager } from "../history/HistoryManager" import { HistoryManager } from "../history/HistoryManager"
@ -187,11 +187,11 @@ export class CanvasEvent {
evt.preventDefault() evt.preventDefault()
} else if (evt.ctrlKey && evt.key === KeyMap.C) { } else if (evt.ctrlKey && evt.key === KeyMap.C) {
if (!isCollspace) { if (!isCollspace) {
writeText(elementList.slice(startIndex + 1, endIndex + 1).map(p => p.value).join('')) writeTextByElementList(elementList.slice(startIndex + 1, endIndex + 1))
} }
} else if (evt.ctrlKey && evt.key === KeyMap.X) { } else if (evt.ctrlKey && evt.key === KeyMap.X) {
if (!isCollspace) { if (!isCollspace) {
writeText(position.slice(startIndex + 1, endIndex + 1).map(p => p.value).join('')) writeTextByElementList(elementList.slice(startIndex + 1, endIndex + 1))
elementList.splice(startIndex + 1, endIndex - startIndex) elementList.splice(startIndex + 1, endIndex - startIndex)
const curIndex = startIndex const curIndex = startIndex
this.range.setRange(curIndex, curIndex) this.range.setRange(curIndex, curIndex)

@ -0,0 +1 @@
export const CURSOR_AGENT_HEIGHT = 12

@ -0,0 +1,4 @@
export enum ElementType {
TEXT = 'text',
IMAGE = 'image'
}

@ -7,6 +7,8 @@ import { Command } from './core/command/Command'
import { CommandAdapt } from './core/command/CommandAdapt' import { CommandAdapt } from './core/command/CommandAdapt'
import { Listener } from './core/listener/Listener' import { Listener } from './core/listener/Listener'
import { RowFlex } from './dataset/enum/Row' import { RowFlex } from './dataset/enum/Row'
import { getUUID } from './utils'
import { ElementType } from './dataset/enum/Element'
export default class Editor { export default class Editor {
@ -43,10 +45,11 @@ export default class Editor {
value: ZERO value: ZERO
}) })
} }
elementList.forEach(text => { elementList.forEach(el => {
if (text.value === '\n') { if (el.value === '\n') {
text.value = ZERO el.value = ZERO
} }
el.id = getUUID()
}) })
// 监听 // 监听
this.listener = new Listener() this.listener = new Listener()
@ -59,8 +62,14 @@ export default class Editor {
} }
// 对外属性 // 对外对象
export { export {
Editor, Editor,
RowFlex RowFlex,
ElementType
}
// 对外类型
export type {
IElement
} }

@ -1,5 +1,11 @@
export interface IDrawOption { export interface IDrawOption {
curIndex?: number; curIndex?: number;
isSetCursor?: boolean isSetCursor?: boolean;
isSubmitHistory?: boolean; isSubmitHistory?: boolean;
} }
export interface IDrawImagePayload {
width: number;
height: number;
value: string;
}

@ -1,5 +1,12 @@
import { ElementType } from "../dataset/enum/Element"
import { RowFlex } from "../dataset/enum/Row" import { RowFlex } from "../dataset/enum/Row"
export interface IElementMetrics {
width: number;
boundingBoxAscent: number;
boundingBoxDescent: number;
}
export interface IElementStyle { export interface IElementStyle {
font?: string; font?: string;
size?: number; size?: number;
@ -16,7 +23,8 @@ export interface IElementStyle {
} }
export interface IElementBasic { export interface IElementBasic {
type?: 'TEXT' | 'IMAGE'; id?: string;
type?: ElementType;
value: string; value: string;
} }
@ -28,7 +36,7 @@ export interface IElementPosition {
rowNo: number; rowNo: number;
ascent: number; ascent: number;
lineHeight: number; lineHeight: number;
metrics: TextMetrics; metrics: IElementMetrics;
isLastLetter: boolean, isLastLetter: boolean,
coordinate: { coordinate: {
leftTop: number[]; leftTop: number[];

@ -1,8 +1,8 @@
import { RowFlex } from "../dataset/enum/Row" import { RowFlex } from "../dataset/enum/Row"
import { IElement } from "./Element" import { IElement, IElementMetrics } from "./Element"
export type IRowElement = IElement & { export type IRowElement = IElement & {
metrics: TextMetrics metrics: IElementMetrics
} }
export interface IRow { export interface IRow {

@ -1,6 +1,14 @@
import { ElementType, IElement } from ".."
import { ZERO } from "../dataset/constant/Common" import { ZERO } from "../dataset/constant/Common"
export function writeText(text: string) { export function writeText(text: string) {
if (!text) return if (!text) return
window.navigator.clipboard.writeText(text.replaceAll(ZERO, `\n`)) window.navigator.clipboard.writeText(text.replaceAll(ZERO, `\n`))
} }
export function writeTextByElementList(elementList: IElement[]) {
const text = elementList
.map(p => !p.type || p.type === ElementType.TEXT ? p.value : '')
.join('')
writeText(text)
}

@ -42,3 +42,10 @@ export function findParent(node: Element, filterFn: Function, includeSelf: boole
} }
return null return null
} }
export function getUUID(): string {
function S4(): string {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4())
}

@ -1,11 +1,11 @@
import './style.css' import './style.css'
import Editor, { RowFlex } from './editor' import Editor, { ElementType, IElement, RowFlex } from './editor'
window.onload = function () { window.onload = function () {
const canvas = document.querySelector<HTMLCanvasElement>('canvas') const canvas = document.querySelector<HTMLCanvasElement>('canvas')
if (!canvas) return if (!canvas) return
const text = `人民医院门诊病历\n主诉\n发热三天咳嗽五天。\n现病史\n发病前14天内有病历报告社区的旅行时或居住史发病前14天内与新型冠状病毒感染的患者或无症状感染者有接触史发病前14天内解除过来自病历报告社区的发热或有呼吸道症状的患者聚集性发病2周内在小范围如家庭、办公室、学校班级等场所出现2例及以上发热或呼吸道症状的病例。\n既往史\n有糖尿病10年有高血压2年有传染性疾病1年。\n体格检查\nT36.5℃P80bpmR20次/分BP120/80mmHg\n辅助检查\n2020年6月10日普放血细胞比容36.50%偏低4050单核细胞绝对值0.75*10^9/L偏高参考值0.10.6\n门诊诊断\n1.高血压\n处置治疗\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n4.氯化钠注射液 250ml/袋、1袋\n5.七叶皂苷钠片欧开、30mg/片*24/盒、1片、口服` const text = `人民医院门诊病历\n主诉\n发热三天咳嗽五天。\n现病史\n发病前14天内有病历报告社区的旅行时或居住史发病前14天内与新型冠状病毒感染的患者或无症状感染者有接触史发病前14天内解除过来自病历报告社区的发热或有呼吸道症状的患者聚集性发病2周内在小范围如家庭、办公室、学校班级等场所出现2例及以上发热或呼吸道症状的病例。\n既往史\n有糖尿病10年有高血压2年有传染性疾病1年。\n体格检查\nT36.5℃P80bpmR20次/分BP120/80mmHg\n辅助检查\n2020年6月10日普放血细胞比容36.50%偏低4050单核细胞绝对值0.75*10^9/L偏高参考值0.10.6\n门诊诊断\n1.高血压\n处置治疗\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名:【】`
// 模拟行居中 // 模拟行居中
const centerText = ['人民医院门诊病历'] const centerText = ['人民医院门诊病历']
const centerIndex: number[] = centerText.map(c => { const centerIndex: number[] = centerText.map(c => {
@ -13,7 +13,7 @@ window.onload = function () {
return ~i ? Array(c.length).fill(i).map((_, j) => i + j) : [] return ~i ? Array(c.length).fill(i).map((_, j) => i + j) : []
}).flat() }).flat()
// 模拟加粗字 // 模拟加粗字
const boldText = ['主诉:', '现病史:', '既往史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:'] const boldText = ['主诉:', '现病史:', '既往史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:', '电子签名:']
const boldIndex: number[] = boldText.map(b => { const boldIndex: number[] = boldText.map(b => {
const i = text.indexOf(b) const i = text.indexOf(b)
return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : [] return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : []
@ -31,7 +31,7 @@ window.onload = function () {
return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : [] return ~i ? Array(b.length).fill(i).map((_, j) => i + j) : []
}).flat() }).flat()
// 组合数据 // 组合数据
const data = text.split('').map((value, index) => { const data: IElement[] = text.split('').map((value, index) => {
if (centerIndex.includes(index)) { if (centerIndex.includes(index)) {
return { return {
value, value,
@ -64,6 +64,13 @@ window.onload = function () {
size: 16 size: 16
} }
}) })
data.splice(390, 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,
id: 'signature',
type: ElementType.IMAGE
})
// 初始化编辑器 // 初始化编辑器
const instance = new Editor(canvas, data, { const instance = new Editor(canvas, data, {
margins: [100, 120, 100, 120] margins: [100, 120, 100, 120]
@ -177,7 +184,30 @@ window.onload = function () {
const li = evt.target as HTMLLIElement const li = evt.target as HTMLLIElement
instance.command.executeRowMargin(Number(li.dataset.rowmargin!)) instance.command.executeRowMargin(Number(li.dataset.rowmargin!))
} }
// 搜索、打印 // 图片上传、搜索、打印
const imageDom = document.querySelector<HTMLDivElement>('.menu-item__image')!
const imageFileDom = document.querySelector<HTMLInputElement>('#image')!
imageDom.onclick = function () {
imageFileDom.click()
}
imageFileDom.onchange = function () {
const file = imageFileDom.files?.[0]!
const fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.onload = function () {
// 计算宽高
const image = new Image()
const value = fileReader.result as string
image.src = value
image.onload = function () {
instance.command.executeImage({
value,
width: image.width,
height: image.height,
})
}
}
}
const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse') const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input') const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () { document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {

@ -232,6 +232,14 @@ ul {
background-image: url('./assets/images/row-margin.svg'); background-image: url('./assets/images/row-margin.svg');
} }
.menu-item__image i {
background-image: url('./assets/images/image.svg');
}
.menu-item__image input {
display: none;
}
.menu-item__search { .menu-item__search {
position: relative; position: relative;
} }

Loading…
Cancel
Save