Compare commits

..

28 Commits

Author SHA1 Message Date
街角小林
0041be9892 打包0.12.1 2024-10-25 10:02:17 +08:00
街角小林
7ebab0298b 打包Demo 2024-10-24 18:27:39 +08:00
街角小林
079b963ae3 Fix:修复拖拽调整节点宽度后回退操作时节点宽度没有回退的问题 2024-10-24 18:25:31 +08:00
街角小林
fb6fcd6bd3 Fix:修复当存在滚动条插件,且思维导图被限制在画布内时,演示模式中边缘节点无法正常显示的问题 2024-10-24 09:49:07 +08:00
街角小林
59950b2ba0 Demo:增加是否自动进入文本编辑的配置 2024-10-24 09:35:52 +08:00
街角小林
1f23257917 Demo:增加是否一直显示展开收起按钮的配置 2024-10-24 09:26:25 +08:00
街角小林
4e1db01f44 Demo:增加节点标签显示位置的配置 2024-10-24 09:20:34 +08:00
街角小林
38769c3b55 打包demo 2024-10-23 18:14:06 +08:00
街角小林
a4ef09779d Demo:将设置类的配置从基础样式移到单独的设置栏中 2024-10-23 18:11:48 +08:00
街角小林
4821dd6052 打包Demo 2024-10-23 09:30:19 +08:00
街角小林
f33c886d6a Feat:修复处于文本编辑中切换为只读模式时文本未保存的问题 2024-10-23 09:26:25 +08:00
街角小林
b5b8c2be60 Merge pull request #951 from ZhangMingZhao1/fix-exit-edit-pr
fix: 修复设置readonly如果处于编辑态还能编辑的问题
2024-10-23 09:18:18 +08:00
街角小林
4a7485c58e Demo:节点右键菜单新增添加待办按钮 2024-10-22 17:32:46 +08:00
街角小林
c097d20748 Feat:去除代码中对编号插件的硬编码,新增节点库前置内容的创建逻辑 2024-10-22 17:22:54 +08:00
ZhangMingZhao1
eeeae7d0e2 fix: 修复设置readonly如果处于编辑态还能编辑的问题 2024-10-22 10:49:29 +08:00
街角小林
dd3e169946 Fix:修复在节点文本编辑中调用destroy方法时setBackgroundStyle方法会报错的问题 2024-10-21 09:37:13 +08:00
街角小林
b895a58194 打包Demo 2024-10-17 18:02:25 +08:00
街角小林
2b42b9fafa Demo:支持设置节点文本编辑是否实时更新节点大小,默认开启 2024-10-17 17:56:03 +08:00
街角小林
c2125b07ca Feat:非富文本模式文本编辑框的样式同步节点样式 2024-10-17 17:54:41 +08:00
街角小林
eb342bf69b Feat:当开启openRealtimeRenderOnNodeTextEdit选项后,会去除文本编辑框的背景和阴影,达到类似原地编辑的效果 2024-10-17 13:51:17 +08:00
街角小林
a7eb66a6c9 Feat:after_update_config事件新增上一次配置的返回参数 2024-10-17 11:32:35 +08:00
街角小林
e24fd9bdbb Fix:修复开启maxImgResizeWidthInheritTheme选项后第一次上传图片拖动图片到最大值会导致后续调整按钮无法显示的问题 2024-10-17 09:34:17 +08:00
街角小林
34d7c6fed2 Fix:修复开启openRealtimeRenderOnNodeTextEdit选项后非富文本模式编辑文本时输入框会左右抖动的问题 2024-10-17 09:13:55 +08:00
街角小林
a0f88031c1 Demo:去除节点样式的行高配置 2024-10-16 18:42:38 +08:00
街角小林
889ec13dbf Feat:1.去除主题的行高配置;2.优化非富文本模式下的文本编辑效果 2024-10-16 18:40:47 +08:00
街角小林
4aa5a8c48b Fix:修复给Text文本设置的字号没有加单位导致在一些浏览器上不生效的问题 2024-10-16 17:39:25 +08:00
街角小林
0ec20b8fa0 update 2024-10-16 10:09:46 +08:00
街角小林
f3285cf4e6 Doc update 2024-10-15 17:08:29 +08:00
39 changed files with 1192 additions and 803 deletions

View File

@@ -44,7 +44,7 @@ Github[releases](https://github.com/wanglin2/mind-map/releases)。百度云
官方提供了如下插件,可根据需求按需引入(某个功能不生效大概率是因为你没有引入对应的插件),具体使用方式请查看文档:
> RichText节点富文本插件、Select鼠标多选节点插件、Drag节点拖拽插件、AssociativeLine关联线插件、Export导出插件、KeyboardNavigation键盘导航插件、MiniMap小地图插件、Watermark水印插件、TouchEvent移动端触摸事件支持插件、NodeImgAdjust拖拽调整节点图片大小插件、Search搜索插件、Painter节点格式刷插件、Scrollbar滚动条插件、Formula数学公式插件、Cooperate协同编辑插件、RainbowLines彩虹线条插件、Demonstrate演示模式插件、OuterFrame外框插件、HandDrawnLikeStyle手绘风格插件[收费]、Notation节点标记插件[收费]、Numbers节点编号插件[收费]、FreemindFreemind格式导入导出插件[收费]、ExcelExcel格式导入导出插件[收费]
> RichText节点富文本插件、Select鼠标多选节点插件、Drag节点拖拽插件、AssociativeLine关联线插件、Export导出插件、KeyboardNavigation键盘导航插件、MiniMap小地图插件、Watermark水印插件、TouchEvent移动端触摸事件支持插件、NodeImgAdjust拖拽调整节点图片大小插件、Search搜索插件、Painter节点格式刷插件、Scrollbar滚动条插件、Formula数学公式插件、Cooperate协同编辑插件、RainbowLines彩虹线条插件、Demonstrate演示模式插件、OuterFrame外框插件、HandDrawnLikeStyle手绘风格插件[收费]、Notation节点标记插件[收费]、Numbers节点编号插件[收费]、FreemindFreemind格式导入导出插件[收费]、ExcelExcel格式导入导出插件[收费]、Checkbox待办插件[收费]
本项目不会实现的特性:
@@ -117,11 +117,13 @@ const mindMap = new MindMap({
# 请作者喝杯咖啡
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡,你的支持是开发者持续维护的最大动力~
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。
>
> 也可以通过购买付费插件来支持我们:[付费插件](https://wanglin2.github.io/mind-map-docs/plugins/about.html)。
>
> 为什么需要你的赞助simple-mind-map 的目标是成为开源中最好的思维导图为开发者提供一个快速实现思维导图产品的js库为用户提供一个免费好用的思维导图软件为了这个目标作者已经持续开发维护了3年多耗费了非常多的精力随着时间的推移simple-mind-map 已经取得了一定的成绩,相比最初,无论是功能,还是体验都已经有了翻天覆地的改变,但是收益方面却可以忽略不计,因为 simple-mind-map 是采用 MIT 许可的开源项目,永久免费,保留版权下可随意商用,这也意味着很难直接通过项目获取收益,为爱发电的激情总会慢慢消退,所以你的赞助对项目的可持续发展非常重要,是作者持续维护的最大动力。
<p>
<img src="./web/src/assets/img/alipay.jpg" style="width: 300px" />
@@ -489,4 +491,12 @@ const mindMap = new MindMap({
<img src="./web/src/assets/avatar/海云.jpg" style="width: 50px;height: 50px;" />
<span>海云</span>
</span>
<span>
<img src="./web/src/assets/avatar/皮老板.jpg" style="width: 50px;height: 50px;" />
<span>皮老板</span>
</span>
<span>
<img src="./web/src/assets/avatar/h.r.w.jpg" style="width: 50px;height: 50px;" />
<span>h.r.w</span>
</span>
</p>

File diff suppressed because one or more lines are too long

2
dist/js/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -9,7 +9,7 @@
})
} catch (error) {
console.log(error)
}</script><link href="dist/css/chunk-vendors.css?63f5fae2a1a38e74b08f" rel="stylesheet"><link href="dist/css/app.css?63f5fae2a1a38e74b08f" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
}</script><link href="dist/css/chunk-vendors.css?fc8e52cca177f49cac0d" rel="stylesheet"><link href="dist/css/app.css?fc8e52cca177f49cac0d" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
@@ -74,4 +74,4 @@
// 可以通过window.$bus.$on()来监听应用的一些事件
// 实例化页面
window.initApp()
}</script><script src="dist/js/chunk-vendors.js?63f5fae2a1a38e74b08f"></script><script src="dist/js/app.js?63f5fae2a1a38e74b08f"></script></body></html>
}</script><script src="dist/js/chunk-vendors.js?fc8e52cca177f49cac0d"></script><script src="dist/js/app.js?fc8e52cca177f49cac0d"></script></body></html>

View File

@@ -29,7 +29,7 @@ MindMap.markdown = markdown
MindMap.iconList = icons.nodeIconList
MindMap.constants = constants
MindMap.defaultTheme = defaultTheme
MindMap.version = '0.12.0'
MindMap.version = '0.12.1'
MindMap.usePlugin(MiniMap)
.usePlugin(Watermark)

View File

@@ -56,6 +56,26 @@ class MindMap {
this.cssEl = null
this.cssTextMap = {} // 该样式在实例化时会动态添加到页面同时导出为svg时也会添加到svg源码中
// 节点前置内容列表
/*
{
name: '',// 一个唯一的类型标识
// 创建节点的显示内容:节点元素、宽高
createContent: (node) => {
return {
node: null,
width: 0,
height: 0
}
},
// 创建保存到节点实例的opt对象中的数据
createNodeData: () => {},
// 更新节点实例的opt数据返回数据是否改变了
updateNodeData: () => {},
}
*/
this.nodeInnerPrefixList = []
// 画布
this.initContainer()
@@ -339,8 +359,11 @@ class MindMap {
// 更新配置
updateConfig(opt = {}) {
this.emit('before_update_config', this.opt)
const lastOpt = {
...this.opt
}
this.opt = this.handleOpt(merge.all([defaultOpt, this.opt, opt]))
this.emit('after_update_config', this.opt)
this.emit('after_update_config', this.opt, lastOpt)
}
// 获取当前布局结构
@@ -456,11 +479,16 @@ class MindMap {
}
const isReadonly = mode === CONSTANTS.MODE.READONLY
if (isReadonly === this.opt.readonly) return
this.opt.readonly = isReadonly
if (this.opt.readonly) {
if (isReadonly) {
// 如果处于编辑态,要隐藏所有的编辑框
if (this.renderer.textEdit.isShowTextEdit()) {
this.renderer.textEdit.hideEditTextBox()
this.command.originAddHistory()
}
// 取消当前激活的元素
this.execCommand('CLEAR_ACTIVE_NODE')
}
this.opt.readonly = isReadonly
this.emit('mode_change', mode)
}

View File

@@ -1,6 +1,6 @@
{
"name": "simple-mind-map",
"version": "0.12.0",
"version": "0.12.1",
"description": "一个简单的web在线思维导图",
"authors": [
{

View File

@@ -167,7 +167,8 @@ export const nodeDataNoStylePropList = [
'range',
'customLeft',
'customTop',
'customTextWidth'
'customTextWidth',
'checkbox'
]
// 错误类型
@@ -212,3 +213,6 @@ export const selfCloseTagList = [
'meta',
'area'
]
// 非富文本模式下的节点文本行高
export const noneRichTextNodeLineHeight = 1.2

View File

@@ -226,7 +226,7 @@ export const defaultOpt = {
// 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%
// 该选项实际影响的是render.moveNodeToCenter方法moveNodeToCenter方法本身也存在第二个参数resetScale来设置是否复位如果resetScale参数没有传递那么使用resetScaleOnMoveNodeToCenter配置否则使用resetScale配置
resetScaleOnMoveNodeToCenter: false,
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。如果存在编号、任务勾选框内容,这里添加的前置内容会在这两者之后
createNodePrefixContent: null,
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
createNodePostfixContent: null,

View File

@@ -18,6 +18,7 @@ class Command {
this.activeHistoryIndex = 0
// 注册快捷键
this.registerShortcutKeys()
this.originAddHistory = this.addHistory.bind(this)
this.addHistory = throttle(
this.addHistory,
this.mindMap.opt.addHistoryTime,

View File

@@ -133,6 +133,11 @@ class Render {
// 绑定事件
bindEvent() {
const {
openPerformance,
performanceConfig,
openRealtimeRenderOnNodeTextEdit
} = this.mindMap.opt
// 画布点击事件清除当前激活节点列表
this.mindMap.on('draw_click', e => {
this.clearActiveNodeListOnDrawClick(e, 'click')
@@ -147,34 +152,6 @@ class Render {
this.setRootNodeCenter()
})
// 性能模式
this.performanceMode()
// 实时渲染当节点文本编辑时
if (this.mindMap.opt.openRealtimeRenderOnNodeTextEdit) {
this.mindMap.on('node_text_edit_change', ({ node, text }) => {
node._textData = node.createTextNode(text)
const { width, height } = node.getNodeRect()
node.width = width
node.height = height
node.layout()
this.mindMap.render(() => {
this.textEdit.updateTextEditNode()
})
})
}
// 处理非https下的复制黏贴问题
// 暂时不启用,因为给页面的其他输入框(比如节点文本编辑框)粘贴内容也会触发,冲突问题暂时没有想到好的解决方法,不可能要求所有输入框都阻止冒泡
// if (!navigator.clipboard) {
// this.handlePaste = this.handlePaste.bind(this)
// window.addEventListener('paste', this.handlePaste)
// this.mindMap.on('beforeDestroy', () => {
// window.removeEventListener('paste', this.handlePaste)
// })
// }
}
// 性能模式,懒加载节点
performanceMode() {
const { openPerformance, performanceConfig } = this.mindMap.opt
const onViewDataChange = throttle(() => {
if (this.root) {
this.mindMap.emit('node_tree_render_start')
@@ -187,24 +164,57 @@ class Render {
)
}
}, performanceConfig.time)
let lastOpen = false
this.mindMap.on('before_update_config', opt => {
lastOpen = opt.openPerformance
})
this.mindMap.on('after_update_config', opt => {
if (opt.openPerformance && !lastOpen) {
// 动态开启性能模式
this.mindMap.on('view_data_change', onViewDataChange)
if (openPerformance) {
this.mindMap.on('view_data_change', onViewDataChange)
}
// 文本编辑时实时更新节点大小
this.onNodeTextEditChange = this.onNodeTextEditChange.bind(this)
if (openRealtimeRenderOnNodeTextEdit) {
this.mindMap.on('node_text_edit_change', this.onNodeTextEditChange)
}
// 监听配置改变事件
this.mindMap.on('after_update_config', (opt, lastOpt) => {
// 更新openPerformance配置
if (opt.openPerformance !== lastOpt.openPerformance) {
this.mindMap[opt.openPerformance ? 'on' : 'off'](
'view_data_change',
onViewDataChange
)
this.forceLoadNode()
}
if (!opt.openPerformance && lastOpen) {
// 动态关闭性能模式
this.mindMap.off('view_data_change', onViewDataChange)
this.forceLoadNode()
// 更新openRealtimeRenderOnNodeTextEdit配置
if (
opt.openRealtimeRenderOnNodeTextEdit !==
lastOpt.openRealtimeRenderOnNodeTextEdit
) {
this.mindMap[opt.openRealtimeRenderOnNodeTextEdit ? 'on' : 'off'](
'node_text_edit_change',
this.onNodeTextEditChange
)
}
})
if (!openPerformance) return
this.mindMap.on('view_data_change', onViewDataChange)
// 处理非https下的复制黏贴问题
// 暂时不启用,因为给页面的其他输入框(比如节点文本编辑框)粘贴内容也会触发,冲突问题暂时没有想到好的解决方法,不可能要求所有输入框都阻止冒泡
// if (!navigator.clipboard) {
// this.handlePaste = this.handlePaste.bind(this)
// window.addEventListener('paste', this.handlePaste)
// this.mindMap.on('beforeDestroy', () => {
// window.removeEventListener('paste', this.handlePaste)
// })
// }
}
// 监听文本编辑事件,实时更新节点大小
onNodeTextEditChange({ node, text }) {
node._textData = node.createTextNode(text)
const { width, height } = node.getNodeRect()
node.width = width
node.height = height
node.layout()
this.mindMap.render(() => {
// 输入框的left不会改变所以无需更新
this.textEdit.updateTextEditNode(['left'])
})
}
// 强制渲染节点,不考虑是否在画布可视区域内

View File

@@ -6,9 +6,15 @@ import {
htmlEscape,
handleInputPasteText,
checkSmmFormatData,
getTextFromHtml
getTextFromHtml,
isWhite,
getVisibleColorFromTheme
} from '../../utils'
import { ERROR_TYPES, CONSTANTS } from '../../constants/constant'
import {
ERROR_TYPES,
CONSTANTS,
noneRichTextNodeLineHeight
} from '../../constants/constant'
// 节点文字编辑类
export default class TextEdit {
@@ -92,6 +98,32 @@ export default class TextEdit {
this.mindMap.on('beforeDestroy', () => {
this.unBindEvent()
})
this.mindMap.on('after_update_config', (opt, lastOpt) => {
if (
opt.openRealtimeRenderOnNodeTextEdit !==
lastOpt.openRealtimeRenderOnNodeTextEdit
) {
if (this.mindMap.richText) {
this.mindMap.richText.onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
opt.openRealtimeRenderOnNodeTextEdit
)
} else {
this.onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
opt.openRealtimeRenderOnNodeTextEdit
)
}
}
if (
opt.enableAutoEnterTextEditWhenKeydown !==
lastOpt.enableAutoEnterTextEditWhenKeydown
) {
window[
opt.enableAutoEnterTextEditWhenKeydown
? 'addEventListener'
: 'removeEventListener'
]('keydown', this.onKeydown)
}
})
}
// 解绑事件
@@ -158,7 +190,8 @@ export default class TextEdit {
if (node.isUseCustomNodeContent()) {
return
}
const { beforeTextEdit } = this.mindMap.opt
const { beforeTextEdit, openRealtimeRenderOnNodeTextEdit } =
this.mindMap.opt
if (typeof beforeTextEdit === 'function') {
let isShow = false
try {
@@ -172,7 +205,12 @@ export default class TextEdit {
this.currentNode = node
const { offsetLeft, offsetTop } = checkNodeOuter(this.mindMap, node)
this.mindMap.view.translateXY(offsetLeft, offsetTop)
const rect = node._textData.node.node.getBoundingClientRect()
const g = node._textData.node
const rect = g.node.getBoundingClientRect()
// 如果开启了大小实时更新,那么直接隐藏节点原文本
if (openRealtimeRenderOnNodeTextEdit) {
g.hide()
}
const params = {
node,
rect,
@@ -187,6 +225,21 @@ export default class TextEdit {
this.showEditTextBox(params)
}
// 当openRealtimeRenderOnNodeTextEdit配置更新后需要更新编辑框样式
onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
openRealtimeRenderOnNodeTextEdit
) {
if (!this.textEditNode) return
this.textEditNode.style.background = openRealtimeRenderOnNodeTextEdit
? 'transparent'
: this.currentNode
? this.getBackground(this.currentNode)
: ''
this.textEditNode.style.boxShadow = openRealtimeRenderOnNodeTextEdit
? 'none'
: '0 0 20px rgba(0,0,0,.5)'
}
// 处理画布缩放
onScale() {
const node = this.getCurrentEditNode()
@@ -208,8 +261,12 @@ export default class TextEdit {
// 显示文本编辑框
showEditTextBox({ node, rect, isInserting, isFromKeyDown, isFromScale }) {
if (this.showTextEdit) return
const { nodeTextEditZIndex, textAutoWrapWidth, selectTextOnEnterEditText } =
this.mindMap.opt
const {
nodeTextEditZIndex,
textAutoWrapWidth,
selectTextOnEnterEditText,
openRealtimeRenderOnNodeTextEdit
} = this.mindMap.opt
if (!isFromScale) {
this.mindMap.emit('before_show_text_edit')
}
@@ -217,7 +274,21 @@ export default class TextEdit {
if (!this.textEditNode) {
this.textEditNode = document.createElement('div')
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;
${
openRealtimeRenderOnNodeTextEdit
? ''
: `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;
line-break: anywhere;
`
this.textEditNode.setAttribute('contenteditable', true)
this.textEditNode.addEventListener('keyup', e => {
e.stopPropagation()
@@ -254,30 +325,34 @@ export default class TextEdit {
this.mindMap.opt.customInnerElsAppendTo || document.body
targetNode.appendChild(this.textEditNode)
}
let scale = this.mindMap.view.scale
let lineHeight = node.style.merge('lineHeight')
let fontSize = node.style.merge('fontSize')
let textLines = (this.cacheEditingText || node.getData('text'))
const scale = this.mindMap.view.scale
const fontSize = node.style.merge('fontSize')
const textLines = (this.cacheEditingText || node.getData('text'))
.split(/\n/gim)
.map(item => {
return htmlEscape(item)
})
let isMultiLine = node._textData.node.attr('data-ismultiLine') === 'true'
node.style.domText(this.textEditNode, scale, isMultiLine)
const isMultiLine = node._textData.node.attr('data-ismultiLine') === 'true'
node.style.domText(this.textEditNode, scale)
if (!openRealtimeRenderOnNodeTextEdit) {
this.textEditNode.style.background = this.getBackground(node)
}
this.textEditNode.style.zIndex = nodeTextEditZIndex
this.textEditNode.innerHTML = textLines.join('<br>')
this.textEditNode.style.minWidth =
rect.width + this.textNodePaddingX * 2 + 'px'
this.textEditNode.style.minHeight =
rect.height + this.textNodePaddingY * 2 + 'px'
this.textEditNode.style.minHeight = rect.height + 'px'
this.textEditNode.style.left = rect.left + 'px'
this.textEditNode.style.top = rect.top + 'px'
this.textEditNode.style.display = 'block'
this.textEditNode.style.maxWidth = textAutoWrapWidth * scale + 'px'
if (isMultiLine && lineHeight !== 1) {
if (isMultiLine) {
this.textEditNode.style.lineHeight = noneRichTextNodeLineHeight
this.textEditNode.style.transform = `translateY(${
-((lineHeight * fontSize - fontSize) / 2) * scale
(((noneRichTextNodeLineHeight - 1) * fontSize) / 2) * scale
}px)`
} else {
this.textEditNode.style.lineHeight = 'normal'
}
this.showTextEdit = true
// 选中文本
@@ -293,7 +368,8 @@ export default class TextEdit {
}
// 更新文本编辑框的大小和位置
updateTextEditNode() {
// notChangeProps不会发生改变的属性列表
updateTextEditNode(notChangeProps = []) {
if (this.mindMap.richText) {
this.mindMap.richText.updateTextEditNode()
return
@@ -306,10 +382,32 @@ export default class TextEdit {
rect.width + this.textNodePaddingX * 2 + 'px'
this.textEditNode.style.minHeight =
rect.height + this.textNodePaddingY * 2 + 'px'
this.textEditNode.style.left = rect.left + 'px'
if (!notChangeProps.includes('left'))
this.textEditNode.style.left = rect.left + 'px'
this.textEditNode.style.top = rect.top + 'px'
}
// 获取编辑区域的背景填充
getBackground(node) {
const gradientStyle = node.style.merge('gradientStyle')
// 当前使用的是渐变色背景
if (gradientStyle) {
const startColor = node.style.merge('startColor')
const endColor = node.style.merge('endColor')
return `linear-gradient(to right, ${startColor}, ${endColor})`
} else {
// 单色背景
const bgColor = node.style.merge('fillColor')
const color = node.style.merge('color')
// 默认使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见
return bgColor === 'transparent'
? isWhite(color)
? getVisibleColorFromTheme(this.mindMap.themeConfig)
: '#fff'
: bgColor
}
}
// 删除文本编辑元素
removeTextEditEl() {
if (this.mindMap.richText) {
@@ -334,17 +432,8 @@ export default class TextEdit {
if (!this.showTextEdit) {
return
}
this.mindMap.execCommand(
'SET_NODE_TEXT',
this.currentNode,
this.getEditText()
)
if (this.currentNode.isGeneralization) {
// 概要节点
this.currentNode.generalizationBelongNode.updateGeneralization()
}
this.mindMap.render()
const currentNode = this.currentNode
const text = this.getEditText()
this.currentNode = null
this.textEditNode.style.display = 'none'
this.textEditNode.innerHTML = ''
@@ -353,6 +442,12 @@ export default class TextEdit {
this.textEditNode.style.fontWeight = 'normal'
this.textEditNode.style.transform = 'translateY(0)'
this.showTextEdit = false
this.mindMap.execCommand('SET_NODE_TEXT', currentNode, text)
// if (currentNode.isGeneralization) {
// // 概要节点
// currentNode.generalizationBelongNode.updateGeneralization()
// }
this.mindMap.render()
this.mindMap.emit(
'hide_text_edit',
this.textEditNode,

View File

@@ -1,6 +1,6 @@
import Style from './Style'
import Shape from './Shape'
import { G, Rect, Text } from '@svgdotjs/svg.js'
import { G, Rect, Text, SVG } from '@svgdotjs/svg.js'
import nodeGeneralizationMethods from './nodeGeneralization'
import nodeExpandBtnMethods from './nodeExpandBtn'
import nodeCommandWrapsMethods from './nodeCommandWraps'
@@ -89,7 +89,6 @@ class MindMapNode {
this.noteEl = null
this.noteContentIsShow = false
this._attachmentData = null
this._numberData = null
this._prefixData = null
this._postfixData = null
this._expandBtn = null
@@ -113,8 +112,6 @@ class MindMapNode {
// 概要节点的宽高
this._generalizationNodeWidth = 0
this._generalizationNodeHeight = 0
// 编号字符
this.number = opt.number || ''
// 各种文字信息的间距
this.textContentItemMargin = this.mindMap.opt.textContentMargin
// 图片和文字节点的间距
@@ -207,10 +204,10 @@ class MindMapNode {
}
// 创建节点的各个内容对象数据
// recreateTypes[] custom、image、icon、text、hyperlink、tag、note、attachment、numbers、prefix、postfix
// recreateTypes[] custom、image、icon、text、hyperlink、tag、note、attachment、numbers、prefix、postfix、checkbox
createNodeData(recreateTypes) {
// 自定义节点内容
let {
const {
isUseCustomNodeContent,
customCreateNodeContent,
createNodePrefixContent,
@@ -226,9 +223,11 @@ class MindMapNode {
'tag',
'note',
'attachment',
'numbers',
'prefix',
'postfix'
'postfix',
...this.mindMap.nodeInnerPrefixList.map(item => {
return item.name
})
]
const createTypes = {}
if (Array.isArray(recreateTypes)) {
@@ -264,9 +263,11 @@ class MindMapNode {
if (createTypes.note) this._noteData = this.createNoteNode()
if (createTypes.attachment)
this._attachmentData = this.createAttachmentNode()
if (this.mindMap.numbers && createTypes.numbers) {
this._numberData = this.mindMap.numbers.createNumberContent(this)
}
this.mindMap.nodeInnerPrefixList.forEach(item => {
if (createTypes[item.name]) {
this[`_${item.name}Data`] = item.createContent(this)
}
})
if (createTypes.prefix) {
this._prefixData = createNodePrefixContent
? createNodePrefixContent(this)
@@ -286,15 +287,19 @@ class MindMapNode {
}
// 计算节点的宽高
getSize(recreateTypes) {
getSize(recreateTypes, opt = {}) {
const ignoreUpdateCustomTextWidth = opt.ignoreUpdateCustomTextWidth || false
if (!ignoreUpdateCustomTextWidth) {
this.customTextWidth = this.getData('customTextWidth') || undefined
}
this.customLeft = this.getData('customLeft') || undefined
this.customTop = this.getData('customTop') || undefined
// 这里不要更新概要,不然即使概要没修改,每次也会重新渲染
// this.updateGeneralization()
this.createNodeData(recreateTypes)
let { width, height } = this.getNodeRect()
const { width, height } = this.getNodeRect()
// 判断节点尺寸是否有变化
let changed = this.width !== width || this.height !== height
const changed = this.width !== width || this.height !== height
this.width = width
this.height = height
return changed
@@ -304,7 +309,7 @@ class MindMapNode {
getNodeRect() {
// 自定义节点内容
if (this.isUseCustomNodeContent()) {
let rect = this.measureCustomNodeContentSize(this._customNodeContent)
const rect = this.measureCustomNodeContentSize(this._customNodeContent)
return {
width: this.hasCustomWidth() ? this.customTextWidth : rect.width,
height: rect.height
@@ -324,11 +329,14 @@ class MindMapNode {
this._rectInfo.imgContentWidth = imgContentWidth = this._imgData.width
this._rectInfo.imgContentHeight = imgContentHeight = this._imgData.height
}
// 编号内容
if (this._numberData) {
textContentWidth += this._numberData.width
textContentHeight = Math.max(textContentHeight, this._numberData.height)
}
// 库前置内容
this.mindMap.nodeInnerPrefixList.forEach(item => {
const itemData = this[`_${item.name}Data`]
if (itemData) {
textContentWidth += itemData.width
textContentHeight = Math.max(textContentHeight, itemData.height)
}
})
// 自定义前置内容
if (this._prefixData) {
textContentWidth += this._prefixData.width
@@ -397,7 +405,7 @@ class MindMapNode {
imgContentHeight > 0 && textContentHeight > 0
? this.blockContentMargin
: 0
let { paddingX, paddingY } = this.getPaddingVale()
const { paddingX, paddingY } = this.getPaddingVale()
// 纯内容宽高
let _width = Math.max(imgContentWidth, textContentWidth)
let _height = imgContentHeight + textContentHeight
@@ -411,7 +419,7 @@ class MindMapNode {
_height += tagContentHeight
}
// 计算节点形状需要的附加内边距
let { paddingX: shapePaddingX, paddingY: shapePaddingY } =
const { paddingX: shapePaddingX, paddingY: shapePaddingY } =
this.shapeInstance.getShapePadding(_width, _height, paddingX, paddingY)
this.shapePadding.paddingX = shapePaddingX
this.shapePadding.paddingY = shapePaddingY
@@ -428,7 +436,8 @@ class MindMapNode {
if (!this.group) return
// 清除之前的内容
this.group.clear()
const { hoverRectPadding, tagPosition } = this.mindMap.opt
const { hoverRectPadding, tagPosition, openRealtimeRenderOnNodeTextEdit } =
this.mindMap.opt
let { width, height, textContentItemMargin } = this
let { paddingY } = this.getPaddingVale()
const halfBorderWidth = this.getBorderWidth() / 2
@@ -480,14 +489,17 @@ class MindMapNode {
// 内容节点
let textContentNested = new G()
let textContentOffsetX = 0
// 编号内容
if (this._numberData) {
this._numberData.node
.x(textContentOffsetX)
.y((textContentHeight - this._numberData.height) / 2)
textContentNested.add(this._numberData.node)
textContentOffsetX += this._numberData.width + textContentItemMargin
}
// 库前置内容
this.mindMap.nodeInnerPrefixList.forEach(item => {
const itemData = this[`_${item.name}Data`]
if (itemData) {
itemData.node
.x(textContentOffsetX)
.y((textContentHeight - itemData.height) / 2)
textContentNested.add(itemData.node)
textContentOffsetX += itemData.width + textContentItemMargin
}
})
// 自定义前置内容
if (this._prefixData) {
const foreignObject = createForeignObjectNode({
@@ -524,6 +536,12 @@ class MindMapNode {
.x(-oldX) // 修复非富文本模式下同时存在图标和换行的文本时,被收起和展开时图标与文字距离会逐渐拉大的问题
.x(textContentOffsetX)
.y((textContentHeight - this._textData.height) / 2)
// 如果开启了文本编辑实时渲染需要判断当前渲染的节点是否是正在编辑的节点是的话将透明度设置为0不显示
if (openRealtimeRenderOnNodeTextEdit) {
this._textData.node.opacity(
this.mindMap.renderer.textEdit.getCurrentEditNode() === this ? 0 : 1
)
}
textContentNested.add(this._textData.node)
textContentOffsetX += this._textData.width + textContentItemMargin
}
@@ -656,7 +674,7 @@ class MindMapNode {
// 多选和取消多选
if (!readonly && (e.ctrlKey || e.metaKey) && enableCtrlKeyNodeSelection) {
this.isMultipleChoice = true
let isActive = this.getData('isActive')
const isActive = this.getData('isActive')
if (!isActive)
this.mindMap.emit(
'before_node_active',
@@ -775,7 +793,7 @@ class MindMapNode {
this.renderExpandBtn()
}
} else {
let { isActive, expand } = this.getData()
const { isActive, expand } = this.getData()
// 展开状态且非激活状态,且当前鼠标不在它上面,才隐藏
if (childrenLength <= 0) {
this.removeExpandBtn()
@@ -793,7 +811,7 @@ class MindMapNode {
// 更新协同头像
if (this.updateUserListNode) this.updateUserListNode()
// 更新节点位置
let t = this.group.transform()
const t = this.group.transform()
// 保存一份当前节点数据快照
this.nodeDataSnapshot = JSON.stringify(this.getData())
// 节点位置变化才更新,因为即使值没有变化属性设置操作也是耗时的
@@ -804,10 +822,10 @@ class MindMapNode {
// 获取节点相当于画布的位置
getNodePosInClient(_left, _top) {
let drawTransform = this.mindMap.draw.transform()
let { scaleX, scaleY, translateX, translateY } = drawTransform
let left = _left * scaleX + translateX
let top = _top * scaleY + translateY
const drawTransform = this.mindMap.draw.transform()
const { scaleX, scaleY, translateX, translateY } = drawTransform
const left = _left * scaleX + translateX
const top = _top * scaleY + translateY
return {
left,
top
@@ -826,8 +844,8 @@ class MindMapNode {
}
// 重新渲染节点,即重新创建节点内容、计算节点大小、计算节点内容布局、更新展开收起按钮,概要及位置
reRender(recreateTypes) {
let sizeChange = this.getSize(recreateTypes)
reRender(recreateTypes, opt) {
const sizeChange = this.getSize(recreateTypes, opt)
this.layout()
this.update()
return sizeChange
@@ -977,7 +995,7 @@ class MindMapNode {
if (this.group) this.group.hide()
this.hideGeneralization()
if (this.parent) {
let index = this.parent.children.indexOf(this)
const index = this.parent.children.indexOf(this)
this.parent._lines[index] && this.parent._lines[index].hide()
this._lines.forEach(item => {
item.hide()
@@ -999,7 +1017,7 @@ class MindMapNode {
this.group.show()
this.showGeneralization()
if (this.parent) {
let index = this.parent.children.indexOf(this)
const index = this.parent.children.indexOf(this)
this.parent._lines[index] && this.parent._lines[index].show()
this._lines.forEach(item => {
item.show()
@@ -1245,7 +1263,7 @@ class MindMapNode {
// 获取某个样式
getStyle(prop, root) {
let v = this.style.merge(prop, root)
const v = this.style.merge(prop, root)
return v === undefined ? '' : v
}
@@ -1310,11 +1328,11 @@ class MindMapNode {
// 获取节点的尺寸和位置信息,宽高是应用了缩放效果后的实际宽高,位置信息相对于画布
getRectInSvg() {
let { scaleX, scaleY, translateX, translateY } =
const { scaleX, scaleY, translateX, translateY } =
this.mindMap.draw.transform()
let { left, top, width, height } = this
let right = (left + width) * scaleX + translateX
let bottom = (top + height) * scaleY + translateY
const right = (left + width) * scaleX + translateX
const bottom = (top + height) * scaleY + translateY
left = left * scaleX + translateX
top = top * scaleY + translateY
return {
@@ -1355,6 +1373,15 @@ class MindMapNode {
return new Text().text(text)
}
// 获取SVG.js库的一些对象
getSvgObjects() {
return {
SVG,
G,
Rect
}
}
// 检查是否支持拖拽调整宽度
// 1.富文本模式
// 2.自定义节点内容

View File

@@ -12,6 +12,7 @@ const backgroundStyleProps = [
class Style {
// 设置背景样式
static setBackgroundStyle(el, themeConfig) {
if (!el) return
// 缓存容器元素原本的样式
if (!Style.cacheStyle) {
Style.cacheStyle = {}
@@ -183,7 +184,7 @@ class Style {
})
.css({
'font-family': styles.fontFamily,
'font-size': styles.fontSize,
'font-size': styles.fontSize + 'px',
'font-weight': styles.fontWeight,
'font-style': styles.fontStyle,
'text-decoration': styles.textDecoration
@@ -229,20 +230,20 @@ class Style {
}
// html文字节点
domText(node, fontSizeScale = 1, isMultiLine) {
domText(node, fontSizeScale = 1) {
const styles = {
color: this.merge('color'),
fontFamily: this.merge('fontFamily'),
fontSize: this.merge('fontSize'),
fontWeight: this.merge('fontWeight'),
fontStyle: this.merge('fontStyle'),
textDecoration: this.merge('textDecoration'),
lineHeight: this.merge('lineHeight')
textDecoration: this.merge('textDecoration')
}
node.style.color = styles.color
node.style.textDecoration = styles.textDecoration
node.style.fontFamily = styles.fontFamily
node.style.fontSize = styles.fontSize * fontSizeScale + 'px'
node.style.fontWeight = styles.fontWeight || 'normal'
node.style.lineHeight = !isMultiLine ? 'normal' : styles.lineHeight
node.style.fontStyle = styles.fontStyle
}
@@ -338,7 +339,7 @@ class Style {
node2.fill({ color: color })
fillNode.fill({ color: fill })
if (this.ctx.mindMap.opt.isShowExpandNum) {
node.attr({ 'font-size': fontSize, 'font-color': fontColor })
node.attr({ 'font-size': fontSize + 'px', 'font-color': fontColor })
}
}

View File

@@ -28,7 +28,7 @@ function createTextAvatar(item) {
color: '#fff'
})
.css({
'font-size': fontSize
'font-size': fontSize + 'px'
})
.dx(-fontSize / 2)
.dy((avatarSize - fontSize) / 2)

View File

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

View File

@@ -71,7 +71,9 @@ function onDragMousemoveHandle(e) {
this.left = this.dragHandleMousedownLeft + ox / scaleX
}
// 自定义内容不重新渲染,交给开发者
this.reRender(useCustomContent ? [] : ['text'])
this.reRender(useCustomContent ? [] : ['text'], {
ignoreUpdateCustomTextWidth: true
})
}
// 鼠标松开事件

View File

@@ -354,6 +354,10 @@ class View {
// 判断是否需要将思维导图限制在画布内
checkNeedMindMapInCanvas() {
// 如果当前在演示模式,那么不需要限制
if (this.mindMap.demonstrate && this.mindMap.demonstrate.isInDemonstrate) {
return false
}
const { isLimitMindMapInCanvasWhenHasScrollbar, isLimitMindMapInCanvas } =
this.mindMap.opt
// 如果注册了滚动条插件那么使用isLimitMindMapInCanvasWhenHasScrollbar配置

View File

@@ -69,28 +69,6 @@ class Base {
}
}
// 获取节点编号信息
getNumberInfo({ parent, ancestors, layerIndex, index }) {
// 编号
const hasNumberPlugin = !!this.mindMap.numbers
const parentNumberStr =
hasNumberPlugin && parent && parent._node.number
? parent._node.number
: ''
const newNumberStr = hasNumberPlugin
? this.mindMap.numbers.getNodeNumberStr({
ancestors,
layerIndex,
num: index + 1,
parentNumberStr
})
: ''
return {
hasNumberPlugin,
newNumberStr
}
}
// 节点节点数据是否发生了改变
checkIsNodeDataChange(lastData, curData) {
if (lastData) {
@@ -105,14 +83,21 @@ class Base {
// 创建节点实例
createNode(data, parent, isRoot, layerIndex, index, ancestors) {
// 编号
const { hasNumberPlugin, newNumberStr } = this.getNumberInfo({
parent,
ancestors,
layerIndex,
index
})
// 创建节点
// 库前置内容数据
const nodeInnerPrefixData = {}
this.mindMap.nodeInnerPrefixList.forEach(item => {
if (item.createNodeData) {
const [key, value] = item.createNodeData({
data,
parent,
ancestors,
layerIndex,
index
})
nodeInnerPrefixData[key] = value
}
})
const uid = data.data.uid
let newNode = null
// 数据上保存了节点引用,那么直接复用节点
@@ -132,14 +117,16 @@ class Base {
}
this.cacheNode(data._node.uid, newNode)
this.checkIsLayoutChangeRerenderExpandBtnPlaceholderRect(newNode)
// 判断编号是否改变
let isNumberChange = false
if (hasNumberPlugin) {
isNumberChange = this.mindMap.numbers.updateNumber(
newNode,
newNumberStr
)
}
// 库前置内容是否改变
let isNodeInnerPrefixChange = false
this.mindMap.nodeInnerPrefixList.forEach(item => {
if (item.updateNodeData) {
const isChange = item.updateNodeData(newNode, nodeInnerPrefixData)
if (isChange) {
isNodeInnerPrefixChange = isChange
}
}
})
// 主题或主题配置改变了
const isResizeSource = this.checkIsNeedResizeSources()
// 节点数据改变了
@@ -153,7 +140,7 @@ class Base {
isNodeDataChange ||
isLayerTypeChange ||
newNode.getData('resetRichText') ||
isNumberChange
isNodeInnerPrefixChange
) {
newNode.getSize()
newNode.needLayout = true
@@ -190,21 +177,23 @@ class Base {
const isResizeSource = this.checkIsNeedResizeSources()
// 点数据改变了
const isNodeDataChange = this.checkIsNodeDataChange(lastData, data.data)
// 判断编号是否改变
let isNumberChange = false
if (hasNumberPlugin) {
isNumberChange = this.mindMap.numbers.updateNumber(
newNode,
newNumberStr
)
}
// 库前置内容是否改变
let isNodeInnerPrefixChange = false
this.mindMap.nodeInnerPrefixList.forEach(item => {
if (item.updateNodeData) {
const isChange = item.updateNodeData(newNode, nodeInnerPrefixData)
if (isChange) {
isNodeInnerPrefixChange = isChange
}
}
})
// 重新计算节点大小和布局
if (
isResizeSource ||
isNodeDataChange ||
isLayerTypeChange ||
newNode.getData('resetRichText') ||
isNumberChange
isNodeInnerPrefixChange
) {
newNode.getSize()
newNode.needLayout = true
@@ -222,7 +211,7 @@ class Base {
layerIndex,
isRoot,
parent: !isRoot ? parent._node : null,
number: newNumberStr
...nodeInnerPrefixData
})
// uid保存到数据上为了节点复用
data.data.uid = newUid

View File

@@ -289,11 +289,14 @@ class NodeImgAdjust {
// 隐藏自定义元素
this.hideHandleEl()
// 更新节点图片为新的大小
const { image, imageTitle, imageSize } = this.node.getData()
const { image, imageTitle } = this.node.getData()
const { scaleX, scaleY } = this.mousedownDrawTransform
const newWidth = this.currentImgWidth / scaleX
const newHeight = this.currentImgHeight / scaleY
if (newWidth !== imageSize.width || newHeight !== imageSize.height) {
if (
Math.abs(newWidth - this.rect.width) > 1 ||
Math.abs(newHeight - this.rect.height) > 1
) {
this.mindMap.execCommand('SET_NODE_IMAGE', this.node, {
url: image,
title: imageTitle,

View File

@@ -4,8 +4,6 @@ import 'quill/dist/quill.snow.css'
import {
walk,
getTextFromHtml,
isWhite,
getVisibleColorFromTheme,
isUndef,
checkSmmFormatData,
removeHtmlNodeByClass,
@@ -189,7 +187,8 @@ class RichText {
nodeTextEditZIndex,
textAutoWrapWidth,
selectTextOnEnterEditText,
transformRichTextOnEnterEdit
transformRichTextOnEnterEdit,
openRealtimeRenderOnNodeTextEdit
} = this.mindMap.opt
textAutoWrapWidth = node.hasCustomWidth()
? node.customTextWidth
@@ -222,10 +221,13 @@ class RichText {
this.textEditNode.style.cssText = `
position:fixed;
box-sizing: border-box;
box-shadow: 0 0 20px rgba(0,0,0,.5);
${
openRealtimeRenderOnNodeTextEdit
? ''
: 'box-shadow: 0 0 20px rgba(0,0,0,.5);'
}
outline: none;
word-break:
break-all;
word-break: break-all;
padding: ${paddingY}px ${paddingX}px;
`
this.textEditNode.addEventListener('click', e => {
@@ -245,7 +247,10 @@ class RichText {
this.textEditNode.style.marginLeft = `-${paddingX * scaleX}px`
this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
this.textEditNode.style.zIndex = nodeTextEditZIndex
this.textEditNode.style.background = this.getBackground(node)
if (!openRealtimeRenderOnNodeTextEdit) {
this.textEditNode.style.background =
this.mindMap.renderer.textEdit.getBackground(node)
}
this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
this.textEditNode.style.minHeight = originHeight + 'px'
this.textEditNode.style.left = rect.left + 'px'
@@ -298,11 +303,26 @@ class RichText {
this.cacheEditingText = ''
}
// 当openRealtimeRenderOnNodeTextEdit配置更新后需要更新编辑框样式
onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
openRealtimeRenderOnNodeTextEdit
) {
if (!this.textEditNode) return
this.textEditNode.style.background = openRealtimeRenderOnNodeTextEdit
? 'transparent'
: this.node
? this.mindMap.renderer.textEdit.getBackground(this.node)
: ''
this.textEditNode.style.boxShadow = openRealtimeRenderOnNodeTextEdit
? 'none'
: '0 0 20px rgba(0,0,0,.5)'
}
// 更新文本编辑框的大小和位置
updateTextEditNode() {
if (!this.node) return
const rect = this.node._textData.node.node.getBoundingClientRect()
const g = this.node._textData.node
const rect = g.node.getBoundingClientRect()
const originWidth = g.attr('data-width')
const originHeight = g.attr('data-height')
this.textEditNode.style.minWidth =
@@ -319,27 +339,6 @@ class RichText {
targetNode.removeChild(this.textEditNode)
}
// 获取编辑区域的背景填充
getBackground(node) {
const gradientStyle = node.style.merge('gradientStyle')
// 当前使用的是渐变色背景
if (gradientStyle) {
const startColor = node.style.merge('startColor')
const endColor = node.style.merge('endColor')
return `linear-gradient(to right, ${startColor}, ${endColor})`
} else {
// 单色背景
const bgColor = node.style.merge('fillColor')
const color = node.style.merge('color')
// 默认使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见
return bgColor === 'transparent'
? isWhite(color)
? getVisibleColorFromTheme(this.mindMap.themeConfig)
: '#fff'
: bgColor
}
}
// 如果是非富文本的情况,需要手动应用文本样式
setTextStyleIfNotRichText(node) {
let style = {
@@ -389,6 +388,12 @@ class RichText {
let html = this.getEditText()
html = this.sortHtmlNodeStyles(html)
const list = nodes && nodes.length > 0 ? nodes : [this.node]
const node = this.node
this.textEditNode.style.display = 'none'
this.showTextEdit = false
this.mindMap.emit('rich_text_selection_change', false)
this.node = null
this.isInserting = false
list.forEach(node => {
this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
// if (node.isGeneralization) {
@@ -397,12 +402,6 @@ class RichText {
// }
this.mindMap.render()
})
const node = this.node
this.textEditNode.style.display = 'none'
this.showTextEdit = false
this.mindMap.emit('rich_text_selection_change', false)
this.node = null
this.isInserting = false
this.mindMap.emit('hide_text_edit', this.textEditNode, list, node)
}

View File

@@ -166,7 +166,7 @@ function styleText(node) {
})
.css({
'font-family': associativeLineTextFontFamily,
'font-size': associativeLineTextFontSize
'font-size': associativeLineTextFontSize + 'px'
})
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -439,6 +439,11 @@ export const sidebarTriggerList = [
value: 'outline',
icon: 'iconfuhao-dagangshu'
},
{
name: 'Setting',
value: 'setting',
icon: 'iconshezhi'
},
{
name: 'ShortcutKey',
value: 'shortcutKey',

View File

@@ -1,6 +1,5 @@
import {
fontSizeList,
lineHeightList,
colorList,
borderWidthList,
borderRadiusList,
@@ -155,7 +154,6 @@ const linearGradientDirList = {
export {
fontSizeList,
lineHeightList,
borderWidthList,
borderRadiusList,
lineWidthList,

View File

@@ -57,9 +57,6 @@ export const fontFamilyList = [
// 字号
export const fontSizeList = [10, 12, 16, 18, 24, 32, 48]
// 行高
export const lineHeightList = [1, 1.5, 2, 2.5, 3]
// 颜色
export const colorList = [
'#4D4D4D',
@@ -537,6 +534,11 @@ export const sidebarTriggerList = [
value: 'outline',
icon: 'iconfuhao-dagangshu'
},
{
name: '设置',
value: 'setting',
icon: 'iconshezhi'
},
{
name: '快捷键',
value: 'shortcutKey',

View File

@@ -439,6 +439,11 @@ export const sidebarTriggerList = [
value: 'outline',
icon: 'iconfuhao-dagangshu'
},
{
name: '設置',
value: 'setting',
icon: 'iconshezhi'
},
{
name: '快捷鍵',
value: 'shortcutKey',

View File

@@ -26,8 +26,41 @@ export default {
nodeBorderType: 'Node border style',
nodeUseLineStyle: 'Use only has bottom border style',
otherConfig: 'Other config',
enableFreeDrag: 'Enable node free drag(Beta)',
associativeLine: 'Associative line',
associativeLineWidth: 'Width',
associativeLineColor: 'Color',
associativeLineActiveWidth: 'Active width',
associativeLineActiveColor: 'Active color',
rootStyle: 'Root Node',
associativeLineText: 'Associative line text',
fontFamily: 'Font family',
fontSize: 'Font size',
rootLineStartPos: 'Root line start pos',
center: 'Center',
edge: 'Edge',
rainbowLines: 'Rainbow lines',
notUseRainbowLines: 'Not use rainbow lines',
outerFramePadding: 'Outer frame padding'
},
setting: {
title: 'Setting',
openPerformance: 'Enable performance mode',
enableFreeDrag: 'Enable node free drag(Beta)',
isEnableNodeRichText: 'Enable node rich text editing',
mousewheelAction: 'Mouse wheel behavior',
zoomView: 'Zoom view',
moveViewUpDown: 'Move view up and down',
mousewheelZoomActionReverse: 'Mouse Wheel Zoom',
mousewheelZoomActionReverse1: 'Zoom out forward and zoom in back',
mousewheelZoomActionReverse2: 'Zoom in forward and zoom out back',
createNewNodeBehavior: 'Behavior of creating new node',
default: 'Active new node and editing',
notActive: 'Not active new node',
activeOnly: 'Only active new node but not editing',
openRealtimeRenderOnNodeTextEdit:
'Enable real-time rendering effect for text editing',
isShowScrollbar: 'Is show scrollbar',
isUseHandDrawnLikeStyle: 'Is use hand drawn like style',
watermark: 'Watermark',
showWatermark: 'Is show watermark',
onlyExport: 'Only export',
@@ -40,34 +73,11 @@ export default {
watermarkTextOpacity: 'Text opacity',
watermarkTextFontSize: 'Font size',
belowNode: 'Display below nodes',
isEnableNodeRichText: 'Enable node rich text editing',
mousewheelAction: 'Mouse wheel behavior',
zoomView: 'Zoom view',
moveViewUpDown: 'Move view up and down',
associativeLine: 'Associative line',
associativeLineWidth: 'Width',
associativeLineColor: 'Color',
associativeLineActiveWidth: 'Active width',
associativeLineActiveColor: 'Active color',
mousewheelZoomActionReverse: 'Mouse Wheel Zoom',
mousewheelZoomActionReverse1: 'Zoom out forward and zoom in back',
mousewheelZoomActionReverse2: 'Zoom in forward and zoom out back',
createNewNodeBehavior: 'Behavior of creating new node',
default: 'Active new node and editing',
notActive: 'Not active new node',
activeOnly: 'Only active new node but not editing',
rootStyle: 'Root Node',
associativeLineText: 'Associative line text',
fontFamily: 'Font family',
fontSize: 'Font size',
isShowScrollbar: 'Is show scrollbar',
isUseHandDrawnLikeStyle: 'Is use hand drawn like style',
rootLineStartPos: 'Root line start pos',
center: 'Center',
edge: 'Edge',
rainbowLines: 'Rainbow lines',
notUseRainbowLines: 'Not use rainbow lines',
outerFramePadding: 'Outer frame padding'
tagPosition: 'Node tag position',
tagPositionRight: 'Text right',
tagPositionBottom: 'Text bottom',
alwaysShowExpandBtn: 'Always show expand btn',
enableAutoEnterTextEditWhenKeydown: 'Auto enter text edit when keydown'
},
color: {
moreColor: 'More color'
@@ -112,7 +122,9 @@ export default {
copySuccess: 'Copy success',
copyFail: 'Copy fail',
number: 'Number child nodes',
expandNodeChild: 'Expand all sub nodes'
expandNodeChild: 'Expand all sub nodes',
addToDo: 'Add toDo',
removeToDo: 'Remove toDo'
},
count: {
words: 'Words',
@@ -216,7 +228,6 @@ export default {
text: 'Text',
fontFamily: 'Font family',
fontSize: 'Font size',
lineHeight: 'Line height',
color: 'color',
addFontWeight: 'add font weight',
italic: 'Italic',

View File

@@ -25,9 +25,40 @@ export default {
belowLevel2Node: '三级及以下节点',
nodeBorderType: '节点边框风格',
nodeUseLineStyle: '是否使用只有底边框的风格',
otherConfig: '其他配置',
enableFreeDrag: '是否开启节点自由拖拽',
associativeLine: '关联线',
associativeLineWidth: '粗细',
associativeLineColor: '颜色',
associativeLineActiveWidth: '激活粗细',
associativeLineActiveColor: '激活颜色',
rootStyle: '根节点',
associativeLineText: '关联线文字',
fontFamily: '字体',
fontSize: '字号',
rootLineStartPos: '根节点连线起始位置',
center: '中心',
edge: '边缘',
rainbowLines: '彩虹线条',
notUseRainbowLines: '不使用彩虹线条',
outerFramePadding: '外框内边距'
},
setting: {
title: '设置',
openPerformance: '开启性能模式(Beta)',
enableFreeDrag: '是否开启节点自由拖拽',
isEnableNodeRichText: '是否开启节点富文本编辑',
mousewheelAction: '鼠标滚轮行为',
zoomView: '缩放视图',
moveViewUpDown: '上下移动视图',
mousewheelZoomActionReverse: '鼠标滚轮缩放',
mousewheelZoomActionReverse1: '向前缩小向后放大',
mousewheelZoomActionReverse2: '向前放大向后缩小',
createNewNodeBehavior: '创建新节点的行为',
default: '激活新节点及进入编辑',
notActive: '不激活新节点',
activeOnly: '只激活新节点,不进入编辑',
openRealtimeRenderOnNodeTextEdit: '开启文本编辑实时渲染效果',
isShowScrollbar: '是否显示滚动条',
isUseHandDrawnLikeStyle: '是否开启手绘风格',
watermark: '水印',
showWatermark: '是否显示水印',
watermarkDefaultText: '水印文字',
@@ -40,34 +71,11 @@ export default {
watermarkTextOpacity: '文字透明度',
watermarkTextFontSize: '文字字号',
belowNode: '显示在节点下方',
isEnableNodeRichText: '是否开启节点富文本编辑',
mousewheelAction: '鼠标滚轮行为',
zoomView: '缩放视图',
moveViewUpDown: '上下移动视图',
associativeLine: '关联线',
associativeLineWidth: '粗细',
associativeLineColor: '颜色',
associativeLineActiveWidth: '激活粗细',
associativeLineActiveColor: '激活颜色',
mousewheelZoomActionReverse: '鼠标滚轮缩放',
mousewheelZoomActionReverse1: '向前缩小向后放大',
mousewheelZoomActionReverse2: '向前放大向后缩小',
createNewNodeBehavior: '创建新节点的行为',
default: '激活新节点及进入编辑',
notActive: '不激活新节点',
activeOnly: '只激活新节点,不进入编辑',
rootStyle: '根节点',
associativeLineText: '关联线文字',
fontFamily: '字体',
fontSize: '字号',
isShowScrollbar: '是否显示滚动条',
isUseHandDrawnLikeStyle: '是否开启手绘风格',
rootLineStartPos: '根节点连线起始位置',
center: '中心',
edge: '边缘',
rainbowLines: '彩虹线条',
notUseRainbowLines: '不使用彩虹线条',
outerFramePadding: '外框内边距'
tagPosition: '节点标签显示的位置',
tagPositionRight: '文本右侧',
tagPositionBottom: '文本下面',
alwaysShowExpandBtn: '是否一直显示展开收起按钮',
enableAutoEnterTextEditWhenKeydown: '键盘输入时自动进入文本编辑'
},
color: {
moreColor: '更多颜色'
@@ -112,7 +120,9 @@ export default {
copySuccess: '复制成功',
copyFail: '复制失败',
number: '编号其子节点',
expandNodeChild: '展开所有下级节点'
expandNodeChild: '展开所有下级节点',
addToDo: '添加待办',
removeToDo: '删除待办'
},
count: {
words: '字数',
@@ -214,7 +224,6 @@ export default {
text: '文字',
fontFamily: '字体',
fontSize: '字号',
lineHeight: '行高',
color: '颜色',
addFontWeight: '加粗',
italic: '斜体',

View File

@@ -26,8 +26,45 @@ export default {
nodeBorderType: '節點邊框樣式',
nodeUseLineStyle: '僅使用底邊框樣式',
otherConfig: '其他設定',
enableFreeDrag: '啟用節點自由拖曳 (Beta)',
associativeLine: '關聯線',
associativeLineWidth: '寬度',
associativeLineColor: '顏色',
associativeLineActiveWidth: '啟用時寬度',
associativeLineActiveColor: '啟用時顏色',
rootStyle: '根節點',
associativeLineText: '關聯線文字',
fontFamily: '字型',
fontSize: '字型大小',
rootLineStartPos: '根節點連線起始位置',
center: '中心',
edge: '邊緣',
rainbowLines: '彩虹線條',
notUseRainbowLines: '不使用彩虹線條',
outerFramePadding: '外框內距',
tagPosition: '節點標簽顯示的位置',
tagPositionRight: '文本右側',
tagPositionBottom: '文本下面',
alwaysShowExpandBtn: '是否壹直顯示展開收起按鈕',
enableAutoEnterTextEditWhenKeydown: '鍵盤輸入時自動進入文本編輯'
},
setting: {
title: '設置',
openPerformance: '啟用效能模式',
enableFreeDrag: '啟用節點自由拖曳 (Beta)',
isEnableNodeRichText: '啟用節點豐富文字編輯',
mousewheelAction: '滑鼠滾輪行為',
zoomView: '縮放檢視',
moveViewUpDown: '上下移動檢視',
mousewheelZoomActionReverse: '滑鼠滾輪縮放',
mousewheelZoomActionReverse1: '向前縮小,向後放大',
mousewheelZoomActionReverse2: '向前放大,向後縮小',
createNewNodeBehavior: '建立新節點行為',
default: '啟用新節點並進入編輯',
notActive: '不啟用新節點',
activeOnly: '僅啟用新節點,不進入編輯',
openRealtimeRenderOnNodeTextEdit: '開啟文本編輯實時渲染效果',
isShowScrollbar: '顯示捲軸',
isUseHandDrawnLikeStyle: '使用手繪風格',
watermark: '浮水印',
showWatermark: '顯示浮水印',
onlyExport: '僅在匯出時顯示',
@@ -39,35 +76,7 @@ export default {
watermarkAngle: '旋轉角度',
watermarkTextOpacity: '文字透明度',
watermarkTextFontSize: '字型大小',
belowNode: '顯示在節點下方',
isEnableNodeRichText: '啟用節點豐富文字編輯',
mousewheelAction: '滑鼠滾輪行為',
zoomView: '縮放檢視',
moveViewUpDown: '上下移動檢視',
associativeLine: '關聯線',
associativeLineWidth: '寬度',
associativeLineColor: '顏色',
associativeLineActiveWidth: '啟用時寬度',
associativeLineActiveColor: '啟用時顏色',
mousewheelZoomActionReverse: '滑鼠滾輪縮放',
mousewheelZoomActionReverse1: '向前縮小,向後放大',
mousewheelZoomActionReverse2: '向前放大,向後縮小',
createNewNodeBehavior: '建立新節點行為',
default: '啟用新節點並進入編輯',
notActive: '不啟用新節點',
activeOnly: '僅啟用新節點,不進入編輯',
rootStyle: '根節點',
associativeLineText: '關聯線文字',
fontFamily: '字型',
fontSize: '字型大小',
isShowScrollbar: '顯示捲軸',
isUseHandDrawnLikeStyle: '使用手繪風格',
rootLineStartPos: '根節點連線起始位置',
center: '中心',
edge: '邊緣',
rainbowLines: '彩虹線條',
notUseRainbowLines: '不使用彩虹線條',
outerFramePadding: '外框內距'
belowNode: '顯示在節點下方'
},
color: {
moreColor: '更多顏色'
@@ -112,7 +121,9 @@ export default {
copySuccess: '複製成功',
copyFail: '複製失敗',
number: '將其子節點編號',
expandNodeChild: '展開所有下級節點'
expandNodeChild: '展開所有下級節點',
addToDo: '添加待辦',
removeToDo: '刪除待辦'
},
count: {
words: '字數',
@@ -214,7 +225,6 @@ export default {
text: '文字',
fontFamily: '字型',
fontSize: '字型大小',
lineHeight: '行高',
color: '顏色',
addFontWeight: '粗體',
italic: '斜體',

View File

@@ -714,146 +714,6 @@
></el-slider>
</div>
</div>
<!-- 水印 -->
<div class="title noTop">{{ $t('baseStyle.watermark') }}</div>
<div class="row">
<!-- 是否显示水印 -->
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.show"
@change="watermarkShowChange"
>{{ $t('baseStyle.showWatermark') }}</el-checkbox
>
</div>
</div>
<template v-if="watermarkConfig.show">
<!-- 是否仅在导出时显示 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.onlyExport"
@change="updateWatermarkConfig"
>{{ $t('baseStyle.onlyExport') }}</el-checkbox
>
</div>
</div>
<!-- 是否在节点下方 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.belowNode"
@change="updateWatermarkConfig"
>{{ $t('baseStyle.belowNode') }}</el-checkbox
>
</div>
</div>
<!-- 水印文字 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkText') }}</span>
<el-input
v-model="watermarkConfig.text"
size="small"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input>
</div>
</div>
<!-- 水印文字颜色 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkTextColor') }}</span>
<span
class="block"
v-popover:popover3
:style="{ backgroundColor: watermarkConfig.textStyle.color }"
></span>
<el-popover ref="popover3" placement="bottom" trigger="click">
<Color
:color="watermarkConfig.textStyle.color"
@change="
value => {
watermarkConfig.textStyle.color = value
updateWatermarkConfig()
}
"
></Color>
</el-popover>
</div>
</div>
<!-- 水印文字透明度 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkTextOpacity') }}</span>
<el-slider
v-model="watermarkConfig.textStyle.opacity"
style="width: 170px"
:min="0"
:max="1"
:step="0.1"
@change="updateWatermarkConfig"
></el-slider>
</div>
</div>
<!-- 水印文字字号 -->
<div class="row">
<div class="rowItem">
<span class="name">{{
$t('baseStyle.watermarkTextFontSize')
}}</span>
<el-input-number
v-model="watermarkConfig.textStyle.fontSize"
size="small"
:min="0"
:max="50"
:step="1"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 旋转角度 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkAngle') }}</span>
<el-input-number
v-model="watermarkConfig.angle"
size="small"
:min="0"
:max="90"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 水印行间距 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkLineSpacing') }}</span>
<el-input-number
v-model="watermarkConfig.lineSpacing"
size="small"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 水印文字间距 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.watermarkTextSpacing') }}</span>
<el-input-number
v-model="watermarkConfig.textSpacing"
size="small"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
</template>
<!-- 外框内边距 -->
<div class="title noTop">{{ $t('baseStyle.outerFramePadding') }}</div>
<div class="row">
@@ -884,150 +744,6 @@
></el-slider>
</div>
</div>
<!-- 其他配置 -->
<div class="title noTop">{{ $t('baseStyle.otherConfig') }}</div>
<!-- 配置性能模式 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.openPerformance"
@change="
value => {
updateOtherConfig('openPerformance', value)
}
"
>{{ $t('baseStyle.openPerformance') }}</el-checkbox
>
</div>
</div>
<!-- 配置开启自由拖拽 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.enableFreeDrag"
@change="
value => {
updateOtherConfig('enableFreeDrag', value)
}
"
>{{ $t('baseStyle.enableFreeDrag') }}</el-checkbox
>
</div>
</div>
<!-- 配置是否启用富文本编辑 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="enableNodeRichText"
@change="enableNodeRichTextChange"
>{{ $t('baseStyle.isEnableNodeRichText') }}</el-checkbox
>
</div>
</div>
<!-- 配置鼠标滚轮行为 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.mousewheelAction') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.mousewheelAction"
placeholder=""
@change="
value => {
updateOtherConfig('mousewheelAction', value)
}
"
>
<el-option
:label="$t('baseStyle.zoomView')"
value="zoom"
></el-option>
<el-option
:label="$t('baseStyle.moveViewUpDown')"
value="move"
></el-option>
</el-select>
</div>
</div>
<!-- 配置鼠标缩放行为 -->
<div class="row" v-if="config.mousewheelAction === 'zoom'">
<div class="rowItem">
<span class="name">{{
$t('baseStyle.mousewheelZoomActionReverse')
}}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.mousewheelZoomActionReverse"
placeholder=""
@change="
value => {
updateOtherConfig('mousewheelZoomActionReverse', value)
}
"
>
<el-option
:label="$t('baseStyle.mousewheelZoomActionReverse1')"
:value="false"
></el-option>
<el-option
:label="$t('baseStyle.mousewheelZoomActionReverse2')"
:value="true"
></el-option>
</el-select>
</div>
</div>
<!-- 配置创建新节点时的行为 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('baseStyle.createNewNodeBehavior') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.createNewNodeBehavior"
placeholder=""
@change="
value => {
updateOtherConfig('createNewNodeBehavior', value)
}
"
>
<el-option
:label="$t('baseStyle.default')"
value="default"
></el-option>
<el-option
:label="$t('baseStyle.notActive')"
value="notActive"
></el-option>
<el-option
:label="$t('baseStyle.activeOnly')"
value="activeOnly"
></el-option>
</el-select>
</div>
</div>
<!-- 是否显示滚动条 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="localConfigs.isShowScrollbar"
@change="updateLocalConfig('isShowScrollbar', $event)"
>{{ $t('baseStyle.isShowScrollbar') }}</el-checkbox
>
</div>
</div>
<!-- 是否开启手绘风格 -->
<div class="row" v-if="supportHandDrawnLikeStyle">
<div class="rowItem">
<el-checkbox
v-model="localConfigs.isUseHandDrawnLikeStyle"
@change="updateLocalConfig('isUseHandDrawnLikeStyle', $event)"
>{{ $t('baseStyle.isUseHandDrawnLikeStyle') }}</el-checkbox
>
</div>
</div>
</div>
</Sidebar>
</template>
@@ -1118,34 +834,8 @@ export default {
marginY: 0,
nodeUseLineStyle: false
},
config: {
openPerformance: false,
enableFreeDrag: false,
mousewheelAction: 'zoom',
mousewheelZoomActionReverse: false,
createNewNodeBehavior: 'default'
},
watermarkConfig: {
show: false,
onlyExport: false,
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '',
opacity: 0,
fontSize: 1
}
},
rainbowLinesPopoverVisible: false,
curRainbowLineColorList: null,
updateWatermarkTimer: null,
enableNodeRichText: true,
localConfigs: {
isShowScrollbar: false,
isUseHandDrawnLikeStyle: false
},
currentLayout: '', // 当前结构
outerFramePadding: {
outerFramePaddingX: 0,
@@ -1157,8 +847,7 @@ export default {
...mapState({
activeSidebar: state => state.activeSidebar,
localConfig: state => state.localConfig,
isDark: state => state.localConfig.isDark,
supportHandDrawnLikeStyle: state => state.supportHandDrawnLikeStyle
isDark: state => state.localConfig.isDark
}),
lineStyleList() {
return lineStyleList[this.$i18n.locale] || lineStyleList.zh
@@ -1221,8 +910,6 @@ export default {
if (val === 'baseStyle') {
this.$refs.sidebar.show = true
this.initStyle()
this.initConfig()
this.initWatermark()
this.initRainbowLines()
this.initOuterFramePadding()
this.currentLayout = this.mindMap.getLayout()
@@ -1243,7 +930,6 @@ export default {
}
},
created() {
this.initLoacalConfig()
this.$bus.$on('setData', this.onSetData)
},
beforeDestroy() {
@@ -1259,11 +945,7 @@ export default {
}, 0)
},
/**
* @Author: 王林
* @Date: 2021-05-05 14:02:12
* @Desc: 初始样式
*/
// 初始样式
initStyle() {
;[
'backgroundColor',
@@ -1303,41 +985,6 @@ export default {
this.initMarginStyle()
},
// 初始化其他配置
initConfig() {
;[
'openPerformance',
'enableFreeDrag',
'mousewheelAction',
'mousewheelZoomActionReverse',
'createNewNodeBehavior'
].forEach(key => {
this.config[key] = this.mindMap.getConfig(key)
})
},
// 初始化本地配置
initLoacalConfig() {
this.enableNodeRichText = this.localConfig.openNodeRichText
this.mousewheelAction = this.localConfig.mousewheelAction
this.mousewheelZoomActionReverse = this.localConfig.mousewheelZoomActionReverse
;['isShowScrollbar', 'isUseHandDrawnLikeStyle'].forEach(key => {
this.localConfigs[key] = this.localConfig[key]
})
},
// 初始化水印配置
initWatermark() {
let config = this.mindMap.getConfig('watermarkConfig')
;['text', 'lineSpacing', 'textSpacing', 'angle', 'onlyExport'].forEach(
key => {
this.watermarkConfig[key] = config[key]
}
)
this.watermarkConfig.show = !!config.text
this.watermarkConfig.textStyle = { ...config.textStyle }
},
// 初始化彩虹线条配置
initRainbowLines() {
const config = this.mindMap.getConfig('rainbowLinesConfig') || {}
@@ -1358,11 +1005,7 @@ export default {
)
},
/**
* @Author: 王林
* @Date: 2021-07-03 22:27:32
* @Desc: margin初始值
*/
// margin初始值
initMarginStyle() {
;['marginX', 'marginY'].forEach(key => {
this.style[key] = this.mindMap.getThemeConfig()[this.marginActiveTab][
@@ -1371,11 +1014,7 @@ export default {
})
},
/**
* @Author: 王林
* @Date: 2021-05-05 14:05:40
* @Desc: 更新配置
*/
// 更新配置
update(key, value) {
if (key === 'backgroundImage' && value === 'none') {
this.style[key] = ''
@@ -1393,36 +1032,6 @@ export default {
})
},
// 更新其他配置
updateOtherConfig(key, value) {
this.mindMap.updateConfig({
[key]: value
})
this.data.config = this.data.config || {}
this.data.config[key] = value
storeConfig({
config: this.data.config
})
},
// 更新水印配置
updateWatermarkConfig() {
clearTimeout(this.updateWatermarkTimer)
this.updateWatermarkTimer = setTimeout(() => {
let { show, ...config } = this.watermarkConfig
this.mindMap.watermark.updateWatermark({
...config
})
this.data.config = this.data.config || {}
this.data.config.watermarkConfig = this.mindMap.getConfig(
'watermarkConfig'
)
storeConfig({
config: this.data.config
})
}, 300)
},
// 更新彩虹线条配置
updateRainbowLinesConfig(item) {
this.rainbowLinesPopoverVisible = false
@@ -1474,33 +1083,6 @@ export default {
config: this.data.theme.config
}
})
},
// 切换显示水印与否
watermarkShowChange(value) {
if (value) {
let text =
this.watermarkConfig.text || this.$t('baseStyle.watermarkDefaultText')
this.watermarkConfig.text = text
} else {
this.watermarkConfig.text = ''
}
this.updateWatermarkConfig()
},
// 切换是否开启节点富文本编辑
enableNodeRichTextChange(e) {
this.mindMap.renderer.textEdit.hideEditTextBox()
this.setLocalConfig({
openNodeRichText: e
})
},
// 本地配置
updateLocalConfig(key, value) {
this.setLocalConfig({
[key]: value
})
}
}
}

View File

@@ -89,6 +89,11 @@
</div>
</div>
</div>
<div class="item" @click="setCheckbox" v-if="supportCheckbox">
<span class="name">{{
hasCheckbox ? $t('contextmenu.removeToDo') : $t('contextmenu.addToDo')
}}</span>
</div>
<div class="splitLine"></div>
<div class="item danger" @click="exec('REMOVE_NODE')">
<span class="name">{{ $t('contextmenu.deleteNode') }}</span>
@@ -244,7 +249,8 @@ export default {
...mapState({
isZenMode: state => state.localConfig.isZenMode,
isDark: state => state.localConfig.isDark,
supportNumbers: state => state.supportNumbers
supportNumbers: state => state.supportNumbers,
supportCheckbox: state => state.supportCheckbox
}),
expandList() {
return [
@@ -322,6 +328,9 @@ export default {
},
numberLevelList() {
return numberLevelList[this.$i18n.locale] || numberLevelList.zh
},
hasCheckbox() {
return !!this.node.getData('checkbox')
}
},
created() {
@@ -496,6 +505,21 @@ export default {
this.mindMap.execCommand('SET_NUMBER', [], {
[prop]: value
})
this.hide()
},
// 设置待办
setCheckbox() {
this.mindMap.execCommand(
'SET_CHECKBOX',
[],
this.hasCheckbox
? null
: {
done: false
}
)
this.hide()
},
// 复制到剪贴板

View File

@@ -38,6 +38,7 @@
<SourceCodeEdit v-if="mindMap" :mindMap="mindMap"></SourceCodeEdit>
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
<Setting :data="mindMapData" :mindMap="mindMap"></Setting>
<div
class="dragMask"
v-if="showDragMask"
@@ -74,17 +75,14 @@ import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
import Themes from 'simple-mind-map-plugin-themes'
// 协同编辑插件
// import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
// 手绘风格插件,该插件为付费插件,详情请查看开发文档
// 以下插件为付费插件,详情请查看开发文档。依次为手绘风格插件、标记插件、编号插件、Freemind软件格式导入导出插件、Excel软件格式导入导出插件、待办插件
// import HandDrawnLikeStyle from 'simple-mind-map-plugin-handdrawnlikestyle'
// 标记插件,该插件为付费插件,详情请查看开发文档
// import Notation from 'simple-mind-map-plugin-notation'
// 编号插件,该插件为付费插件,详情请查看开发文档
// import Numbers from 'simple-mind-map-plugin-numbers'
// Freemind软件格式导入导出插件该插件为付费插件详情请查看开发文档
// import Freemind from 'simple-mind-map-plugin-freemind'
// Excel软件格式导入导出插件该插件为付费插件详情请查看开发文档
// import Excel from 'simple-mind-map-plugin-excel'
// npm link simple-mind-map-plugin-excel simple-mind-map-plugin-freemind simple-mind-map-plugin-numbers simple-mind-map-plugin-notation simple-mind-map-plugin-handdrawnlikestyle simple-mind-map simple-mind-map-plugin-themes
// import Checkbox from 'simple-mind-map-plugin-checkbox'
// npm link simple-mind-map-plugin-excel simple-mind-map-plugin-freemind simple-mind-map-plugin-numbers simple-mind-map-plugin-notation simple-mind-map-plugin-handdrawnlikestyle simple-mind-map-plugin-checkbox simple-mind-map simple-mind-map-plugin-themes
import OutlineSidebar from './OutlineSidebar'
import Style from './Style'
import BaseStyle from './BaseStyle'
@@ -121,6 +119,7 @@ import SourceCodeEdit from './SourceCodeEdit.vue'
import NodeAttachment from './NodeAttachment.vue'
import NodeOuterFrame from './NodeOuterFrame.vue'
import NodeTagStyle from './NodeTagStyle.vue'
import Setting from './Setting.vue'
// 注册插件
MindMap.usePlugin(MiniMap)
@@ -176,7 +175,8 @@ export default {
SourceCodeEdit,
NodeAttachment,
NodeOuterFrame,
NodeTagStyle
NodeTagStyle,
Setting
},
data() {
return {
@@ -367,11 +367,12 @@ export default {
// this.$bus.$emit('hideNoteContent')
}
},
openRealtimeRenderOnNodeTextEdit: true,
enableAutoEnterTextEditWhenKeydown: true,
...(config || {}),
iconList: [...icon],
useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
customInnerElsAppendTo: null,
enableAutoEnterTextEditWhenKeydown: true,
customHandleClipboardText: handleClipboardText,
defaultNodeImage: require('../../../assets/img/图片加载失败.svg'),
initRootNodePosition: ['center', 'center'],
@@ -576,6 +577,10 @@ export default {
this.$store.commit('setSupportExcel', true)
Vue.prototype.Excel = Excel
}
if (typeof Checkbox !== 'undefined') {
this.mindMap.addPlugin(Checkbox)
this.$store.commit('setSupportCheckbox', true)
}
this.mindMap.keyCommand.addShortcut('Control+s', () => {
this.manualSave()
})

View File

@@ -0,0 +1,574 @@
<template>
<Sidebar ref="sidebar" :title="$t('setting.title')">
<div class="sidebarContent" :class="{ isDark: isDark }" v-if="data">
<!-- 水印 -->
<div class="title noTop">{{ $t('setting.watermark') }}</div>
<div class="row">
<!-- 是否显示水印 -->
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.show"
@change="watermarkShowChange"
>{{ $t('setting.showWatermark') }}</el-checkbox
>
</div>
</div>
<template v-if="watermarkConfig.show">
<!-- 是否仅在导出时显示 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.onlyExport"
@change="updateWatermarkConfig"
>{{ $t('setting.onlyExport') }}</el-checkbox
>
</div>
</div>
<!-- 是否在节点下方 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="watermarkConfig.belowNode"
@change="updateWatermarkConfig"
>{{ $t('setting.belowNode') }}</el-checkbox
>
</div>
</div>
<!-- 水印文字 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkText') }}</span>
<el-input
v-model="watermarkConfig.text"
size="small"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input>
</div>
</div>
<!-- 水印文字颜色 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkTextColor') }}</span>
<span
class="block"
v-popover:popover3
:style="{ backgroundColor: watermarkConfig.textStyle.color }"
></span>
<el-popover ref="popover3" placement="bottom" trigger="click">
<Color
:color="watermarkConfig.textStyle.color"
@change="
value => {
watermarkConfig.textStyle.color = value
updateWatermarkConfig()
}
"
></Color>
</el-popover>
</div>
</div>
<!-- 水印文字透明度 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkTextOpacity') }}</span>
<el-slider
v-model="watermarkConfig.textStyle.opacity"
style="width: 170px"
:min="0"
:max="1"
:step="0.1"
@change="updateWatermarkConfig"
></el-slider>
</div>
</div>
<!-- 水印文字字号 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkTextFontSize') }}</span>
<el-input-number
v-model="watermarkConfig.textStyle.fontSize"
size="small"
:min="0"
:max="50"
:step="1"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 旋转角度 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkAngle') }}</span>
<el-input-number
v-model="watermarkConfig.angle"
size="small"
:min="0"
:max="90"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 水印行间距 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkLineSpacing') }}</span>
<el-input-number
v-model="watermarkConfig.lineSpacing"
size="small"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
<!-- 水印文字间距 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.watermarkTextSpacing') }}</span>
<el-input-number
v-model="watermarkConfig.textSpacing"
size="small"
:step="10"
@change="updateWatermarkConfig"
@keydown.native.stop
></el-input-number>
</div>
</div>
</template>
<!-- 配置性能模式 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.openPerformance"
@change="
value => {
updateOtherConfig('openPerformance', value)
}
"
>{{ $t('setting.openPerformance') }}</el-checkbox
>
</div>
</div>
<!-- 配置开启自由拖拽 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.enableFreeDrag"
@change="
value => {
updateOtherConfig('enableFreeDrag', value)
}
"
>{{ $t('setting.enableFreeDrag') }}</el-checkbox
>
</div>
</div>
<!-- 配置是否启用富文本编辑 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="enableNodeRichText"
@change="enableNodeRichTextChange"
>{{ $t('setting.isEnableNodeRichText') }}</el-checkbox
>
</div>
</div>
<!-- 是否开启文本编辑时实时更新节点大小 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.openRealtimeRenderOnNodeTextEdit"
@change="
updateOtherConfig('openRealtimeRenderOnNodeTextEdit', $event)
"
>{{ $t('setting.openRealtimeRenderOnNodeTextEdit') }}</el-checkbox
>
</div>
</div>
<!-- 是否显示滚动条 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="localConfigs.isShowScrollbar"
@change="updateLocalConfig('isShowScrollbar', $event)"
>{{ $t('setting.isShowScrollbar') }}</el-checkbox
>
</div>
</div>
<!-- 是否一直显示展开收起按钮 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.alwaysShowExpandBtn"
@change="updateOtherConfig('alwaysShowExpandBtn', $event)"
>{{ $t('setting.alwaysShowExpandBtn') }}</el-checkbox
>
</div>
</div>
<!-- 是否在键盘输入时自动进入节点文本编辑模式 -->
<div class="row">
<div class="rowItem">
<el-checkbox
v-model="config.enableAutoEnterTextEditWhenKeydown"
@change="updateOtherConfig('enableAutoEnterTextEditWhenKeydown', $event)"
>{{ $t('setting.enableAutoEnterTextEditWhenKeydown') }}</el-checkbox
>
</div>
</div>
<!-- 是否开启手绘风格 -->
<div class="row" v-if="supportHandDrawnLikeStyle">
<div class="rowItem">
<el-checkbox
v-model="localConfigs.isUseHandDrawnLikeStyle"
@change="updateLocalConfig('isUseHandDrawnLikeStyle', $event)"
>{{ $t('setting.isUseHandDrawnLikeStyle') }}</el-checkbox
>
</div>
</div>
<!-- 配置鼠标滚轮行为 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.mousewheelAction') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.mousewheelAction"
placeholder=""
@change="
value => {
updateOtherConfig('mousewheelAction', value)
}
"
>
<el-option :label="$t('setting.zoomView')" value="zoom"></el-option>
<el-option
:label="$t('setting.moveViewUpDown')"
value="move"
></el-option>
</el-select>
</div>
</div>
<!-- 配置鼠标缩放行为 -->
<div class="row" v-if="config.mousewheelAction === 'zoom'">
<div class="rowItem">
<span class="name">{{
$t('setting.mousewheelZoomActionReverse')
}}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.mousewheelZoomActionReverse"
placeholder=""
@change="
value => {
updateOtherConfig('mousewheelZoomActionReverse', value)
}
"
>
<el-option
:label="$t('setting.mousewheelZoomActionReverse1')"
:value="false"
></el-option>
<el-option
:label="$t('setting.mousewheelZoomActionReverse2')"
:value="true"
></el-option>
</el-select>
</div>
</div>
<!-- 配置创建新节点时的行为 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.createNewNodeBehavior') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.createNewNodeBehavior"
placeholder=""
@change="
value => {
updateOtherConfig('createNewNodeBehavior', value)
}
"
>
<el-option
:label="$t('setting.default')"
value="default"
></el-option>
<el-option
:label="$t('setting.notActive')"
value="notActive"
></el-option>
<el-option
:label="$t('setting.activeOnly')"
value="activeOnly"
></el-option>
</el-select>
</div>
</div>
<!-- 标签显示的位置 -->
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('setting.tagPosition') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="config.tagPosition"
placeholder=""
@change="
value => {
updateOtherConfig('tagPosition', value)
}
"
>
<el-option
:label="$t('setting.tagPositionRight')"
value="right"
></el-option>
<el-option
:label="$t('setting.tagPositionBottom')"
value="bottom"
></el-option>
</el-select>
</div>
</div>
</div>
</Sidebar>
</template>
<script>
import Sidebar from './Sidebar'
import { storeConfig } from '@/api'
import { mapState, mapMutations } from 'vuex'
import Color from './Color'
export default {
components: {
Sidebar,
Color
},
props: {
data: {
type: [Object, null],
default: null
},
mindMap: {
type: Object
}
},
data() {
return {
config: {
openPerformance: false,
enableFreeDrag: false,
mousewheelAction: 'zoom',
mousewheelZoomActionReverse: false,
createNewNodeBehavior: 'default',
tagPosition: 'right',
openRealtimeRenderOnNodeTextEdit: true,
alwaysShowExpandBtn: false,
enableAutoEnterTextEditWhenKeydown: true
},
watermarkConfig: {
show: false,
onlyExport: false,
text: '',
lineSpacing: 100,
textSpacing: 100,
angle: 30,
textStyle: {
color: '',
opacity: 0,
fontSize: 1
}
},
updateWatermarkTimer: null,
enableNodeRichText: true,
localConfigs: {
isShowScrollbar: false,
isUseHandDrawnLikeStyle: false
}
}
},
computed: {
...mapState({
activeSidebar: state => state.activeSidebar,
localConfig: state => state.localConfig,
isDark: state => state.localConfig.isDark,
supportHandDrawnLikeStyle: state => state.supportHandDrawnLikeStyle
})
},
watch: {
activeSidebar(val) {
if (val === 'setting') {
this.$refs.sidebar.show = true
this.initConfig()
this.initWatermark()
} else {
this.$refs.sidebar.show = false
}
}
},
created() {
this.initLoacalConfig()
},
beforeDestroy() {},
methods: {
...mapMutations(['setLocalConfig']),
// 初始化其他配置
initConfig() {
Object.keys(this.config).forEach(key => {
this.config[key] = this.mindMap.getConfig(key)
})
},
// 初始化本地配置
initLoacalConfig() {
this.enableNodeRichText = this.localConfig.openNodeRichText
this.mousewheelAction = this.localConfig.mousewheelAction
this.mousewheelZoomActionReverse = this.localConfig.mousewheelZoomActionReverse
;['isShowScrollbar', 'isUseHandDrawnLikeStyle'].forEach(key => {
this.localConfigs[key] = this.localConfig[key]
})
},
// 初始化水印配置
initWatermark() {
const config = this.mindMap.getConfig('watermarkConfig')
;['text', 'lineSpacing', 'textSpacing', 'angle', 'onlyExport'].forEach(
key => {
this.watermarkConfig[key] = config[key]
}
)
this.watermarkConfig.show = !!config.text
this.watermarkConfig.textStyle = { ...config.textStyle }
},
// 更新其他配置
updateOtherConfig(key, value) {
this.mindMap.updateConfig({
[key]: value
})
this.data.config = this.data.config || {}
this.data.config[key] = value
storeConfig({
config: this.data.config
})
if (['tagPosition', 'alwaysShowExpandBtn'].includes(key)) {
this.mindMap.reRender()
}
},
// 更新水印配置
updateWatermarkConfig() {
clearTimeout(this.updateWatermarkTimer)
this.updateWatermarkTimer = setTimeout(() => {
let { show, ...config } = this.watermarkConfig
this.mindMap.watermark.updateWatermark({
...config
})
this.data.config = this.data.config || {}
this.data.config.watermarkConfig = this.mindMap.getConfig(
'watermarkConfig'
)
storeConfig({
config: this.data.config
})
}, 300)
},
// 切换显示水印与否
watermarkShowChange(value) {
if (value) {
let text =
this.watermarkConfig.text || this.$t('setting.watermarkDefaultText')
this.watermarkConfig.text = text
} else {
this.watermarkConfig.text = ''
}
this.updateWatermarkConfig()
},
// 切换是否开启节点富文本编辑
enableNodeRichTextChange(e) {
this.mindMap.renderer.textEdit.hideEditTextBox()
this.setLocalConfig({
openNodeRichText: e
})
},
// 本地配置
updateLocalConfig(key, value) {
this.setLocalConfig({
[key]: value
})
}
}
}
</script>
<style lang="less" scoped>
.sidebarContent {
padding: 20px;
padding-top: 10px;
&.isDark {
.title {
color: #fff;
}
.row {
.rowItem {
.name {
color: hsla(0, 0%, 100%, 0.6);
}
}
}
}
.title {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(26, 26, 26, 0.9);
margin-bottom: 10px;
margin-top: 20px;
&.noTop {
margin-top: 0;
}
}
.row {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
.rowItem {
display: flex;
align-items: center;
margin-bottom: 5px;
.name {
font-size: 12px;
margin-right: 10px;
white-space: nowrap;
}
.block {
display: inline-block;
width: 30px;
height: 30px;
border: 1px solid #dcdfe6;
border-radius: 4px;
cursor: pointer;
}
}
}
}
</style>

View File

@@ -13,6 +13,7 @@
<span class="name">{{ $t('style.fontFamily') }}</span>
<el-select
size="mini"
style="width: 100px"
v-model="style.fontFamily"
placeholder=""
@change="update('fontFamily')"
@@ -27,8 +28,6 @@
</el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('style.fontSize') }}</span>
<el-select
@@ -48,24 +47,6 @@
</el-option>
</el-select>
</div>
<div class="rowItem">
<span class="name">{{ $t('style.lineHeight') }}</span>
<el-select
size="mini"
style="width: 80px"
v-model="style.lineHeight"
placeholder=""
@change="update('lineHeight')"
>
<el-option
v-for="item in lineHeightList"
:key="item"
:label="item"
:value="item"
>
</el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="btnGroup">
@@ -474,7 +455,6 @@ import {
borderWidthList,
borderDasharrayList,
borderRadiusList,
lineHeightList,
shapeList,
shapeListMap,
linearGradientDirList
@@ -497,7 +477,6 @@ export default {
fontSizeList,
borderWidthList,
borderRadiusList,
lineHeightList,
activeNodes: [],
style: {
shape: '',
@@ -506,7 +485,6 @@ export default {
color: '',
fontFamily: '',
fontSize: '',
lineHeight: '',
textDecoration: '',
fontWeight: '',
fontStyle: '',
@@ -593,7 +571,6 @@ export default {
'color',
'fontFamily',
'fontSize',
'lineHeight',
'textDecoration',
'fontWeight',
'fontStyle',

View File

@@ -33,6 +33,7 @@ const store = new Vuex.Store({
supportNumbers: false, // 是否支持编号
supportFreemind: false, // 是否支持Freemind插件
supportExcel: false, // 是否支持Excel插件
supportCheckbox: false, // 是否支持Checkbox插件
isDragOutlineTreeNode: false // 当前是否正在拖拽大纲树的节点
},
mutations: {
@@ -105,6 +106,11 @@ const store = new Vuex.Store({
state.supportExcel = data
},
// 设置是否支持Checkbox插件
setSupportCheckbox(state, data) {
state.supportCheckbox = data
},
// 设置树节点拖拽
setIsDragOutlineTreeNode(state, data) {
state.isDragOutlineTreeNode = data