mind-map/simple-mind-map/src/utils/associativeLineText.js
2023-04-28 17:26:37 +08:00

157 lines
4.4 KiB
JavaScript

import { Text } from '@svgdotjs/svg.js'
import { getStrWithBrFromHtml } from './index'
// 创建文字节点
function createText(data) {
let g = this.draw.group()
g.click(e => {
e.stopPropagation()
})
g.on('dblclick', e => {
e.stopPropagation()
if (
!this.activeLine ||
this.activeLine[3] !== data.node ||
this.activeLine[4] !== data.toNode
) {
this.setActiveLine({
...data,
text: g
})
}
if (!this.activeLine) return
this.showEditTextBox(g)
})
return g
}
// 显示文本编辑框
function showEditTextBox(g) {
this.mindMap.emit('before_show_text_edit')
// 注册回车快捷键
this.mindMap.keyCommand.addShortcut('Enter', () => {
this.hideEditTextBox()
})
if (!this.textEditNode) {
this.textEditNode = document.createElement('div')
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
this.textEditNode.setAttribute('contenteditable', true)
this.textEditNode.addEventListener('keyup', e => {
e.stopPropagation()
})
this.textEditNode.addEventListener('click', e => {
e.stopPropagation()
})
document.body.appendChild(this.textEditNode)
}
let {
associativeLineTextFontSize,
associativeLineTextFontFamily,
associativeLineTextLineHeight
} = this.mindMap.themeConfig
let [, , , node, toNode] = this.activeLine
let textLines = (
this.getText(node, toNode) || this.mindMap.opt.defaultAssociativeLineText
).split(/\n/gim)
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
this.textEditNode.style.fontSize = associativeLineTextFontSize + 'px'
this.textEditNode.style.lineHeight = associativeLineTextLineHeight
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
this.textEditNode.innerHTML = textLines.join('<br>')
this.textEditNode.style.display = 'block'
this.updateTextEditBoxPos(g)
this.showTextEdit = true
}
// 更新文本编辑框位置
function updateTextEditBoxPos(g) {
let rect = g.node.getBoundingClientRect()
this.textEditNode.style.minWidth = rect.width + 10 + 'px'
this.textEditNode.style.minHeight = rect.height + 6 + 'px'
this.textEditNode.style.left = rect.left + 'px'
this.textEditNode.style.top = rect.top + 'px'
}
// 隐藏文本编辑框
function hideEditTextBox() {
if (!this.showTextEdit) {
return
}
let [path, , text, node, toNode] = this.activeLine
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
this.mindMap.execCommand('SET_NODE_DATA', node, {
associativeLineText: {
...(node.nodeData.data.associativeLineText || {}),
[toNode.nodeData.data.id]: str
}
})
this.textEditNode.style.display = 'none'
this.textEditNode.innerHTML = ''
this.showTextEdit = false
this.renderText(str, path, text)
this.mindMap.emit('hide_text_edit')
}
// 获取某根关联线的文字
function getText(node, toNode) {
let obj = node.nodeData.data.associativeLineText
if (!obj) {
return ''
}
return obj[toNode.nodeData.data.id] || ''
}
// 渲染关联线文字
function renderText(str, path, text) {
if (!str) return
let { associativeLineTextFontSize, associativeLineTextLineHeight } =
this.mindMap.themeConfig
text.clear()
let textArr = str.split(/\n/gim)
textArr.forEach((item, index) => {
let node = new Text().text(item)
node.y(associativeLineTextFontSize * associativeLineTextLineHeight * index)
this.styleText(node)
text.add(node)
})
updateTextPos(path, text)
}
// 给文本设置样式
function styleText(node) {
let {
associativeLineTextColor,
associativeLineTextFontSize,
associativeLineTextFontFamily
} = this.mindMap.themeConfig
node
.fill({
color: associativeLineTextColor
})
.css({
'font-family': associativeLineTextFontFamily,
'font-size': associativeLineTextFontSize
})
}
// 更新关联线文字位置
function updateTextPos(path, text) {
let pathLength = path.length()
let centerPoint = path.pointAt(pathLength / 2)
let { width: textWidth, height: textHeight } = text.bbox()
text.x(centerPoint.x - textWidth / 2)
text.y(centerPoint.y - textHeight / 2)
}
export default {
getText,
createText,
styleText,
showEditTextBox,
hideEditTextBox,
updateTextEditBoxPos,
renderText,
updateTextPos
}