Feat:1.去除主题的行高配置;2.优化非富文本模式下的文本编辑效果

This commit is contained in:
街角小林 2024-10-16 18:40:47 +08:00
parent 4aa5a8c48b
commit 889ec13dbf
5 changed files with 51 additions and 27 deletions

View File

@ -212,3 +212,6 @@ export const selfCloseTagList = [
'meta', 'meta',
'area' 'area'
] ]
// 非富文本模式下的节点文本行高
export const noneRichTextNodeLineHeight = 1.2

View File

@ -8,7 +8,11 @@ import {
checkSmmFormatData, checkSmmFormatData,
getTextFromHtml getTextFromHtml
} from '../../utils' } from '../../utils'
import { ERROR_TYPES, CONSTANTS } from '../../constants/constant' import {
ERROR_TYPES,
CONSTANTS,
noneRichTextNodeLineHeight
} from '../../constants/constant'
// 节点文字编辑类 // 节点文字编辑类
export default class TextEdit { export default class TextEdit {
@ -217,7 +221,17 @@ export default class TextEdit {
if (!this.textEditNode) { if (!this.textEditNode) {
this.textEditNode = document.createElement('div') this.textEditNode = document.createElement('div')
this.textEditNode.classList.add('smm-node-edit-wrap') this.textEditNode.classList.add('smm-node-edit-wrap')
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: ${this.textNodePaddingY}px ${this.textNodePaddingX}px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;` this.textEditNode.style.cssText = `
position: fixed;
box-sizing: border-box;
background-color:#fff;
box-shadow: 0 0 20px rgba(0,0,0,.5);
padding: ${this.textNodePaddingY}px ${this.textNodePaddingX}px;
margin-left: -${this.textNodePaddingX}px;
margin-top: -${this.textNodePaddingY}px;
outline: none;
word-break: break-all;
`
this.textEditNode.setAttribute('contenteditable', true) this.textEditNode.setAttribute('contenteditable', true)
this.textEditNode.addEventListener('keyup', e => { this.textEditNode.addEventListener('keyup', e => {
e.stopPropagation() e.stopPropagation()
@ -254,30 +268,31 @@ export default class TextEdit {
this.mindMap.opt.customInnerElsAppendTo || document.body this.mindMap.opt.customInnerElsAppendTo || document.body
targetNode.appendChild(this.textEditNode) targetNode.appendChild(this.textEditNode)
} }
let scale = this.mindMap.view.scale const scale = this.mindMap.view.scale
let lineHeight = node.style.merge('lineHeight') const fontSize = node.style.merge('fontSize')
let fontSize = node.style.merge('fontSize') const textLines = (this.cacheEditingText || node.getData('text'))
let textLines = (this.cacheEditingText || node.getData('text'))
.split(/\n/gim) .split(/\n/gim)
.map(item => { .map(item => {
return htmlEscape(item) return htmlEscape(item)
}) })
let isMultiLine = node._textData.node.attr('data-ismultiLine') === 'true' const isMultiLine = node._textData.node.attr('data-ismultiLine') === 'true'
node.style.domText(this.textEditNode, scale, isMultiLine) node.style.domText(this.textEditNode, scale)
this.textEditNode.style.zIndex = nodeTextEditZIndex this.textEditNode.style.zIndex = nodeTextEditZIndex
this.textEditNode.innerHTML = textLines.join('<br>') this.textEditNode.innerHTML = textLines.join('<br>')
this.textEditNode.style.minWidth = this.textEditNode.style.minWidth =
rect.width + this.textNodePaddingX * 2 + 'px' rect.width + this.textNodePaddingX * 2 + 'px'
this.textEditNode.style.minHeight = this.textEditNode.style.minHeight = rect.height + 'px'
rect.height + this.textNodePaddingY * 2 + 'px'
this.textEditNode.style.left = rect.left + 'px' this.textEditNode.style.left = rect.left + 'px'
this.textEditNode.style.top = rect.top + 'px' this.textEditNode.style.top = rect.top + 'px'
this.textEditNode.style.display = 'block' this.textEditNode.style.display = 'block'
this.textEditNode.style.maxWidth = textAutoWrapWidth * scale + 'px' this.textEditNode.style.maxWidth = textAutoWrapWidth * scale + 'px'
if (isMultiLine && lineHeight !== 1) { if (isMultiLine) {
this.textEditNode.style.lineHeight = noneRichTextNodeLineHeight
this.textEditNode.style.transform = `translateY(${ this.textEditNode.style.transform = `translateY(${
-((lineHeight * fontSize - fontSize) / 2) * scale (((noneRichTextNodeLineHeight - 1) * fontSize) / 2) * scale
}px)` }px)`
} else {
this.textEditNode.style.lineHeight = 'normal'
} }
this.showTextEdit = true this.showTextEdit = true
// 选中文本 // 选中文本

View File

@ -229,20 +229,18 @@ class Style {
} }
// html文字节点 // html文字节点
domText(node, fontSizeScale = 1, isMultiLine) { domText(node, fontSizeScale = 1) {
const styles = { const styles = {
color: this.merge('color'), color: this.merge('color'),
fontFamily: this.merge('fontFamily'), fontFamily: this.merge('fontFamily'),
fontSize: this.merge('fontSize'), fontSize: this.merge('fontSize'),
fontWeight: this.merge('fontWeight'), fontWeight: this.merge('fontWeight'),
fontStyle: this.merge('fontStyle'), fontStyle: this.merge('fontStyle'),
textDecoration: this.merge('textDecoration'), textDecoration: this.merge('textDecoration')
lineHeight: this.merge('lineHeight')
} }
node.style.fontFamily = styles.fontFamily node.style.fontFamily = styles.fontFamily
node.style.fontSize = styles.fontSize * fontSizeScale + 'px' node.style.fontSize = styles.fontSize * fontSizeScale + 'px'
node.style.fontWeight = styles.fontWeight || 'normal' node.style.fontWeight = styles.fontWeight || 'normal'
node.style.lineHeight = !isMultiLine ? 'normal' : styles.lineHeight
node.style.fontStyle = styles.fontStyle node.style.fontStyle = styles.fontStyle
} }

View File

@ -1,5 +1,4 @@
import { import {
measureText,
resizeImgSize, resizeImgSize,
removeHtmlStyle, removeHtmlStyle,
addHtmlStyle, addHtmlStyle,
@ -11,7 +10,19 @@ import {
} from '../../../utils' } from '../../../utils'
import { Image as SVGImage, SVG, A, G, Rect, Text } from '@svgdotjs/svg.js' import { Image as SVGImage, SVG, A, G, Rect, Text } from '@svgdotjs/svg.js'
import iconsSvg from '../../../svg/icons' import iconsSvg from '../../../svg/icons'
import { CONSTANTS } from '../../../constants/constant' import {
CONSTANTS,
noneRichTextNodeLineHeight
} from '../../../constants/constant'
// 测量svg文本宽高
const measureText = (text, style) => {
const g = new G()
const node = new Text().text(text)
style.text(node)
g.add(node)
return g.bbox()
}
// 标签默认的样式 // 标签默认的样式
const defaultTagStyle = { const defaultTagStyle = {
@ -218,16 +229,14 @@ function createTextNode(specifyText) {
} }
let g = new G() let g = new G()
let fontSize = this.getStyle('fontSize', false) let fontSize = this.getStyle('fontSize', false)
let lineHeight = this.getStyle('lineHeight', false)
// 文本超长自动换行 // 文本超长自动换行
let textStyle = this.style.getTextFontStyle()
let textArr = [] let textArr = []
if (!isUndef(text)) { if (!isUndef(text)) {
textArr = String(text).split(/\n/gim) textArr = String(text).split(/\n/gim)
} }
const { textAutoWrapWidth: maxWidth, emptyTextMeasureHeightText } = const { textAutoWrapWidth: maxWidth, emptyTextMeasureHeightText } =
this.mindMap.opt this.mindMap.opt
let isMultiLine = false let isMultiLine = textArr.length > 1
textArr.forEach((item, index) => { textArr.forEach((item, index) => {
let arr = item.split('') let arr = item.split('')
let lines = [] let lines = []
@ -235,7 +244,7 @@ function createTextNode(specifyText) {
while (arr.length) { while (arr.length) {
let str = arr.shift() let str = arr.shift()
let text = [...line, str].join('') let text = [...line, str].join('')
if (measureText(text, textStyle).width <= maxWidth) { if (measureText(text, this.style).width <= maxWidth) {
line.push(str) line.push(str)
} else { } else {
lines.push(line.join('')) lines.push(line.join(''))
@ -254,7 +263,10 @@ function createTextNode(specifyText) {
textArr.forEach((item, index) => { textArr.forEach((item, index) => {
let node = new Text().text(item) let node = new Text().text(item)
this.style.text(node) this.style.text(node)
node.y(fontSize * lineHeight * index) node.y(
fontSize * noneRichTextNodeLineHeight * index +
((noneRichTextNodeLineHeight - 1) * fontSize) / 2
)
g.add(node) g.add(node)
}) })
let { width, height } = g.bbox() let { width, height } = g.bbox()

View File

@ -72,7 +72,6 @@ export default {
fontSize: 16, fontSize: 16,
fontWeight: 'bold', fontWeight: 'bold',
fontStyle: 'normal', fontStyle: 'normal',
lineHeight: 1.5,
borderColor: 'transparent', borderColor: 'transparent',
borderWidth: 0, borderWidth: 0,
borderDasharray: 'none', borderDasharray: 'none',
@ -103,7 +102,6 @@ export default {
fontSize: 16, fontSize: 16,
fontWeight: 'normal', fontWeight: 'normal',
fontStyle: 'normal', fontStyle: 'normal',
lineHeight: 1.5,
borderColor: '#549688', borderColor: '#549688',
borderWidth: 1, borderWidth: 1,
borderDasharray: 'none', borderDasharray: 'none',
@ -131,7 +129,6 @@ export default {
fontSize: 14, fontSize: 14,
fontWeight: 'normal', fontWeight: 'normal',
fontStyle: 'normal', fontStyle: 'normal',
lineHeight: 1.5,
borderColor: 'transparent', borderColor: 'transparent',
borderWidth: 0, borderWidth: 0,
borderRadius: 5, borderRadius: 5,
@ -159,7 +156,6 @@ export default {
fontSize: 16, fontSize: 16,
fontWeight: 'normal', fontWeight: 'normal',
fontStyle: 'normal', fontStyle: 'normal',
lineHeight: 1.5,
borderColor: '#549688', borderColor: '#549688',
borderWidth: 1, borderWidth: 1,
borderDasharray: 'none', borderDasharray: 'none',