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('
') 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 }