mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-25 11:18:40 +08:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0041be9892 | ||
|
|
7ebab0298b | ||
|
|
079b963ae3 | ||
|
|
fb6fcd6bd3 | ||
|
|
59950b2ba0 | ||
|
|
1f23257917 | ||
|
|
4e1db01f44 | ||
|
|
38769c3b55 | ||
|
|
a4ef09779d | ||
|
|
4821dd6052 | ||
|
|
f33c886d6a | ||
|
|
b5b8c2be60 | ||
|
|
4a7485c58e | ||
|
|
c097d20748 | ||
|
|
eeeae7d0e2 | ||
|
|
dd3e169946 | ||
|
|
b895a58194 | ||
|
|
2b42b9fafa | ||
|
|
c2125b07ca | ||
|
|
eb342bf69b | ||
|
|
a7eb66a6c9 | ||
|
|
e24fd9bdbb | ||
|
|
34d7c6fed2 | ||
|
|
a0f88031c1 | ||
|
|
889ec13dbf | ||
|
|
4aa5a8c48b | ||
|
|
0ec20b8fa0 | ||
|
|
f3285cf4e6 |
14
README.md
14
README.md
@@ -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(节点编号插件)[收费]、Freemind(Freemind格式导入导出插件)[收费]、Excel(Excel格式导入导出插件)[收费]
|
||||
> RichText(节点富文本插件)、Select(鼠标多选节点插件)、Drag(节点拖拽插件)、AssociativeLine(关联线插件)、Export(导出插件)、KeyboardNavigation(键盘导航插件)、MiniMap(小地图插件)、Watermark(水印插件)、TouchEvent(移动端触摸事件支持插件)、NodeImgAdjust(拖拽调整节点图片大小插件)、Search(搜索插件)、Painter(节点格式刷插件)、Scrollbar(滚动条插件)、Formula(数学公式插件)、Cooperate(协同编辑插件)、RainbowLines(彩虹线条插件)、Demonstrate(演示模式插件)、OuterFrame(外框插件)、HandDrawnLikeStyle(手绘风格插件)[收费]、Notation(节点标记插件)[收费]、Numbers(节点编号插件)[收费]、Freemind(Freemind格式导入导出插件)[收费]、Excel(Excel格式导入导出插件)[收费]、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
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
@@ -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>
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.12.0",
|
||||
"version": "0.12.1",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -226,7 +226,7 @@ export const defaultOpt = {
|
||||
// 移动节点到画布中心、回到根节点等操作时是否将缩放层级复位为100%
|
||||
// 该选项实际影响的是render.moveNodeToCenter方法,moveNodeToCenter方法本身也存在第二个参数resetScale来设置是否复位,如果resetScale参数没有传递,那么使用resetScaleOnMoveNodeToCenter配置,否则使用resetScale配置
|
||||
resetScaleOnMoveNodeToCenter: false,
|
||||
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
|
||||
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。如果存在编号、任务勾选框内容,这里添加的前置内容会在这两者之后
|
||||
createNodePrefixContent: null,
|
||||
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
|
||||
createNodePostfixContent: null,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'])
|
||||
})
|
||||
}
|
||||
|
||||
// 强制渲染节点,不考虑是否在画布可视区域内
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.自定义节点内容
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ function createTextAvatar(item) {
|
||||
color: '#fff'
|
||||
})
|
||||
.css({
|
||||
'font-size': fontSize
|
||||
'font-size': fontSize + 'px'
|
||||
})
|
||||
.dx(-fontSize / 2)
|
||||
.dy((avatarSize - fontSize) / 2)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -71,7 +71,9 @@ function onDragMousemoveHandle(e) {
|
||||
this.left = this.dragHandleMousedownLeft + ox / scaleX
|
||||
}
|
||||
// 自定义内容不重新渲染,交给开发者
|
||||
this.reRender(useCustomContent ? [] : ['text'])
|
||||
this.reRender(useCustomContent ? [] : ['text'], {
|
||||
ignoreUpdateCustomTextWidth: true
|
||||
})
|
||||
}
|
||||
|
||||
// 鼠标松开事件
|
||||
|
||||
@@ -354,6 +354,10 @@ class View {
|
||||
|
||||
// 判断是否需要将思维导图限制在画布内
|
||||
checkNeedMindMapInCanvas() {
|
||||
// 如果当前在演示模式,那么不需要限制
|
||||
if (this.mindMap.demonstrate && this.mindMap.demonstrate.isInDemonstrate) {
|
||||
return false
|
||||
}
|
||||
const { isLimitMindMapInCanvasWhenHasScrollbar, isLimitMindMapInCanvas } =
|
||||
this.mindMap.opt
|
||||
// 如果注册了滚动条插件,那么使用isLimitMindMapInCanvasWhenHasScrollbar配置
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ function styleText(node) {
|
||||
})
|
||||
.css({
|
||||
'font-family': associativeLineTextFontFamily,
|
||||
'font-size': associativeLineTextFontSize
|
||||
'font-size': associativeLineTextFontSize + 'px'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
BIN
web/src/assets/avatar/h.r.w.jpg
Normal file
BIN
web/src/assets/avatar/h.r.w.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
web/src/assets/avatar/皮老板.jpg
Normal file
BIN
web/src/assets/avatar/皮老板.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -439,6 +439,11 @@ export const sidebarTriggerList = [
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: 'Setting',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
},
|
||||
{
|
||||
name: 'ShortcutKey',
|
||||
value: 'shortcutKey',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
fontSizeList,
|
||||
lineHeightList,
|
||||
colorList,
|
||||
borderWidthList,
|
||||
borderRadiusList,
|
||||
@@ -155,7 +154,6 @@ const linearGradientDirList = {
|
||||
|
||||
export {
|
||||
fontSizeList,
|
||||
lineHeightList,
|
||||
borderWidthList,
|
||||
borderRadiusList,
|
||||
lineWidthList,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -439,6 +439,11 @@ export const sidebarTriggerList = [
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: '設置',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
},
|
||||
{
|
||||
name: '快捷鍵',
|
||||
value: 'shortcutKey',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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: '斜体',
|
||||
|
||||
@@ -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: '斜體',
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
},
|
||||
|
||||
// 复制到剪贴板
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
574
web/src/pages/Edit/components/Setting.vue
Normal file
574
web/src/pages/Edit/components/Setting.vue
Normal 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>
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user