feat:增加图片插入
This commit is contained in:
@@ -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,47 @@ 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)) {
|
}
|
||||||
|
if (element.type === ElementType.IMAGE) {
|
||||||
|
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 > rightTopPoint[0] - leftTopPoint[0] || (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 +246,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 +279,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,31 @@
|
|||||||
|
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) {
|
||||||
|
if (this.imageCache.has(element.id!)) {
|
||||||
|
const img = this.imageCache.get(element.id!)!
|
||||||
|
this.ctx.drawImage(img, x, y, element.width!, element.height!)
|
||||||
|
} else {
|
||||||
|
const img = new Image()
|
||||||
|
img.src = element.value
|
||||||
|
img.onload = () => {
|
||||||
|
this.ctx.drawImage(img, x, y, img.width, img.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'
|
||||||
|
}
|
||||||
+14
-5
@@ -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())
|
||||||
|
}
|
||||||
+26
-3
@@ -1,5 +1,5 @@
|
|||||||
import './style.css'
|
import './style.css'
|
||||||
import Editor, { RowFlex } from './editor'
|
import Editor, { IElement, RowFlex } from './editor'
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
|
||||||
@@ -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,
|
||||||
@@ -177,7 +177,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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user