mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-21 10:27:44 +08:00
194 lines
5.5 KiB
JavaScript
194 lines
5.5 KiB
JavaScript
import { Text } from '@svgdotjs/svg.js'
|
|
import {
|
|
getStrWithBrFromHtml,
|
|
focusInput,
|
|
selectAllInput
|
|
} from '../../utils/index'
|
|
|
|
// 创建文字节点
|
|
function createText(data) {
|
|
let g = this.associativeLineDraw.group()
|
|
const setActive = () => {
|
|
if (
|
|
!this.activeLine ||
|
|
this.activeLine[3] !== data.node ||
|
|
this.activeLine[4] !== data.toNode
|
|
) {
|
|
this.setActiveLine({
|
|
...data,
|
|
text: g
|
|
})
|
|
}
|
|
}
|
|
g.click(e => {
|
|
e.stopPropagation()
|
|
setActive()
|
|
})
|
|
g.on('dblclick', e => {
|
|
e.stopPropagation()
|
|
setActive()
|
|
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()
|
|
})
|
|
const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
|
|
targetNode.appendChild(this.textEditNode)
|
|
}
|
|
let {
|
|
associativeLineTextFontSize,
|
|
associativeLineTextFontFamily,
|
|
associativeLineTextLineHeight
|
|
} = this.mindMap.themeConfig
|
|
let { defaultAssociativeLineText, nodeTextEditZIndex } = this.mindMap.opt
|
|
let scale = this.mindMap.view.scale
|
|
let [, , , node, toNode] = this.activeLine
|
|
let text = this.getText(node, toNode)
|
|
let textLines = (text || defaultAssociativeLineText).split(/\n/gim)
|
|
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
|
|
this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
|
|
this.textEditNode.style.lineHeight =
|
|
textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
|
this.textEditNode.style.zIndex = nodeTextEditZIndex
|
|
this.textEditNode.innerHTML = textLines.join('<br>')
|
|
this.textEditNode.style.display = 'block'
|
|
this.updateTextEditBoxPos(g)
|
|
this.showTextEdit = true
|
|
// 如果是默认文本要全选输入框
|
|
if (text === '' || text === defaultAssociativeLineText) {
|
|
selectAllInput(this.textEditNode)
|
|
} else {
|
|
// 否则聚焦即可
|
|
focusInput(this.textEditNode)
|
|
}
|
|
}
|
|
|
|
// 删除文本编辑框元素
|
|
function removeTextEditEl() {
|
|
if (!this.textEditNode) return
|
|
const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
|
|
targetNode.removeChild(this.textEditNode)
|
|
}
|
|
|
|
// 处理画布缩放
|
|
function onScale() {
|
|
this.hideEditTextBox()
|
|
}
|
|
|
|
// 更新文本编辑框位置
|
|
function updateTextEditBoxPos(g) {
|
|
let rect = g.node.getBoundingClientRect()
|
|
if (this.textEditNode) {
|
|
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)
|
|
// 如果是默认文本,那么不保存
|
|
let isDefaultText = str === this.mindMap.opt.defaultAssociativeLineText
|
|
str = isDefaultText ? '' : str
|
|
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
|
associativeLineText: {
|
|
...(node.getData('associativeLineText') || {}),
|
|
[toNode.getData('uid')]: 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.getData('associativeLineText')
|
|
if (!obj) {
|
|
return ''
|
|
}
|
|
return obj[toNode.getData('uid')] || ''
|
|
}
|
|
|
|
// 渲染关联线文字
|
|
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,
|
|
onScale,
|
|
showEditTextBox,
|
|
removeTextEditEl,
|
|
hideEditTextBox,
|
|
updateTextEditBoxPos,
|
|
renderText,
|
|
updateTextPos
|
|
}
|