feat:add laTeX previewer
This commit is contained in:
@@ -43,6 +43,7 @@ import { DeepRequired } from '../../interface/Common'
|
|||||||
import { ControlComponent } from '../../dataset/enum/Control'
|
import { ControlComponent } from '../../dataset/enum/Control'
|
||||||
import { formatElementList } from '../../utils/element'
|
import { formatElementList } from '../../utils/element'
|
||||||
import { WorkerManager } from '../worker/WorkerManager'
|
import { WorkerManager } from '../worker/WorkerManager'
|
||||||
|
import { Previewer } from './particle/previewer/Previewer'
|
||||||
|
|
||||||
export class Draw {
|
export class Draw {
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ export class Draw {
|
|||||||
private strikeout: Strikeout
|
private strikeout: Strikeout
|
||||||
private highlight: Highlight
|
private highlight: Highlight
|
||||||
private historyManager: HistoryManager
|
private historyManager: HistoryManager
|
||||||
|
private previewer: Previewer
|
||||||
private imageParticle: ImageParticle
|
private imageParticle: ImageParticle
|
||||||
private laTexParticle: LaTexParticle
|
private laTexParticle: LaTexParticle
|
||||||
private textParticle: TextParticle
|
private textParticle: TextParticle
|
||||||
@@ -118,6 +120,7 @@ export class Draw {
|
|||||||
this.underline = new Underline(this)
|
this.underline = new Underline(this)
|
||||||
this.strikeout = new Strikeout(this)
|
this.strikeout = new Strikeout(this)
|
||||||
this.highlight = new Highlight(this)
|
this.highlight = new Highlight(this)
|
||||||
|
this.previewer = new Previewer(this)
|
||||||
this.imageParticle = new ImageParticle(this)
|
this.imageParticle = new ImageParticle(this)
|
||||||
this.laTexParticle = new LaTexParticle(this)
|
this.laTexParticle = new LaTexParticle(this)
|
||||||
this.textParticle = new TextParticle(this)
|
this.textParticle = new TextParticle(this)
|
||||||
@@ -354,6 +357,10 @@ export class Draw {
|
|||||||
return this.cursor
|
return this.cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getPreviewer(): Previewer {
|
||||||
|
return this.previewer
|
||||||
|
}
|
||||||
|
|
||||||
public getImageParticle(): ImageParticle {
|
public getImageParticle(): ImageParticle {
|
||||||
return this.imageParticle
|
return this.imageParticle
|
||||||
}
|
}
|
||||||
@@ -532,12 +539,6 @@ export class Draw {
|
|||||||
boundingBoxDescent: 0
|
boundingBoxDescent: 0
|
||||||
}
|
}
|
||||||
if (element.type === ElementType.IMAGE || element.type === ElementType.LATEX) {
|
if (element.type === ElementType.IMAGE || element.type === ElementType.LATEX) {
|
||||||
if (element.type === ElementType.LATEX) {
|
|
||||||
const { svg, width, height } = this.laTexParticle.convertLaTextToSVG(element.value)
|
|
||||||
element.width = width
|
|
||||||
element.height = height
|
|
||||||
element.laTexSVG = svg
|
|
||||||
}
|
|
||||||
const elementWidth = element.width! * scale
|
const elementWidth = element.width! * scale
|
||||||
const elementHeight = element.height! * scale
|
const elementHeight = element.height! * scale
|
||||||
// 图片超出尺寸后自适应
|
// 图片超出尺寸后自适应
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ControlComponent } from '../../../../dataset/enum/Control'
|
import { ControlComponent } from '../../../../dataset/enum/Control'
|
||||||
import { KeyMap } from '../../../../dataset/enum/Keymap'
|
import { KeyMap } from '../../../../dataset/enum/KeyMap'
|
||||||
import { IControlInstance } from '../../../../interface/Control'
|
import { IControlInstance } from '../../../../interface/Control'
|
||||||
import { IElement } from '../../../../interface/Element'
|
import { IElement } from '../../../../interface/Element'
|
||||||
import { Control } from '../Control'
|
import { Control } from '../Control'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EDITOR_COMPONENT } from '../../../../dataset/constant/Editor'
|
import { EDITOR_COMPONENT } from '../../../../dataset/constant/Editor'
|
||||||
import { ControlComponent } from '../../../../dataset/enum/Control'
|
import { ControlComponent } from '../../../../dataset/enum/Control'
|
||||||
import { EditorComponent } from '../../../../dataset/enum/Editor'
|
import { EditorComponent } from '../../../../dataset/enum/Editor'
|
||||||
import { KeyMap } from '../../../../dataset/enum/Keymap'
|
import { KeyMap } from '../../../../dataset/enum/KeyMap'
|
||||||
import { IControlInstance } from '../../../../interface/Control'
|
import { IControlInstance } from '../../../../interface/Control'
|
||||||
import { IElement } from '../../../../interface/Element'
|
import { IElement } from '../../../../interface/Element'
|
||||||
import { splitText } from '../../../../utils'
|
import { splitText } from '../../../../utils'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ControlComponent } from '../../../../dataset/enum/Control'
|
import { ControlComponent } from '../../../../dataset/enum/Control'
|
||||||
import { KeyMap } from '../../../../dataset/enum/Keymap'
|
import { KeyMap } from '../../../../dataset/enum/KeyMap'
|
||||||
import { IControlInstance } from '../../../../interface/Control'
|
import { IControlInstance } from '../../../../interface/Control'
|
||||||
import { IElement } from '../../../../interface/Element'
|
import { IElement } from '../../../../interface/Element'
|
||||||
import { Control } from '../Control'
|
import { Control } from '../Control'
|
||||||
|
|||||||
@@ -1,334 +1,15 @@
|
|||||||
import { IImageParticleCreateResult } from '../../../interface/Draw'
|
|
||||||
import { IEditorOption } from '../../../interface/Editor'
|
import { IEditorOption } from '../../../interface/Editor'
|
||||||
import { IElement, IElementPosition } from '../../../interface/Element'
|
import { IElement } from '../../../interface/Element'
|
||||||
import { downloadFile } from '../../../utils'
|
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
|
|
||||||
export class ImageParticle {
|
export class ImageParticle {
|
||||||
|
|
||||||
protected container: HTMLDivElement
|
|
||||||
protected canvas: HTMLCanvasElement
|
|
||||||
protected draw: Draw
|
|
||||||
protected options: Required<IEditorOption>
|
protected options: Required<IEditorOption>
|
||||||
protected curElement: IElement | null
|
|
||||||
protected curPosition: IElementPosition | null
|
|
||||||
protected imageCache: Map<string, HTMLImageElement>
|
protected imageCache: Map<string, HTMLImageElement>
|
||||||
// 拖拽改变尺寸
|
|
||||||
protected resizerSelection: HTMLDivElement
|
|
||||||
protected resizerHandleList: HTMLDivElement[]
|
|
||||||
protected resizerImageContainer: HTMLDivElement
|
|
||||||
protected resizerImage: HTMLImageElement
|
|
||||||
protected width: number
|
|
||||||
protected height: number
|
|
||||||
protected mousedownX: number
|
|
||||||
protected mousedownY: number
|
|
||||||
protected curHandleIndex: number
|
|
||||||
// 预览选区
|
|
||||||
protected previewerContainer: HTMLDivElement | null
|
|
||||||
protected previewerImage: HTMLImageElement | null
|
|
||||||
|
|
||||||
constructor(draw: Draw) {
|
constructor(draw: Draw) {
|
||||||
this.container = draw.getContainer()
|
|
||||||
this.canvas = draw.getPage()
|
|
||||||
this.draw = draw
|
|
||||||
this.options = draw.getOptions()
|
this.options = draw.getOptions()
|
||||||
this.curElement = null
|
|
||||||
this.curPosition = null
|
|
||||||
this.imageCache = new Map()
|
this.imageCache = new Map()
|
||||||
// 图片尺寸缩放
|
|
||||||
const { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage } = this._createResizerDom()
|
|
||||||
this.resizerSelection = resizerSelection
|
|
||||||
this.resizerHandleList = resizerHandleList
|
|
||||||
this.resizerImageContainer = resizerImageContainer
|
|
||||||
this.resizerImage = resizerImage
|
|
||||||
this.width = 0
|
|
||||||
this.height = 0
|
|
||||||
this.mousedownX = 0
|
|
||||||
this.mousedownY = 0
|
|
||||||
this.curHandleIndex = 0 // 默认右下角
|
|
||||||
// 图片预览
|
|
||||||
resizerSelection.ondblclick = this._dblclick.bind(this)
|
|
||||||
this.previewerContainer = null
|
|
||||||
this.previewerImage = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createResizerDom(): IImageParticleCreateResult {
|
|
||||||
// 拖拽边框
|
|
||||||
const resizerSelection = document.createElement('div')
|
|
||||||
resizerSelection.classList.add('resizer-selection')
|
|
||||||
resizerSelection.style.display = 'none'
|
|
||||||
resizerSelection.style.borderColor = this.options.resizerColor
|
|
||||||
const resizerHandleList: HTMLDivElement[] = []
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
const handleDom = document.createElement('div')
|
|
||||||
handleDom.style.background = this.options.resizerColor
|
|
||||||
handleDom.classList.add(`handle-${i}`)
|
|
||||||
handleDom.setAttribute('data-index', String(i))
|
|
||||||
handleDom.onmousedown = this._mousedown.bind(this)
|
|
||||||
resizerSelection.append(handleDom)
|
|
||||||
resizerHandleList.push(handleDom)
|
|
||||||
}
|
|
||||||
this.container.append(resizerSelection)
|
|
||||||
// 拖拽镜像
|
|
||||||
const resizerImageContainer = document.createElement('div')
|
|
||||||
resizerImageContainer.classList.add('resizer-image')
|
|
||||||
resizerImageContainer.style.display = 'none'
|
|
||||||
const resizerImage = document.createElement('img')
|
|
||||||
resizerImageContainer.append(resizerImage)
|
|
||||||
this.container.append(resizerImageContainer)
|
|
||||||
return { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage }
|
|
||||||
}
|
|
||||||
|
|
||||||
private _mousedown(evt: MouseEvent) {
|
|
||||||
this.canvas = this.draw.getPage()
|
|
||||||
if (!this.curPosition || !this.curElement) return
|
|
||||||
const { scale } = this.options
|
|
||||||
const height = this.draw.getHeight()
|
|
||||||
const pageGap = this.draw.getPageGap()
|
|
||||||
this.mousedownX = evt.x
|
|
||||||
this.mousedownY = evt.y
|
|
||||||
const target = evt.target as HTMLDivElement
|
|
||||||
this.curHandleIndex = Number(target.dataset.index)
|
|
||||||
// 改变光标
|
|
||||||
const cursor = window.getComputedStyle(target).cursor
|
|
||||||
document.body.style.cursor = cursor
|
|
||||||
this.canvas.style.cursor = cursor
|
|
||||||
// 拖拽图片镜像
|
|
||||||
this.resizerImage.src = this.curElement?.value || ''
|
|
||||||
this.resizerImageContainer.style.display = 'block'
|
|
||||||
const { coordinate: { leftTop: [left, top] } } = this.curPosition
|
|
||||||
const prePageHeight = this.draw.getPageNo() * (height + pageGap)
|
|
||||||
this.resizerImageContainer.style.left = `${left}px`
|
|
||||||
this.resizerImageContainer.style.top = `${top + prePageHeight}px`
|
|
||||||
this.resizerImage.style.width = `${this.curElement.width! * scale}px`
|
|
||||||
this.resizerImage.style.height = `${this.curElement.height! * scale}px`
|
|
||||||
// 追加全局事件
|
|
||||||
const mousemoveFn = this._mousemove.bind(this)
|
|
||||||
document.addEventListener('mousemove', mousemoveFn)
|
|
||||||
document.addEventListener('mouseup', () => {
|
|
||||||
// 改变尺寸
|
|
||||||
if (this.curElement && this.curPosition) {
|
|
||||||
this.curElement.width = this.width
|
|
||||||
this.curElement.height = this.height
|
|
||||||
this.draw.render({ isSetCursor: false })
|
|
||||||
this.drawResizer(this.curElement, this.curPosition)
|
|
||||||
}
|
|
||||||
// 还原副作用
|
|
||||||
this.resizerImageContainer.style.display = 'none'
|
|
||||||
document.removeEventListener('mousemove', mousemoveFn)
|
|
||||||
document.body.style.cursor = ''
|
|
||||||
this.canvas.style.cursor = 'text'
|
|
||||||
}, {
|
|
||||||
once: true
|
|
||||||
})
|
|
||||||
evt.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
private _mousemove(evt: MouseEvent) {
|
|
||||||
if (!this.curElement) return
|
|
||||||
const { scale } = this.options
|
|
||||||
let dx = 0
|
|
||||||
let dy = 0
|
|
||||||
switch (this.curHandleIndex) {
|
|
||||||
case 0:
|
|
||||||
dx = this.mousedownX - evt.x
|
|
||||||
dy = this.mousedownY - evt.y
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
dy = this.mousedownY - evt.y
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
dx = evt.x - this.mousedownX
|
|
||||||
dy = this.mousedownY - evt.y
|
|
||||||
break
|
|
||||||
case 3:
|
|
||||||
dx = evt.x - this.mousedownX
|
|
||||||
break
|
|
||||||
case 5:
|
|
||||||
dy = evt.y - this.mousedownY
|
|
||||||
break
|
|
||||||
case 6:
|
|
||||||
dx = this.mousedownX - evt.x
|
|
||||||
dy = evt.y - this.mousedownY
|
|
||||||
break
|
|
||||||
case 7:
|
|
||||||
dx = this.mousedownX - evt.x
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
dx = evt.x - this.mousedownX
|
|
||||||
dy = evt.y - this.mousedownY
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this.width = this.curElement.width! + dx
|
|
||||||
this.height = this.curElement.height! + dy
|
|
||||||
this.resizerImage.style.width = `${this.width * scale}px`
|
|
||||||
this.resizerImage.style.height = `${this.height * scale}px`
|
|
||||||
evt.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dblclick() {
|
|
||||||
this._drawPreviewer()
|
|
||||||
document.body.style.overflow = 'hidden'
|
|
||||||
}
|
|
||||||
|
|
||||||
private _drawPreviewer() {
|
|
||||||
const previewerContainer = document.createElement('div')
|
|
||||||
previewerContainer.classList.add('image-previewer')
|
|
||||||
// 关闭按钮
|
|
||||||
const closeBtn = document.createElement('i')
|
|
||||||
closeBtn.classList.add('image-close')
|
|
||||||
closeBtn.onclick = () => {
|
|
||||||
this._clearPreviewer()
|
|
||||||
}
|
|
||||||
previewerContainer.append(closeBtn)
|
|
||||||
// 图片
|
|
||||||
const imgContainer = document.createElement('div')
|
|
||||||
imgContainer.classList.add('image-container')
|
|
||||||
const img = document.createElement('img')
|
|
||||||
img.src = this.curElement?.value || ''
|
|
||||||
img.draggable = false
|
|
||||||
imgContainer.append(img)
|
|
||||||
this.previewerImage = img
|
|
||||||
previewerContainer.append(imgContainer)
|
|
||||||
// 操作栏
|
|
||||||
let x = 0
|
|
||||||
let y = 0
|
|
||||||
let scaleSize = 1
|
|
||||||
let rotateSize = 0
|
|
||||||
const menuContainer = document.createElement('div')
|
|
||||||
menuContainer.classList.add('image-menu')
|
|
||||||
const zoomIn = document.createElement('i')
|
|
||||||
zoomIn.classList.add('zoom-in')
|
|
||||||
zoomIn.onclick = () => {
|
|
||||||
scaleSize += 0.1
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
menuContainer.append(zoomIn)
|
|
||||||
const zoomOut = document.createElement('i')
|
|
||||||
zoomOut.onclick = () => {
|
|
||||||
if (scaleSize - 0.1 <= 0.1) return
|
|
||||||
scaleSize -= 0.1
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
zoomOut.classList.add('zoom-out')
|
|
||||||
menuContainer.append(zoomOut)
|
|
||||||
const rotate = document.createElement('i')
|
|
||||||
rotate.classList.add('rotate')
|
|
||||||
rotate.onclick = () => {
|
|
||||||
rotateSize += 1
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
menuContainer.append(rotate)
|
|
||||||
const originalSize = document.createElement('i')
|
|
||||||
originalSize.classList.add('original-size')
|
|
||||||
originalSize.onclick = () => {
|
|
||||||
x = 0
|
|
||||||
y = 0
|
|
||||||
scaleSize = 1
|
|
||||||
rotateSize = 0
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
menuContainer.append(originalSize)
|
|
||||||
const imageDownload = document.createElement('i')
|
|
||||||
imageDownload.classList.add('image-download')
|
|
||||||
imageDownload.onclick = () => {
|
|
||||||
downloadFile(img.src, `${this.curElement?.id}.png`)
|
|
||||||
}
|
|
||||||
menuContainer.append(imageDownload)
|
|
||||||
previewerContainer.append(menuContainer)
|
|
||||||
this.previewerContainer = previewerContainer
|
|
||||||
document.body.append(previewerContainer)
|
|
||||||
// 拖拽调整位置
|
|
||||||
let startX = 0
|
|
||||||
let startY = 0
|
|
||||||
let isAllowDrag = false
|
|
||||||
img.onmousedown = (evt) => {
|
|
||||||
isAllowDrag = true
|
|
||||||
startX = evt.x
|
|
||||||
startY = evt.y
|
|
||||||
previewerContainer.style.cursor = 'move'
|
|
||||||
}
|
|
||||||
previewerContainer.onmousemove = (evt: MouseEvent) => {
|
|
||||||
if (!isAllowDrag) return
|
|
||||||
x += (evt.x - startX)
|
|
||||||
y += (evt.y - startY)
|
|
||||||
startX = evt.x
|
|
||||||
startY = evt.y
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
previewerContainer.onmouseup = () => {
|
|
||||||
isAllowDrag = false
|
|
||||||
previewerContainer.style.cursor = 'auto'
|
|
||||||
}
|
|
||||||
previewerContainer.onwheel = (evt) => {
|
|
||||||
evt.preventDefault()
|
|
||||||
if (evt.deltaY < 0) {
|
|
||||||
// 放大
|
|
||||||
scaleSize += 0.1
|
|
||||||
} else {
|
|
||||||
// 缩小
|
|
||||||
if (scaleSize - 0.1 <= 0.1) return
|
|
||||||
scaleSize -= 0.1
|
|
||||||
}
|
|
||||||
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public _setPreviewerTransform(scale: number, rotate: number, x: number, y: number) {
|
|
||||||
if (!this.previewerImage) return
|
|
||||||
this.previewerImage.style.left = `${x}px`
|
|
||||||
this.previewerImage.style.top = `${y}px`
|
|
||||||
this.previewerImage.style.transform = `scale(${scale}) rotate(${rotate * 90}deg)`
|
|
||||||
}
|
|
||||||
|
|
||||||
private _clearPreviewer() {
|
|
||||||
this.previewerContainer?.remove()
|
|
||||||
this.previewerContainer = null
|
|
||||||
document.body.style.overflow = 'auto'
|
|
||||||
}
|
|
||||||
|
|
||||||
public getImageCache(): Map<string, HTMLImageElement> {
|
|
||||||
return this.imageCache
|
|
||||||
}
|
|
||||||
|
|
||||||
public drawResizer(element: IElement, position: IElementPosition) {
|
|
||||||
const { scale } = this.options
|
|
||||||
const { coordinate: { leftTop: [left, top] } } = position
|
|
||||||
const elementWidth = element.width! * scale
|
|
||||||
const elementHeight = element.height! * scale
|
|
||||||
const height = this.draw.getHeight()
|
|
||||||
const pageGap = this.draw.getPageGap()
|
|
||||||
const handleSize = this.options.resizerSize
|
|
||||||
const preY = this.draw.getPageNo() * (height + pageGap)
|
|
||||||
// 边框
|
|
||||||
this.resizerSelection.style.left = `${left}px`
|
|
||||||
this.resizerSelection.style.top = `${top + preY}px`
|
|
||||||
this.resizerSelection.style.width = `${elementWidth}px`
|
|
||||||
this.resizerSelection.style.height = `${elementHeight}px`
|
|
||||||
// handle
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
const left = i === 0 || i === 6 || i === 7
|
|
||||||
? -handleSize
|
|
||||||
: i === 1 || i === 5
|
|
||||||
? elementWidth / 2
|
|
||||||
: elementWidth - handleSize
|
|
||||||
const top = i === 0 || i === 1 || i === 2
|
|
||||||
? -handleSize
|
|
||||||
: i === 3 || i === 7
|
|
||||||
? elementHeight / 2 - handleSize
|
|
||||||
: elementHeight - handleSize
|
|
||||||
this.resizerHandleList[i].style.left = `${left}px`
|
|
||||||
this.resizerHandleList[i].style.top = `${top}px`
|
|
||||||
}
|
|
||||||
this.resizerSelection.style.display = 'block'
|
|
||||||
this.curElement = element
|
|
||||||
this.curPosition = position
|
|
||||||
this.width = this.curElement.width! * scale
|
|
||||||
this.height = this.curElement.height! * scale
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearResizer() {
|
|
||||||
this.resizerSelection.style.display = 'none'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(ctx: CanvasRenderingContext2D, element: IElement, x: number, y: number) {
|
public render(ctx: CanvasRenderingContext2D, element: IElement, x: number, y: number) {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { IElement } from '../../../../interface/Element'
|
import { IElement } from '../../../../interface/Element'
|
||||||
import { ImageParticle } from '../ImageParticle'
|
import { ImageParticle } from '../ImageParticle'
|
||||||
import { LaTexSVG, LaTexUtils } from './utils/LaTexUtils'
|
import { LaTexSVG, LaTexUtils } from './utils/LaTeXUtils'
|
||||||
|
|
||||||
export class LaTexParticle extends ImageParticle {
|
export class LaTexParticle extends ImageParticle {
|
||||||
|
|
||||||
public convertLaTextToSVG(laTex: string): LaTexSVG {
|
public static convertLaTextToSVG(laTex: string): LaTexSVG {
|
||||||
return new LaTexUtils(laTex).svg({
|
return new LaTexUtils(laTex).svg({
|
||||||
SCALE_X: 10,
|
SCALE_X: 10,
|
||||||
SCALE_Y: 10,
|
SCALE_Y: 10,
|
||||||
|
|||||||
@@ -1022,8 +1022,8 @@ export class LaTexUtils {
|
|||||||
o += `</svg>`
|
o += `</svg>`
|
||||||
return {
|
return {
|
||||||
svg: `data:image/svg+xml;base64,${window.btoa(o)}`,
|
svg: `data:image/svg+xml;base64,${window.btoa(o)}`,
|
||||||
width: w,
|
width: Math.ceil(w),
|
||||||
height: h
|
height: Math.ceil(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
import { IEditorOption } from '../../../../interface/Editor'
|
||||||
|
import { IElement, IElementPosition } from '../../../../interface/Element'
|
||||||
|
import { IPreviewerCreateResult, IPreviewerDrawOption } from '../../../../interface/Previewer'
|
||||||
|
import { downloadFile } from '../../../../utils'
|
||||||
|
import { Draw } from '../../Draw'
|
||||||
|
|
||||||
|
export class Previewer {
|
||||||
|
|
||||||
|
private container: HTMLDivElement
|
||||||
|
private canvas: HTMLCanvasElement
|
||||||
|
private draw: Draw
|
||||||
|
private options: Required<IEditorOption>
|
||||||
|
private curElement: IElement | null
|
||||||
|
private curElementSrc: string
|
||||||
|
private previewerDrawOption: IPreviewerDrawOption
|
||||||
|
private curPosition: IElementPosition | null
|
||||||
|
// 拖拽改变尺寸
|
||||||
|
private resizerSelection: HTMLDivElement
|
||||||
|
private resizerHandleList: HTMLDivElement[]
|
||||||
|
private resizerImageContainer: HTMLDivElement
|
||||||
|
private resizerImage: HTMLImageElement
|
||||||
|
private width: number
|
||||||
|
private height: number
|
||||||
|
private mousedownX: number
|
||||||
|
private mousedownY: number
|
||||||
|
private curHandleIndex: number
|
||||||
|
// 预览选区
|
||||||
|
private previewerContainer: HTMLDivElement | null
|
||||||
|
private previewerImage: HTMLImageElement | null
|
||||||
|
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.container = draw.getContainer()
|
||||||
|
this.canvas = draw.getPage()
|
||||||
|
this.draw = draw
|
||||||
|
this.options = draw.getOptions()
|
||||||
|
this.curElement = null
|
||||||
|
this.curElementSrc = ''
|
||||||
|
this.previewerDrawOption = {}
|
||||||
|
this.curPosition = null
|
||||||
|
// 图片尺寸缩放
|
||||||
|
const { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage } = this._createResizerDom()
|
||||||
|
this.resizerSelection = resizerSelection
|
||||||
|
this.resizerHandleList = resizerHandleList
|
||||||
|
this.resizerImageContainer = resizerImageContainer
|
||||||
|
this.resizerImage = resizerImage
|
||||||
|
this.width = 0
|
||||||
|
this.height = 0
|
||||||
|
this.mousedownX = 0
|
||||||
|
this.mousedownY = 0
|
||||||
|
this.curHandleIndex = 0 // 默认右下角
|
||||||
|
// 图片预览
|
||||||
|
resizerSelection.ondblclick = this._dblclick.bind(this)
|
||||||
|
this.previewerContainer = null
|
||||||
|
this.previewerImage = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createResizerDom(): IPreviewerCreateResult {
|
||||||
|
// 拖拽边框
|
||||||
|
const resizerSelection = document.createElement('div')
|
||||||
|
resizerSelection.classList.add('resizer-selection')
|
||||||
|
resizerSelection.style.display = 'none'
|
||||||
|
resizerSelection.style.borderColor = this.options.resizerColor
|
||||||
|
const resizerHandleList: HTMLDivElement[] = []
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const handleDom = document.createElement('div')
|
||||||
|
handleDom.style.background = this.options.resizerColor
|
||||||
|
handleDom.classList.add(`handle-${i}`)
|
||||||
|
handleDom.setAttribute('data-index', String(i))
|
||||||
|
handleDom.onmousedown = this._mousedown.bind(this)
|
||||||
|
resizerSelection.append(handleDom)
|
||||||
|
resizerHandleList.push(handleDom)
|
||||||
|
}
|
||||||
|
this.container.append(resizerSelection)
|
||||||
|
// 拖拽镜像
|
||||||
|
const resizerImageContainer = document.createElement('div')
|
||||||
|
resizerImageContainer.classList.add('resizer-image')
|
||||||
|
resizerImageContainer.style.display = 'none'
|
||||||
|
const resizerImage = document.createElement('img')
|
||||||
|
resizerImageContainer.append(resizerImage)
|
||||||
|
this.container.append(resizerImageContainer)
|
||||||
|
return { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage }
|
||||||
|
}
|
||||||
|
|
||||||
|
private _mousedown(evt: MouseEvent) {
|
||||||
|
this.canvas = this.draw.getPage()
|
||||||
|
if (!this.curPosition || !this.curElement) return
|
||||||
|
const { scale } = this.options
|
||||||
|
const height = this.draw.getHeight()
|
||||||
|
const pageGap = this.draw.getPageGap()
|
||||||
|
this.mousedownX = evt.x
|
||||||
|
this.mousedownY = evt.y
|
||||||
|
const target = evt.target as HTMLDivElement
|
||||||
|
this.curHandleIndex = Number(target.dataset.index)
|
||||||
|
// 改变光标
|
||||||
|
const cursor = window.getComputedStyle(target).cursor
|
||||||
|
document.body.style.cursor = cursor
|
||||||
|
this.canvas.style.cursor = cursor
|
||||||
|
// 拖拽图片镜像
|
||||||
|
this.resizerImage.src = this.curElementSrc
|
||||||
|
this.resizerImageContainer.style.display = 'block'
|
||||||
|
const { coordinate: { leftTop: [left, top] } } = this.curPosition
|
||||||
|
const prePageHeight = this.draw.getPageNo() * (height + pageGap)
|
||||||
|
this.resizerImageContainer.style.left = `${left}px`
|
||||||
|
this.resizerImageContainer.style.top = `${top + prePageHeight}px`
|
||||||
|
this.resizerImage.style.width = `${this.curElement.width! * scale}px`
|
||||||
|
this.resizerImage.style.height = `${this.curElement.height! * scale}px`
|
||||||
|
// 追加全局事件
|
||||||
|
const mousemoveFn = this._mousemove.bind(this)
|
||||||
|
document.addEventListener('mousemove', mousemoveFn)
|
||||||
|
document.addEventListener('mouseup', () => {
|
||||||
|
// 改变尺寸
|
||||||
|
if (this.curElement && this.curPosition) {
|
||||||
|
this.curElement.width = this.width
|
||||||
|
this.curElement.height = this.height
|
||||||
|
this.draw.render({ isSetCursor: false })
|
||||||
|
this.drawResizer(this.curElement, this.curPosition, this.previewerDrawOption)
|
||||||
|
}
|
||||||
|
// 还原副作用
|
||||||
|
this.resizerImageContainer.style.display = 'none'
|
||||||
|
document.removeEventListener('mousemove', mousemoveFn)
|
||||||
|
document.body.style.cursor = ''
|
||||||
|
this.canvas.style.cursor = 'text'
|
||||||
|
}, {
|
||||||
|
once: true
|
||||||
|
})
|
||||||
|
evt.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _mousemove(evt: MouseEvent) {
|
||||||
|
if (!this.curElement) return
|
||||||
|
const { scale } = this.options
|
||||||
|
let dx = 0
|
||||||
|
let dy = 0
|
||||||
|
switch (this.curHandleIndex) {
|
||||||
|
case 0:
|
||||||
|
dx = this.mousedownX - evt.x
|
||||||
|
dy = this.mousedownY - evt.y
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
dy = this.mousedownY - evt.y
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
dx = evt.x - this.mousedownX
|
||||||
|
dy = this.mousedownY - evt.y
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
dx = evt.x - this.mousedownX
|
||||||
|
break
|
||||||
|
case 5:
|
||||||
|
dy = evt.y - this.mousedownY
|
||||||
|
break
|
||||||
|
case 6:
|
||||||
|
dx = this.mousedownX - evt.x
|
||||||
|
dy = evt.y - this.mousedownY
|
||||||
|
break
|
||||||
|
case 7:
|
||||||
|
dx = this.mousedownX - evt.x
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
dx = evt.x - this.mousedownX
|
||||||
|
dy = evt.y - this.mousedownY
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.width = this.curElement.width! + dx
|
||||||
|
this.height = this.curElement.height! + dy
|
||||||
|
this.resizerImage.style.width = `${this.width * scale}px`
|
||||||
|
this.resizerImage.style.height = `${this.height * scale}px`
|
||||||
|
evt.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dblclick() {
|
||||||
|
this._drawPreviewer()
|
||||||
|
document.body.style.overflow = 'hidden'
|
||||||
|
}
|
||||||
|
|
||||||
|
private _drawPreviewer() {
|
||||||
|
const previewerContainer = document.createElement('div')
|
||||||
|
previewerContainer.classList.add('image-previewer')
|
||||||
|
// 关闭按钮
|
||||||
|
const closeBtn = document.createElement('i')
|
||||||
|
closeBtn.classList.add('image-close')
|
||||||
|
closeBtn.onclick = () => {
|
||||||
|
this._clearPreviewer()
|
||||||
|
}
|
||||||
|
previewerContainer.append(closeBtn)
|
||||||
|
// 图片
|
||||||
|
const imgContainer = document.createElement('div')
|
||||||
|
imgContainer.classList.add('image-container')
|
||||||
|
const img = document.createElement('img')
|
||||||
|
img.src = this.curElementSrc
|
||||||
|
img.draggable = false
|
||||||
|
imgContainer.append(img)
|
||||||
|
this.previewerImage = img
|
||||||
|
previewerContainer.append(imgContainer)
|
||||||
|
// 操作栏
|
||||||
|
let x = 0
|
||||||
|
let y = 0
|
||||||
|
let scaleSize = 1
|
||||||
|
let rotateSize = 0
|
||||||
|
const menuContainer = document.createElement('div')
|
||||||
|
menuContainer.classList.add('image-menu')
|
||||||
|
const zoomIn = document.createElement('i')
|
||||||
|
zoomIn.classList.add('zoom-in')
|
||||||
|
zoomIn.onclick = () => {
|
||||||
|
scaleSize += 0.1
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
menuContainer.append(zoomIn)
|
||||||
|
const zoomOut = document.createElement('i')
|
||||||
|
zoomOut.onclick = () => {
|
||||||
|
if (scaleSize - 0.1 <= 0.1) return
|
||||||
|
scaleSize -= 0.1
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
zoomOut.classList.add('zoom-out')
|
||||||
|
menuContainer.append(zoomOut)
|
||||||
|
const rotate = document.createElement('i')
|
||||||
|
rotate.classList.add('rotate')
|
||||||
|
rotate.onclick = () => {
|
||||||
|
rotateSize += 1
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
menuContainer.append(rotate)
|
||||||
|
const originalSize = document.createElement('i')
|
||||||
|
originalSize.classList.add('original-size')
|
||||||
|
originalSize.onclick = () => {
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
scaleSize = 1
|
||||||
|
rotateSize = 0
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
menuContainer.append(originalSize)
|
||||||
|
const imageDownload = document.createElement('i')
|
||||||
|
imageDownload.classList.add('image-download')
|
||||||
|
imageDownload.onclick = () => {
|
||||||
|
const { mime } = this.previewerDrawOption
|
||||||
|
downloadFile(img.src, `${this.curElement?.id}.${mime || 'png'}`)
|
||||||
|
}
|
||||||
|
menuContainer.append(imageDownload)
|
||||||
|
previewerContainer.append(menuContainer)
|
||||||
|
this.previewerContainer = previewerContainer
|
||||||
|
document.body.append(previewerContainer)
|
||||||
|
// 拖拽调整位置
|
||||||
|
let startX = 0
|
||||||
|
let startY = 0
|
||||||
|
let isAllowDrag = false
|
||||||
|
img.onmousedown = (evt) => {
|
||||||
|
isAllowDrag = true
|
||||||
|
startX = evt.x
|
||||||
|
startY = evt.y
|
||||||
|
previewerContainer.style.cursor = 'move'
|
||||||
|
}
|
||||||
|
previewerContainer.onmousemove = (evt: MouseEvent) => {
|
||||||
|
if (!isAllowDrag) return
|
||||||
|
x += (evt.x - startX)
|
||||||
|
y += (evt.y - startY)
|
||||||
|
startX = evt.x
|
||||||
|
startY = evt.y
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
previewerContainer.onmouseup = () => {
|
||||||
|
isAllowDrag = false
|
||||||
|
previewerContainer.style.cursor = 'auto'
|
||||||
|
}
|
||||||
|
previewerContainer.onwheel = (evt) => {
|
||||||
|
evt.preventDefault()
|
||||||
|
if (evt.deltaY < 0) {
|
||||||
|
// 放大
|
||||||
|
scaleSize += 0.1
|
||||||
|
} else {
|
||||||
|
// 缩小
|
||||||
|
if (scaleSize - 0.1 <= 0.1) return
|
||||||
|
scaleSize -= 0.1
|
||||||
|
}
|
||||||
|
this._setPreviewerTransform(scaleSize, rotateSize, x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public _setPreviewerTransform(scale: number, rotate: number, x: number, y: number) {
|
||||||
|
if (!this.previewerImage) return
|
||||||
|
this.previewerImage.style.left = `${x}px`
|
||||||
|
this.previewerImage.style.top = `${y}px`
|
||||||
|
this.previewerImage.style.transform = `scale(${scale}) rotate(${rotate * 90}deg)`
|
||||||
|
}
|
||||||
|
|
||||||
|
private _clearPreviewer() {
|
||||||
|
this.previewerContainer?.remove()
|
||||||
|
this.previewerContainer = null
|
||||||
|
document.body.style.overflow = 'auto'
|
||||||
|
}
|
||||||
|
|
||||||
|
public drawResizer(element: IElement, position: IElementPosition, options: IPreviewerDrawOption = {}) {
|
||||||
|
this.previewerDrawOption = options
|
||||||
|
const { scale } = this.options
|
||||||
|
const { coordinate: { leftTop: [left, top] } } = position
|
||||||
|
const elementWidth = element.width! * scale
|
||||||
|
const elementHeight = element.height! * scale
|
||||||
|
const height = this.draw.getHeight()
|
||||||
|
const pageGap = this.draw.getPageGap()
|
||||||
|
const handleSize = this.options.resizerSize
|
||||||
|
const preY = this.draw.getPageNo() * (height + pageGap)
|
||||||
|
// 边框
|
||||||
|
this.resizerSelection.style.left = `${left}px`
|
||||||
|
this.resizerSelection.style.top = `${top + preY}px`
|
||||||
|
this.resizerSelection.style.width = `${elementWidth}px`
|
||||||
|
this.resizerSelection.style.height = `${elementHeight}px`
|
||||||
|
// handle
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const left = i === 0 || i === 6 || i === 7
|
||||||
|
? -handleSize
|
||||||
|
: i === 1 || i === 5
|
||||||
|
? elementWidth / 2
|
||||||
|
: elementWidth - handleSize
|
||||||
|
const top = i === 0 || i === 1 || i === 2
|
||||||
|
? -handleSize
|
||||||
|
: i === 3 || i === 7
|
||||||
|
? elementHeight / 2 - handleSize
|
||||||
|
: elementHeight - handleSize
|
||||||
|
this.resizerHandleList[i].style.left = `${left}px`
|
||||||
|
this.resizerHandleList[i].style.top = `${top}px`
|
||||||
|
}
|
||||||
|
this.resizerSelection.style.display = 'block'
|
||||||
|
this.curElement = element
|
||||||
|
this.curElementSrc = element[options.srcKey || 'value'] || ''
|
||||||
|
this.curPosition = position
|
||||||
|
this.width = this.curElement.width! * scale
|
||||||
|
this.height = this.curElement.height! * scale
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearResizer() {
|
||||||
|
this.resizerSelection.style.display = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,14 +3,13 @@ import { ZERO } from '../../dataset/constant/Common'
|
|||||||
import { EDITOR_ELEMENT_COPY_ATTR } from '../../dataset/constant/Element'
|
import { EDITOR_ELEMENT_COPY_ATTR } from '../../dataset/constant/Element'
|
||||||
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
|
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
|
||||||
import { MouseEventButton } from '../../dataset/enum/Event'
|
import { MouseEventButton } from '../../dataset/enum/Event'
|
||||||
import { KeyMap } from '../../dataset/enum/Keymap'
|
import { KeyMap } from '../../dataset/enum/KeyMap'
|
||||||
import { IElement } from '../../interface/Element'
|
import { IElement } from '../../interface/Element'
|
||||||
import { ICurrentPosition } from '../../interface/Position'
|
import { ICurrentPosition } from '../../interface/Position'
|
||||||
import { writeElementList } from '../../utils/clipboard'
|
import { writeElementList } from '../../utils/clipboard'
|
||||||
import { Cursor } from '../cursor/Cursor'
|
import { Cursor } from '../cursor/Cursor'
|
||||||
import { Draw } from '../draw/Draw'
|
import { Draw } from '../draw/Draw'
|
||||||
import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle'
|
import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle'
|
||||||
import { ImageParticle } from '../draw/particle/ImageParticle'
|
|
||||||
import { TableTool } from '../draw/particle/table/TableTool'
|
import { TableTool } from '../draw/particle/table/TableTool'
|
||||||
import { HistoryManager } from '../history/HistoryManager'
|
import { HistoryManager } from '../history/HistoryManager'
|
||||||
import { Listener } from '../listener/Listener'
|
import { Listener } from '../listener/Listener'
|
||||||
@@ -20,6 +19,7 @@ import { LETTER_REG, NUMBER_LIKE_REG } from '../../dataset/constant/Regular'
|
|||||||
import { Control } from '../draw/control/Control'
|
import { Control } from '../draw/control/Control'
|
||||||
import { CheckboxControl } from '../draw/control/checkbox/CheckboxControl'
|
import { CheckboxControl } from '../draw/control/checkbox/CheckboxControl'
|
||||||
import { splitText } from '../../utils'
|
import { splitText } from '../../utils'
|
||||||
|
import { Previewer } from '../draw/particle/previewer/Previewer'
|
||||||
|
|
||||||
export class CanvasEvent {
|
export class CanvasEvent {
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export class CanvasEvent {
|
|||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private cursor: Cursor | null
|
private cursor: Cursor | null
|
||||||
private historyManager: HistoryManager
|
private historyManager: HistoryManager
|
||||||
private imageParticle: ImageParticle
|
private previewer: Previewer
|
||||||
private tableTool: TableTool
|
private tableTool: TableTool
|
||||||
private hyperlinkParticle: HyperlinkParticle
|
private hyperlinkParticle: HyperlinkParticle
|
||||||
private listener: Listener
|
private listener: Listener
|
||||||
@@ -52,7 +52,7 @@ export class CanvasEvent {
|
|||||||
this.position = this.draw.getPosition()
|
this.position = this.draw.getPosition()
|
||||||
this.range = this.draw.getRange()
|
this.range = this.draw.getRange()
|
||||||
this.historyManager = this.draw.getHistoryManager()
|
this.historyManager = this.draw.getHistoryManager()
|
||||||
this.imageParticle = this.draw.getImageParticle()
|
this.previewer = this.draw.getPreviewer()
|
||||||
this.tableTool = this.draw.getTableTool()
|
this.tableTool = this.draw.getTableTool()
|
||||||
this.hyperlinkParticle = this.draw.getHyperlinkParticle()
|
this.hyperlinkParticle = this.draw.getHyperlinkParticle()
|
||||||
this.listener = this.draw.getListener()
|
this.listener = this.draw.getListener()
|
||||||
@@ -258,10 +258,16 @@ export class CanvasEvent {
|
|||||||
isComputeRowList: false
|
isComputeRowList: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 图片尺寸拖拽组件
|
// 预览工具组件
|
||||||
this.imageParticle.clearResizer()
|
this.previewer.clearResizer()
|
||||||
if (isDirectHitImage && !isReadonly) {
|
if (isDirectHitImage && !isReadonly) {
|
||||||
this.imageParticle.drawResizer(curElement, positionList[curIndex])
|
this.previewer.drawResizer(curElement, positionList[curIndex],
|
||||||
|
curElement.type === ElementType.LATEX
|
||||||
|
? {
|
||||||
|
mime: 'svg',
|
||||||
|
srcKey: 'laTexSVG'
|
||||||
|
}
|
||||||
|
: {})
|
||||||
}
|
}
|
||||||
// 表格工具组件
|
// 表格工具组件
|
||||||
this.tableTool.dispose()
|
this.tableTool.dispose()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Cursor } from '../cursor/Cursor'
|
|||||||
import { Control } from '../draw/control/Control'
|
import { Control } from '../draw/control/Control'
|
||||||
import { Draw } from '../draw/Draw'
|
import { Draw } from '../draw/Draw'
|
||||||
import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle'
|
import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle'
|
||||||
import { ImageParticle } from '../draw/particle/ImageParticle'
|
import { Previewer } from '../draw/particle/previewer/Previewer'
|
||||||
import { TableTool } from '../draw/particle/table/TableTool'
|
import { TableTool } from '../draw/particle/table/TableTool'
|
||||||
import { RangeManager } from '../range/RangeManager'
|
import { RangeManager } from '../range/RangeManager'
|
||||||
import { CanvasEvent } from './CanvasEvent'
|
import { CanvasEvent } from './CanvasEvent'
|
||||||
@@ -18,7 +18,7 @@ export class GlobalEvent {
|
|||||||
private cursor: Cursor | null
|
private cursor: Cursor | null
|
||||||
private canvasEvent: CanvasEvent
|
private canvasEvent: CanvasEvent
|
||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private imageParticle: ImageParticle
|
private previewer: Previewer
|
||||||
private tableTool: TableTool
|
private tableTool: TableTool
|
||||||
private hyperlinkParticle: HyperlinkParticle
|
private hyperlinkParticle: HyperlinkParticle
|
||||||
private control: Control
|
private control: Control
|
||||||
@@ -30,7 +30,7 @@ export class GlobalEvent {
|
|||||||
this.canvasEvent = canvasEvent
|
this.canvasEvent = canvasEvent
|
||||||
this.cursor = null
|
this.cursor = null
|
||||||
this.range = draw.getRange()
|
this.range = draw.getRange()
|
||||||
this.imageParticle = draw.getImageParticle()
|
this.previewer = draw.getPreviewer()
|
||||||
this.tableTool = draw.getTableTool()
|
this.tableTool = draw.getTableTool()
|
||||||
this.hyperlinkParticle = draw.getHyperlinkParticle()
|
this.hyperlinkParticle = draw.getHyperlinkParticle()
|
||||||
this.control = draw.getControl()
|
this.control = draw.getControl()
|
||||||
@@ -74,7 +74,7 @@ export class GlobalEvent {
|
|||||||
this.cursor.recoveryCursor()
|
this.cursor.recoveryCursor()
|
||||||
this.range.recoveryRangeStyle()
|
this.range.recoveryRangeStyle()
|
||||||
this.range.setRange(-1, -1)
|
this.range.setRange(-1, -1)
|
||||||
this.imageParticle.clearResizer()
|
this.previewer.clearResizer()
|
||||||
this.tableTool.dispose()
|
this.tableTool.dispose()
|
||||||
this.hyperlinkParticle.clearHyperlinkPopup()
|
this.hyperlinkParticle.clearHyperlinkPopup()
|
||||||
this.control.destroyControl()
|
this.control.destroyControl()
|
||||||
|
|||||||
@@ -14,13 +14,6 @@ export interface IDrawImagePayload {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IImageParticleCreateResult {
|
|
||||||
resizerSelection: HTMLDivElement;
|
|
||||||
resizerHandleList: HTMLDivElement[];
|
|
||||||
resizerImageContainer: HTMLDivElement;
|
|
||||||
resizerImage: HTMLImageElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDrawRowPayload {
|
export interface IDrawRowPayload {
|
||||||
positionList: IElementPosition[];
|
positionList: IElementPosition[];
|
||||||
rowList: IRow[];
|
rowList: IRow[];
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { IElement } from './Element'
|
||||||
|
|
||||||
|
export interface IPreviewerCreateResult {
|
||||||
|
resizerSelection: HTMLDivElement;
|
||||||
|
resizerHandleList: HTMLDivElement[];
|
||||||
|
resizerImageContainer: HTMLDivElement;
|
||||||
|
resizerImage: HTMLImageElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPreviewerDrawOption {
|
||||||
|
mime?: 'png' | 'jpg' | 'jpeg' | 'svg';
|
||||||
|
srcKey?: keyof Pick<IElement, 'value' | 'laTexSVG'>;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { deepClone, getUUID, splitText } from '.'
|
import { deepClone, getUUID, splitText } from '.'
|
||||||
import { ElementType, IEditorOption, IElement } from '..'
|
import { ElementType, IEditorOption, IElement } from '..'
|
||||||
|
import { LaTexParticle } from '../core/draw/particle/latex/LaTexParticle'
|
||||||
import { defaultCheckboxOption } from '../dataset/constant/Checkbox'
|
import { defaultCheckboxOption } from '../dataset/constant/Checkbox'
|
||||||
import { ZERO } from '../dataset/constant/Common'
|
import { ZERO } from '../dataset/constant/Common'
|
||||||
import { defaultControlOption } from '../dataset/constant/Control'
|
import { defaultControlOption } from '../dataset/constant/Control'
|
||||||
@@ -214,6 +215,13 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
|
|||||||
if (el.type === ElementType.IMAGE) {
|
if (el.type === ElementType.IMAGE) {
|
||||||
el.id = getUUID()
|
el.id = getUUID()
|
||||||
}
|
}
|
||||||
|
if (el.type === ElementType.LATEX) {
|
||||||
|
const { svg, width, height } = LaTexParticle.convertLaTextToSVG(el.value)
|
||||||
|
el.width = el.width || width
|
||||||
|
el.height = el.height || height
|
||||||
|
el.laTexSVG = svg
|
||||||
|
el.id = getUUID()
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user