@@ -96,6 +96,10 @@
|
||||
</div>
|
||||
<div class="menu-divider"></div>
|
||||
<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">
|
||||
<i></i>
|
||||
</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 { IDrawImagePayload } from "../../interface/Draw"
|
||||
import { CommandAdapt } from "./CommandAdapt"
|
||||
|
||||
export class Command {
|
||||
@@ -20,6 +21,7 @@ export class Command {
|
||||
private static center: Function
|
||||
private static right: Function
|
||||
private static rowMargin: Function
|
||||
private static image: Function
|
||||
private static search: Function
|
||||
private static print: Function
|
||||
|
||||
@@ -41,6 +43,7 @@ export class Command {
|
||||
Command.center = adapt.rowFlex.bind(adapt)
|
||||
Command.right = adapt.rowFlex.bind(adapt)
|
||||
Command.rowMargin = adapt.rowMargin.bind(adapt)
|
||||
Command.image = adapt.image.bind(adapt)
|
||||
Command.search = adapt.search.bind(adapt)
|
||||
Command.print = adapt.print.bind(adapt)
|
||||
}
|
||||
@@ -115,7 +118,11 @@ export class Command {
|
||||
return Command.rowMargin(payload)
|
||||
}
|
||||
|
||||
// 搜索、打印
|
||||
// 图片上传、搜索、打印
|
||||
public executeImage(payload: IDrawImagePayload) {
|
||||
return Command.image(payload)
|
||||
}
|
||||
|
||||
public executeSearch(payload: string | null) {
|
||||
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 { RowFlex } from "../../dataset/enum/Row"
|
||||
import { IDrawImagePayload } from "../../interface/Draw"
|
||||
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 { Draw } from "../draw/Draw"
|
||||
import { HistoryManager } from "../history/HistoryManager"
|
||||
@@ -205,10 +209,32 @@ export class CommandAdapt {
|
||||
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) {
|
||||
if (payload) {
|
||||
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)
|
||||
.join('')
|
||||
const matchStartIndexList = []
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CURSOR_AGENT_HEIGHT } from "../../dataset/constant/Cursor"
|
||||
import { Draw } from "../draw/Draw"
|
||||
import { CanvasEvent } from "../event/CanvasEvent"
|
||||
import { Position } from "../position/Position"
|
||||
@@ -48,18 +49,19 @@ export class Cursor {
|
||||
if (!cursorPosition) return
|
||||
// 设置光标代理
|
||||
const { metrics, coordinate: { leftTop, rightTop }, ascent } = cursorPosition
|
||||
const height = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent
|
||||
const height = metrics.boundingBoxAscent + metrics.boundingBoxDescent
|
||||
const agentCursorDom = this.cursorAgent.getAgentCursorDom()
|
||||
setTimeout(() => {
|
||||
agentCursorDom.focus()
|
||||
agentCursorDom.setSelectionRange(0, 0)
|
||||
})
|
||||
const curosrleft = `${rightTop[0]}px`
|
||||
agentCursorDom.style.left = curosrleft
|
||||
agentCursorDom.style.top = `${leftTop[1] + ascent - 12}px`
|
||||
const cursorTop = leftTop[1] + ascent - metrics.boundingBoxAscent
|
||||
const curosrleft = rightTop[0]
|
||||
agentCursorDom.style.left = `${curosrleft}px`
|
||||
agentCursorDom.style.top = `${cursorTop + height - CURSOR_AGENT_HEIGHT}px`
|
||||
// 模拟光标显示
|
||||
this.cursorDom.style.left = curosrleft
|
||||
this.cursorDom.style.top = `${leftTop[1] + ascent - metrics.fontBoundingBoxAscent}px`
|
||||
this.cursorDom.style.left = `${curosrleft}px`
|
||||
this.cursorDom.style.top = `${cursorTop}px`
|
||||
this.cursorDom.style.display = 'block'
|
||||
this.cursorDom.style.height = `${height}px`
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ZERO } from "../../dataset/constant/Common"
|
||||
import { RowFlex } from "../../dataset/enum/Row"
|
||||
import { IDrawOption } from "../../interface/Draw"
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IElement, IElementPosition, IElementStyle } from "../../interface/Element"
|
||||
import { IRow } from "../../interface/Row"
|
||||
import { IElement, IElementMetrics, IElementPosition, IElementStyle } from "../../interface/Element"
|
||||
import { IRow, IRowElement } from "../../interface/Row"
|
||||
import { deepClone } from "../../utils"
|
||||
import { Cursor } from "../cursor/Cursor"
|
||||
import { CanvasEvent } from "../event/CanvasEvent"
|
||||
@@ -12,12 +12,14 @@ import { HistoryManager } from "../history/HistoryManager"
|
||||
import { Listener } from "../listener/Listener"
|
||||
import { Position } from "../position/Position"
|
||||
import { RangeManager } from "../range/RangeManager"
|
||||
import { Background } from "./Background"
|
||||
import { Highlight } from "./Highlight"
|
||||
import { Margin } from "./Margin"
|
||||
import { Search } from "./Search"
|
||||
import { Strikeout } from "./Strikeout"
|
||||
import { Underline } from "./Underline"
|
||||
import { Background } from "./frame/Background"
|
||||
import { Highlight } from "./richtext/Highlight"
|
||||
import { Margin } from "./frame/Margin"
|
||||
import { Search } from "./interactive/Search"
|
||||
import { Strikeout } from "./richtext/Strikeout"
|
||||
import { Underline } from "./richtext/Underline"
|
||||
import { ElementType } from "../../dataset/enum/Element"
|
||||
import { ImageParticle } from "./particle/ImageParticle"
|
||||
|
||||
export class Draw {
|
||||
|
||||
@@ -37,6 +39,7 @@ export class Draw {
|
||||
private strikeout: Strikeout
|
||||
private highlight: Highlight
|
||||
private historyManager: HistoryManager
|
||||
private imageParticle: ImageParticle
|
||||
|
||||
private rowCount: number
|
||||
private painterStyle: IElementStyle | null
|
||||
@@ -64,6 +67,7 @@ export class Draw {
|
||||
this.underline = new Underline(ctx, options)
|
||||
this.strikeout = new Strikeout(ctx, options)
|
||||
this.highlight = new Highlight(ctx, options)
|
||||
this.imageParticle = new ImageParticle(ctx)
|
||||
|
||||
const canvasEvent = new CanvasEvent(canvas, this)
|
||||
this.cursor = new Cursor(canvas, this, canvasEvent)
|
||||
@@ -179,29 +183,55 @@ export class Draw {
|
||||
this.ctx.save()
|
||||
const curRow: IRow = rowList[rowList.length - 1]
|
||||
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 fontBoundingBoxAscent = metrics.fontBoundingBoxAscent + rowMargin
|
||||
const fontBoundingBoxDescent = metrics.fontBoundingBoxDescent + rowMargin
|
||||
const height = fontBoundingBoxAscent + fontBoundingBoxDescent
|
||||
const lineText = { ...element, metrics }
|
||||
if (curRow.width + width > rightTopPoint[0] - leftTopPoint[0] || (i !== 0 && element.value === ZERO)) {
|
||||
let metrics: IElementMetrics = {
|
||||
width: 0,
|
||||
boundingBoxAscent: 0,
|
||||
boundingBoxDescent: 0
|
||||
}
|
||||
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({
|
||||
width,
|
||||
width: metrics.width,
|
||||
height: this.options.defaultSize,
|
||||
elementList: [lineText],
|
||||
ascent: fontBoundingBoxAscent,
|
||||
rowFlex: lineText.rowFlex
|
||||
elementList: [rowElement],
|
||||
ascent,
|
||||
rowFlex: rowElement.rowFlex
|
||||
})
|
||||
} else {
|
||||
curRow.width += width
|
||||
curRow.width += metrics.width
|
||||
if (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()
|
||||
}
|
||||
@@ -224,16 +254,21 @@ export class Draw {
|
||||
this.ctx.save()
|
||||
const element = curRow.elementList[j]
|
||||
const metrics = element.metrics
|
||||
this.ctx.font = this.getFont(element)
|
||||
if (element.color) {
|
||||
this.ctx.fillStyle = element.color
|
||||
if (!element.type || element.type === ElementType.TEXT) {
|
||||
this.ctx.font = this.getFont(element)
|
||||
if (element.color) {
|
||||
this.ctx.fillStyle = element.color
|
||||
}
|
||||
}
|
||||
const offsetY = element.type === ElementType.IMAGE
|
||||
? curRow.ascent - element.height!
|
||||
: curRow.ascent
|
||||
const positionItem: IElementPosition = {
|
||||
index,
|
||||
value: element.value,
|
||||
rowNo: i,
|
||||
metrics,
|
||||
ascent: curRow.ascent,
|
||||
ascent: offsetY,
|
||||
lineHeight: curRow.height,
|
||||
isLastLetter: j === curRow.elementList.length - 1,
|
||||
coordinate: {
|
||||
@@ -252,12 +287,16 @@ export class Draw {
|
||||
if (element.strikeout) {
|
||||
this.strikeout.render(x, y + curRow.height / 2, metrics.width)
|
||||
}
|
||||
// 文本高亮
|
||||
// 元素高亮
|
||||
if (element.highlight) {
|
||||
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()
|
||||
if (startIndex !== endIndex && startIndex < index && index <= endIndex) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
|
||||
export class Margin {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { Position } from "../position/Position"
|
||||
import { Draw } from "./Draw"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
import { Position } from "../../position/Position"
|
||||
import { Draw } from "../Draw"
|
||||
|
||||
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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
|
||||
export class Strikeout {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
|
||||
export class Underline {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ZERO } from "../../dataset/constant/Common"
|
||||
import { ElementStyleKey } from "../../dataset/enum/ElementStyle"
|
||||
import { KeyMap } from "../../dataset/enum/Keymap"
|
||||
import { IElement } from "../../interface/Element"
|
||||
import { writeText } from "../../utils/clipboard"
|
||||
import { writeTextByElementList } from "../../utils/clipboard"
|
||||
import { Cursor } from "../cursor/Cursor"
|
||||
import { Draw } from "../draw/Draw"
|
||||
import { HistoryManager } from "../history/HistoryManager"
|
||||
@@ -187,11 +187,11 @@ export class CanvasEvent {
|
||||
evt.preventDefault()
|
||||
} else if (evt.ctrlKey && evt.key === KeyMap.C) {
|
||||
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) {
|
||||
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)
|
||||
const curIndex = startIndex
|
||||
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'
|
||||
}
|
||||
+14
-5
@@ -7,6 +7,8 @@ import { Command } from './core/command/Command'
|
||||
import { CommandAdapt } from './core/command/CommandAdapt'
|
||||
import { Listener } from './core/listener/Listener'
|
||||
import { RowFlex } from './dataset/enum/Row'
|
||||
import { getUUID } from './utils'
|
||||
import { ElementType } from './dataset/enum/Element'
|
||||
|
||||
export default class Editor {
|
||||
|
||||
@@ -43,10 +45,11 @@ export default class Editor {
|
||||
value: ZERO
|
||||
})
|
||||
}
|
||||
elementList.forEach(text => {
|
||||
if (text.value === '\n') {
|
||||
text.value = ZERO
|
||||
elementList.forEach(el => {
|
||||
if (el.value === '\n') {
|
||||
el.value = ZERO
|
||||
}
|
||||
el.id = getUUID()
|
||||
})
|
||||
// 监听
|
||||
this.listener = new Listener()
|
||||
@@ -59,8 +62,14 @@ export default class Editor {
|
||||
|
||||
}
|
||||
|
||||
// 对外属性
|
||||
// 对外对象
|
||||
export {
|
||||
Editor,
|
||||
RowFlex
|
||||
RowFlex,
|
||||
ElementType
|
||||
}
|
||||
|
||||
// 对外类型
|
||||
export type {
|
||||
IElement
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
export interface IDrawOption {
|
||||
curIndex?: number;
|
||||
isSetCursor?: boolean
|
||||
isSetCursor?: 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"
|
||||
|
||||
export interface IElementMetrics {
|
||||
width: number;
|
||||
boundingBoxAscent: number;
|
||||
boundingBoxDescent: number;
|
||||
}
|
||||
|
||||
export interface IElementStyle {
|
||||
font?: string;
|
||||
size?: number;
|
||||
@@ -16,7 +23,8 @@ export interface IElementStyle {
|
||||
}
|
||||
|
||||
export interface IElementBasic {
|
||||
type?: 'TEXT' | 'IMAGE';
|
||||
id?: string;
|
||||
type?: ElementType;
|
||||
value: string;
|
||||
}
|
||||
|
||||
@@ -28,7 +36,7 @@ export interface IElementPosition {
|
||||
rowNo: number;
|
||||
ascent: number;
|
||||
lineHeight: number;
|
||||
metrics: TextMetrics;
|
||||
metrics: IElementMetrics;
|
||||
isLastLetter: boolean,
|
||||
coordinate: {
|
||||
leftTop: number[];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RowFlex } from "../dataset/enum/Row"
|
||||
import { IElement } from "./Element"
|
||||
import { IElement, IElementMetrics } from "./Element"
|
||||
|
||||
export type IRowElement = IElement & {
|
||||
metrics: TextMetrics
|
||||
metrics: IElementMetrics
|
||||
}
|
||||
|
||||
export interface IRow {
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { ElementType, IElement } from ".."
|
||||
import { ZERO } from "../dataset/constant/Common"
|
||||
|
||||
export function writeText(text: string) {
|
||||
if (!text) return
|
||||
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)
|
||||
}
|
||||
@@ -41,4 +41,11 @@ export function findParent(node: Element, filterFn: Function, includeSelf: boole
|
||||
}
|
||||
}
|
||||
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())
|
||||
}
|
||||
+35
-5
@@ -1,11 +1,11 @@
|
||||
import './style.css'
|
||||
import Editor, { RowFlex } from './editor'
|
||||
import Editor, { ElementType, IElement, RowFlex } from './editor'
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
const canvas = document.querySelector<HTMLCanvasElement>('canvas')
|
||||
if (!canvas) return
|
||||
const text = `人民医院门诊病历\n主诉:\n发热三天,咳嗽五天。\n现病史:\n发病前14天内有病历报告社区的旅行时或居住史;发病前14天内与新型冠状病毒感染的患者或无症状感染者有接触史;发病前14天内解除过来自病历报告社区的发热或有呼吸道症状的患者;聚集性发病,2周内在小范围如家庭、办公室、学校班级等场所,出现2例及以上发热或呼吸道症状的病例。\n既往史:\n有糖尿病10年,有高血压2年,有传染性疾病1年。\n体格检查:\nT:36.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10^9/L(偏高)参考值:0.1~0.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体格检查:\nT:36.5℃,P:80bpm,R:20次/分,BP:120/80mmHg;\n辅助检查:\n2020年6月10日,普放:血细胞比容36.50%(偏低)40~50;单核细胞绝对值0.75*10^9/L(偏高)参考值:0.1~0.6;\n门诊诊断:\n1.高血压\n处置治疗:\n1.超声引导下甲状腺细针穿刺术;\n2.乙型肝炎表面抗体测定;\n3.膜式病变细胞采集术、后颈皮下肤层;\n电子签名:【】`
|
||||
// 模拟行居中
|
||||
const centerText = ['人民医院门诊病历']
|
||||
const centerIndex: number[] = centerText.map(c => {
|
||||
@@ -13,7 +13,7 @@ window.onload = function () {
|
||||
return ~i ? Array(c.length).fill(i).map((_, j) => i + j) : []
|
||||
}).flat()
|
||||
// 模拟加粗字
|
||||
const boldText = ['主诉:', '现病史:', '既往史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:']
|
||||
const boldText = ['主诉:', '现病史:', '既往史:', '体格检查:', '辅助检查:', '门诊诊断:', '处置治疗:', '电子签名:']
|
||||
const boldIndex: number[] = boldText.map(b => {
|
||||
const i = text.indexOf(b)
|
||||
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) : []
|
||||
}).flat()
|
||||
// 组合数据
|
||||
const data = text.split('').map((value, index) => {
|
||||
const data: IElement[] = text.split('').map((value, index) => {
|
||||
if (centerIndex.includes(index)) {
|
||||
return {
|
||||
value,
|
||||
@@ -64,6 +64,13 @@ window.onload = function () {
|
||||
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, {
|
||||
margins: [100, 120, 100, 120]
|
||||
@@ -177,7 +184,30 @@ window.onload = function () {
|
||||
const li = evt.target as HTMLLIElement
|
||||
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 searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
||||
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
||||
|
||||
@@ -232,6 +232,14 @@ ul {
|
||||
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 {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user