|
@@ -5,6 +5,7 @@ import { MARGIN_DISTANCE } from '../../constants'
|
|
|
export class TextEditor {
|
|
|
constructor({
|
|
|
eventBus,
|
|
|
+ contentContainer,
|
|
|
container,
|
|
|
pagePtr,
|
|
|
editPagePtr,
|
|
@@ -12,9 +13,11 @@ export class TextEditor {
|
|
|
editAreaIndex,
|
|
|
viewport,
|
|
|
scale,
|
|
|
- messageHandler
|
|
|
+ messageHandler,
|
|
|
+ newAdd
|
|
|
}) {
|
|
|
this.eventBus = eventBus
|
|
|
+ this.contentContainer = contentContainer
|
|
|
this.container = container
|
|
|
this.pagePtr = pagePtr
|
|
|
this.editPagePtr = editPagePtr
|
|
@@ -23,6 +26,7 @@ export class TextEditor {
|
|
|
this.viewport = viewport
|
|
|
this.scale = scale
|
|
|
this.messageHandler = messageHandler
|
|
|
+ this.newAdd = newAdd
|
|
|
|
|
|
this.frame = null
|
|
|
this.canvas = null
|
|
@@ -112,13 +116,12 @@ export class TextEditor {
|
|
|
)
|
|
|
this.textContainer.append(textarea)
|
|
|
this.textarea = textarea
|
|
|
- let text = await this.messageHandler.sendWithPromise('GetText', this.editAreaPtr)
|
|
|
- // console.log(text)
|
|
|
+ let text = await this.getText()
|
|
|
this.textarea.innerHTML = text
|
|
|
|
|
|
this.frameContainer.append(this.textContainer)
|
|
|
|
|
|
- this.textContainer.addEventListener('click', this.onClick)
|
|
|
+ // this.textContainer.addEventListener('click', this.onClick)
|
|
|
this.textContainer.addEventListener('mousedown', this.onMousedown)
|
|
|
this.textContainer.addEventListener('mouseup', this.onMouseup)
|
|
|
|
|
@@ -274,6 +277,10 @@ export class TextEditor {
|
|
|
|
|
|
this.outerLine.addEventListener('mousedown', this.onMousedown)
|
|
|
this.outerLine.addEventListener('mouseup', this.onMouseup)
|
|
|
+
|
|
|
+ if (this.newAdd) {
|
|
|
+ this.goEditing()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
getActualRect (viewport, s, frame) {
|
|
@@ -321,12 +328,12 @@ export class TextEditor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- getInitialPoint () {
|
|
|
+ getInitialPoint (start, end) {
|
|
|
const s = this.scale
|
|
|
- const startX = this.start.x
|
|
|
- const startY = this.start.y
|
|
|
- const endX = this.end.x
|
|
|
- const endY = this.end.y
|
|
|
+ const startX = start.x
|
|
|
+ const startY = start.y
|
|
|
+ const endX = end.x
|
|
|
+ const endY = end.y
|
|
|
|
|
|
const { width, height, rotation } = this.viewport;
|
|
|
let x1, y1, x2, y2;
|
|
@@ -364,8 +371,6 @@ export class TextEditor {
|
|
|
}
|
|
|
|
|
|
handleMouseDown (e) {
|
|
|
- // e.stopPropagation()
|
|
|
-
|
|
|
if (this.state === 1) {
|
|
|
const operatorId = e.target.getAttribute('data-id')
|
|
|
|
|
@@ -393,7 +398,16 @@ export class TextEditor {
|
|
|
}
|
|
|
|
|
|
async handleMouseUp (e) {
|
|
|
- // e.stopPropagation()
|
|
|
+ if (e && e.target !== this.textarea && e.target !== this.textContainer) {
|
|
|
+ const newEvent = new MouseEvent('mouseup', {
|
|
|
+ offsetX: e.offsetX,
|
|
|
+ offsetY: e.offsetY,
|
|
|
+ type: e.type,
|
|
|
+ target: this.textarea
|
|
|
+ })
|
|
|
+ this.textarea.dispatchEvent(newEvent)
|
|
|
+ }
|
|
|
+
|
|
|
if (!this.mouseDown) return
|
|
|
this.mouseDown = false
|
|
|
|
|
@@ -405,11 +419,22 @@ export class TextEditor {
|
|
|
if (this.state === 0) {
|
|
|
this.state = 1
|
|
|
flag = false
|
|
|
+
|
|
|
+ this.contentContainer.selectedFrameIndex = this.editAreaIndex + 1
|
|
|
}
|
|
|
|
|
|
if (this.state === 1) {
|
|
|
this.frameContainer.classList.remove('editing')
|
|
|
|
|
|
+ const oldPoint = {
|
|
|
+ start: this.start,
|
|
|
+ end: this.end
|
|
|
+ }
|
|
|
+ const newPoint = {
|
|
|
+ start: this.newStart,
|
|
|
+ end: this.newEnd
|
|
|
+ }
|
|
|
+
|
|
|
const { pageX, pageY } = getClickPoint(e)
|
|
|
if (!(pageX === this.startState?.clickX && pageY === this.startState?.clickY) && this.newStart && this.newEnd) {
|
|
|
this.start = this.newStart
|
|
@@ -419,7 +444,7 @@ export class TextEditor {
|
|
|
this.container.append(this.outerLine)
|
|
|
|
|
|
if (this.mouseMoved) {
|
|
|
- const { start, end } = this.getInitialPoint()
|
|
|
+ const { start, end } = this.getInitialPoint(this.start, this.end)
|
|
|
const rect = {
|
|
|
left: start.x,
|
|
|
top: start.y,
|
|
@@ -433,6 +458,8 @@ export class TextEditor {
|
|
|
rect
|
|
|
})
|
|
|
this.updateCanvas()
|
|
|
+ const area = this.getEntireArea(oldPoint, newPoint)
|
|
|
+ this.contentContainer.updateSomeCanvas(area)
|
|
|
|
|
|
} else if (!this.mouseMoved && flag) {
|
|
|
this.state = 2
|
|
@@ -476,7 +503,8 @@ export class TextEditor {
|
|
|
if (this.selectedRects && !this.mouseMoved) {
|
|
|
this.clearSelectText()
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ this.textarea.focus()
|
|
|
this.textarea.addEventListener('blur', this.onBlur)
|
|
|
this.textarea.addEventListener('keydown', this.onKeydown)
|
|
|
this.textarea.addEventListener('textInput', this.onTextInput)
|
|
@@ -648,7 +676,10 @@ export class TextEditor {
|
|
|
// console.log('blur')
|
|
|
}
|
|
|
|
|
|
- handleOutside () {
|
|
|
+ async handleOutside () {
|
|
|
+ if (this.newAdd) {
|
|
|
+ this.state = 1
|
|
|
+ }
|
|
|
this.state = this.state === 2 ? 1 : this.state === 1 ? 0 : this.state
|
|
|
|
|
|
this.frameContainer.classList.remove('editing')
|
|
@@ -663,6 +694,8 @@ export class TextEditor {
|
|
|
this.frameContainer.classList.remove('selected')
|
|
|
|
|
|
this.outerLine.remove()
|
|
|
+
|
|
|
+ this.contentContainer.selectedFrameIndex = 0
|
|
|
}
|
|
|
|
|
|
if (this.state === 1) {
|
|
@@ -672,15 +705,20 @@ export class TextEditor {
|
|
|
}
|
|
|
|
|
|
this.textarea.removeEventListener('blur', this.onBlur)
|
|
|
- this.textarea.removeEventListener('keyup', this.onKeydown)
|
|
|
+ this.textarea.removeEventListener('keydown', this.onKeydown)
|
|
|
this.textarea.removeEventListener('textInput', this.onTextInput)
|
|
|
+
|
|
|
+ if (this.newAdd) {
|
|
|
+ const text = await this.getText()
|
|
|
+ if (text.length === 0) {
|
|
|
+ this.remove()
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
async handleKeyDown (e) {
|
|
|
- // e.stopPropagation()
|
|
|
let keyCode = e.keyCode || e.which
|
|
|
|
|
|
- console.log(keyCode)
|
|
|
let isToolKey = (keyCode === 9 || keyCode === 27 || keyCode === 20 || keyCode === 16 || keyCode === 17 || keyCode === 18 || keyCode === 91 || keyCode === 93 || keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40)
|
|
|
if (this.selectedCharRange && !isToolKey) {
|
|
|
const newChar = await this.getCharPlace('DeleteChars')
|
|
@@ -715,8 +753,6 @@ export class TextEditor {
|
|
|
}
|
|
|
|
|
|
async handleTextInput (e) {
|
|
|
- // e.stopPropagation()
|
|
|
- // console.log(e.data)
|
|
|
const newChar = await this.messageHandler.sendWithPromise('InsertText', {
|
|
|
editAreaPtr: this.editAreaPtr,
|
|
|
char: this.activeCharPlace,
|
|
@@ -729,6 +765,7 @@ export class TextEditor {
|
|
|
this.updateCursorLine()
|
|
|
}
|
|
|
|
|
|
+ // 更新canvas图
|
|
|
async updateCanvas() {
|
|
|
this.frame = await this.messageHandler.sendWithPromise('GetFrame', {
|
|
|
pagePtr: this.pagePtr,
|
|
@@ -774,16 +811,23 @@ export class TextEditor {
|
|
|
bottom: imgRect.bottom,
|
|
|
top: imgRect.top
|
|
|
})
|
|
|
+ this.imageArray = imageArray
|
|
|
|
|
|
this.canvas.width = imgRect.width
|
|
|
this.canvas.height = imgRect.height
|
|
|
|
|
|
+ this.drawCanvas()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 绘制canvas
|
|
|
+ drawCanvas () {
|
|
|
const ctx = this.canvas.getContext('2d')
|
|
|
- const imageData = ctx.createImageData(imgRect.width, imgRect.height)
|
|
|
- imageData.data.set(imageArray)
|
|
|
+ const imageData = ctx.createImageData(this.imgRect.width, this.imgRect.height)
|
|
|
+ imageData.data.set(this.imageArray)
|
|
|
ctx.putImageData(imageData, 0, 0)
|
|
|
}
|
|
|
|
|
|
+ // 更新光标位置
|
|
|
async updateCursorLine () {
|
|
|
let cursorPoints = await this.messageHandler.sendWithPromise('GetTextCursorPoints', {
|
|
|
pagePtr: this.pagePtr,
|
|
@@ -806,6 +850,7 @@ export class TextEditor {
|
|
|
this.cursor.append(cursorLine)
|
|
|
}
|
|
|
|
|
|
+ // 某个操作之后,获取光标所在字符的位置
|
|
|
async getCharPlace (action) {
|
|
|
const data = {
|
|
|
editAreaPtr: this.editAreaPtr,
|
|
@@ -820,6 +865,7 @@ export class TextEditor {
|
|
|
return await this.messageHandler.sendWithPromise(action, data)
|
|
|
}
|
|
|
|
|
|
+ // 根据定位点,获取选中区域的始末字符位置
|
|
|
async getCharsRange (startPoint, endPoint) {
|
|
|
return await this.messageHandler.sendWithPromise('SelectCharsRangeAtPos', {
|
|
|
pagePtr: this.pagePtr,
|
|
@@ -829,10 +875,17 @@ export class TextEditor {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ // 保存编辑
|
|
|
saveEdit () {
|
|
|
this.messageHandler.sendWithPromise('EndEdit', this.editPagePtr)
|
|
|
}
|
|
|
|
|
|
+ // 获取区域内的文本
|
|
|
+ getText () {
|
|
|
+ return this.messageHandler.sendWithPromise('GetText', this.editAreaPtr)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新outerline框的位置大小
|
|
|
updateOutline ({ start, end }) {
|
|
|
const rect = this.calculate(start, end)
|
|
|
|
|
@@ -870,6 +923,7 @@ export class TextEditor {
|
|
|
this.topRect.setAttribute("x", (rect.width - this.pointWidth + this.borderWidth) / 2)
|
|
|
}
|
|
|
|
|
|
+ // 获取选中区域里文本的矩形rect
|
|
|
async getCharsRect (startPoint, endPoint) {
|
|
|
if (
|
|
|
startPoint.SectionIndex === endPoint.SectionIndex &&
|
|
@@ -914,6 +968,7 @@ export class TextEditor {
|
|
|
return selectedRectList
|
|
|
}
|
|
|
|
|
|
+ // 选中文本的渲染
|
|
|
async selectText () {
|
|
|
const { start, end } = this.selectedCharRange
|
|
|
const selectedRectList = await this.getCharsRect(start, end)
|
|
@@ -956,7 +1011,7 @@ export class TextEditor {
|
|
|
prevSelectedRect.height
|
|
|
)
|
|
|
}
|
|
|
- await this.updateCanvas()
|
|
|
+ this.drawCanvas()
|
|
|
}
|
|
|
|
|
|
this.selectedRects = selectedRectList // store the new rectangles
|
|
@@ -972,10 +1027,10 @@ export class TextEditor {
|
|
|
selectedRect.height
|
|
|
)
|
|
|
}
|
|
|
-
|
|
|
this.updateCursorLine()
|
|
|
}
|
|
|
|
|
|
+ // 取消选中文本
|
|
|
async clearSelectText () {
|
|
|
if (this.selectedRects?.length) {
|
|
|
for (const selectedRect of this.selectedRects) {
|
|
@@ -987,11 +1042,12 @@ export class TextEditor {
|
|
|
selectedRect.height
|
|
|
)
|
|
|
}
|
|
|
- await this.updateCanvas()
|
|
|
+ this.drawCanvas()
|
|
|
}
|
|
|
this.selectedRects = null
|
|
|
}
|
|
|
|
|
|
+ // 属性面板 修改属性
|
|
|
async handlePropertyPanelChanged (props) {
|
|
|
if (this.state !== 2) return
|
|
|
for (const item in props) {
|
|
@@ -1078,17 +1134,103 @@ export class TextEditor {
|
|
|
this.selectText()
|
|
|
}
|
|
|
|
|
|
+ // 十六进制颜色转换为rgb
|
|
|
hexToRgb (hex) {
|
|
|
- hex = hex.replace("#", "");
|
|
|
+ hex = hex.replace("#", "")
|
|
|
|
|
|
- let shorthand = hex.length === 3;
|
|
|
+ let shorthand = hex.length === 3
|
|
|
|
|
|
- hex = shorthand ? hex.repeat(2) : hex;
|
|
|
+ hex = shorthand ? hex.repeat(2) : hex
|
|
|
|
|
|
- let r = parseInt(hex.substr(0, 2), 16);
|
|
|
- let g = parseInt(hex.substr(2, 2), 16);
|
|
|
- let b = parseInt(hex.substr(4, 2), 16);
|
|
|
+ let r = parseInt(hex.substr(0, 2), 16)
|
|
|
+ let g = parseInt(hex.substr(2, 2), 16)
|
|
|
+ let b = parseInt(hex.substr(4, 2), 16)
|
|
|
|
|
|
- return {r, g, b};
|
|
|
+ return {r, g, b}
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算编辑区域移动后,影响的整个区域的位置
|
|
|
+ getEntireArea (oldPoint, newPoint) {
|
|
|
+ let oldP = this.getInitialPoint(oldPoint.start, oldPoint.end)
|
|
|
+ let newP = this.getInitialPoint(newPoint.start, newPoint.end)
|
|
|
+
|
|
|
+ let left = Math.min(oldP.start.x, newP.start.x)
|
|
|
+ let top = Math.min(oldP.start.y, newP.start.y)
|
|
|
+ let right = Math.max(oldP.end.x, newP.end.x)
|
|
|
+ let bottom = Math.max(oldP.end.y, newP.end.y)
|
|
|
+
|
|
|
+ const area = {
|
|
|
+ left,
|
|
|
+ top,
|
|
|
+ right,
|
|
|
+ bottom
|
|
|
+ }
|
|
|
+ return area
|
|
|
+ }
|
|
|
+
|
|
|
+ // 直接进入编辑模式
|
|
|
+ goEditing () {
|
|
|
+ this.state = 2
|
|
|
+ this.frameContainer.classList.add('selected')
|
|
|
+ this.frameContainer.classList.add('editing')
|
|
|
+
|
|
|
+ this.activeCharPlace = {
|
|
|
+ SectionIndex: 0,
|
|
|
+ LineIndex: 0,
|
|
|
+ RunIndex: 0,
|
|
|
+ CharIndex: -1
|
|
|
+ }
|
|
|
+
|
|
|
+ const cursor = createSvg(
|
|
|
+ 'svg',
|
|
|
+ {
|
|
|
+ class: 'cursor-animation'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ position: 'absolute',
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ width: '100%',
|
|
|
+ height: '100%',
|
|
|
+ }
|
|
|
+ )
|
|
|
+ this.cursor = cursor
|
|
|
+ this.textContainer.append(this.cursor)
|
|
|
+
|
|
|
+ const cursorLine = createSvg(
|
|
|
+ 'line',
|
|
|
+ {
|
|
|
+ x1: 0,
|
|
|
+ x2: 0,
|
|
|
+ y1: 0,
|
|
|
+ y2: 20,
|
|
|
+ stroke: 'currentcolor'
|
|
|
+ },
|
|
|
+ )
|
|
|
+ this.cursorLine = cursorLine
|
|
|
+ this.cursor.append(cursorLine)
|
|
|
+
|
|
|
+ this.textarea.focus()
|
|
|
+ this.textarea.addEventListener('blur', this.onBlur)
|
|
|
+ this.textarea.addEventListener('keydown', this.onKeydown)
|
|
|
+ this.textarea.addEventListener('textInput', this.onTextInput)
|
|
|
+
|
|
|
+ const editPanel = document.querySelector('.edit-panel')
|
|
|
+ onClickOutside([this.textContainer, this.outerLine, editPanel], this.handleOutside.bind(this))
|
|
|
+ }
|
|
|
+
|
|
|
+ async remove () {
|
|
|
+ this.frameContainer.remove()
|
|
|
+
|
|
|
+ await this.messageHandler.send('RemoveEditAreaByIndex', {
|
|
|
+ editPagePtr: this.editPagePtr,
|
|
|
+ editAreaIndex: this.editAreaIndex
|
|
|
+ })
|
|
|
+ // await this.messageHandler.send('RemoveEditArea', {
|
|
|
+ // editPagePtr: this.editPagePtr,
|
|
|
+ // editAreaPtr: this.editAreaPtr
|
|
|
+ // })
|
|
|
+
|
|
|
+ this.contentContainer.removeEditor(this.editAreaIndex)
|
|
|
}
|
|
|
}
|