mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-21 10:27:44 +08:00
Demo:新增节点标记功能
This commit is contained in:
parent
d14fb0b666
commit
e7f1608605
@ -314,7 +314,8 @@ export const nodeDataNoStylePropList = [
|
||||
'associativeLinePoint',
|
||||
'associativeLineText',
|
||||
'attachmentUrl',
|
||||
'attachmentName'
|
||||
'attachmentName',
|
||||
'notation'
|
||||
]
|
||||
|
||||
// 错误类型
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1713438156457') format('woff2'),
|
||||
url('iconfont.woff?t=1713438156457') format('woff'),
|
||||
url('iconfont.ttf?t=1713438156457') format('truetype');
|
||||
src: url('iconfont.woff2?t=1718261316837') format('woff2'),
|
||||
url('iconfont.woff?t=1718261316837') format('woff'),
|
||||
url('iconfont.ttf?t=1718261316837') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,10 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconhighlight:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.iconyanshibofang:before {
|
||||
content: "\e648";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -278,8 +278,10 @@ export default {
|
||||
defaultFileName: 'Mind map',
|
||||
creatingTip: 'Creating file',
|
||||
directory: 'Directory',
|
||||
newFileTip: 'Please export the currently edited file before creating a new one, otherwise the content will be lost',
|
||||
openFileTip: 'Please export the currently edited file before opening it, otherwise the content will be lost'
|
||||
newFileTip:
|
||||
'Please export the currently edited file before creating a new one, otherwise the content will be lost',
|
||||
openFileTip:
|
||||
'Please export the currently edited file before opening it, otherwise the content will be lost'
|
||||
},
|
||||
edit: {
|
||||
newFeatureNoticeTitle: 'New feature reminder',
|
||||
@ -333,7 +335,8 @@ export default {
|
||||
loading: 'Loading, please wait...'
|
||||
},
|
||||
sourceCodeEdit: {
|
||||
sourceCodeTip: 'It is not recommended to modify the style in rich text mode because it requires synchronous modification of data and HTML structure.',
|
||||
sourceCodeTip:
|
||||
'It is not recommended to modify the style in rich text mode because it requires synchronous modification of data and HTML structure.',
|
||||
format: 'Format',
|
||||
copy: 'Copy',
|
||||
confirm: 'Complete',
|
||||
@ -345,5 +348,14 @@ export default {
|
||||
attachment: {
|
||||
deleteAttachment: 'Delete attachment',
|
||||
tip: 'The attachment function is only available on the client side'
|
||||
},
|
||||
annotation: {
|
||||
mark: 'Mark',
|
||||
show: 'Show mark',
|
||||
type: 'Type',
|
||||
color: 'Color',
|
||||
lineWidth: 'Line width',
|
||||
padding: 'Padding',
|
||||
animate: 'Animate'
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,7 +327,8 @@ export default {
|
||||
loading: '正在加载,请稍后...'
|
||||
},
|
||||
sourceCodeEdit: {
|
||||
sourceCodeTip: '富文本模式下不建议修改样式,因为需要同步修改数据及html结构。',
|
||||
sourceCodeTip:
|
||||
'富文本模式下不建议修改样式,因为需要同步修改数据及html结构。',
|
||||
format: '格式化',
|
||||
copy: '复制',
|
||||
confirm: '完成',
|
||||
@ -339,5 +340,14 @@ export default {
|
||||
attachment: {
|
||||
deleteAttachment: '删除附件',
|
||||
tip: '附件功能仅在客户端可用'
|
||||
},
|
||||
annotation: {
|
||||
mark: '标记',
|
||||
show: '显示标记',
|
||||
type: '类型',
|
||||
color: '颜色',
|
||||
lineWidth: '线宽',
|
||||
padding: '内边距',
|
||||
animate: '开启动画'
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,8 @@ import Demonstrate from 'simple-mind-map/src/plugins/Demonstrate.js'
|
||||
// import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
||||
// 手绘风格插件,该插件为付费插件,详情请查看开发文档
|
||||
// import HandDrawnLikeStyle from 'simple-mind-map-plugin-handdrawnlikestyle'
|
||||
// 标记插件,该插件为付费插件,详情请查看开发文档
|
||||
// import Notation from 'simple-mind-map-plugin-notation'
|
||||
import OutlineSidebar from './OutlineSidebar'
|
||||
import Style from './Style'
|
||||
import BaseStyle from './BaseStyle'
|
||||
@ -493,6 +495,13 @@ export default {
|
||||
if (this.openNodeRichText) this.addRichTextPlugin()
|
||||
if (this.isShowScrollbar) this.addScrollbarPlugin()
|
||||
if (this.isUseHandDrawnLikeStyle) this.addHandDrawnLikeStylePlugin()
|
||||
if (typeof HandDrawnLikeStyle !== 'undefined') {
|
||||
this.$store.commit('setSupportHandDrawnLikeStyle', true)
|
||||
}
|
||||
if (typeof Notation !== 'undefined') {
|
||||
this.mindMap.addPlugin(Notation)
|
||||
this.$store.commit('setSupportMark', true)
|
||||
}
|
||||
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
||||
this.manualSave()
|
||||
})
|
||||
|
||||
269
web/src/pages/Edit/components/NodeAnnotationBtn.vue
Normal file
269
web/src/pages/Edit/components/NodeAnnotationBtn.vue
Normal file
@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<el-popover placement="bottom" width="200" trigger="click">
|
||||
<div class="annotationConfigBox" :class="{ isDark: isDark }">
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.show') }}</span>
|
||||
<el-switch
|
||||
v-model="show"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
@change="onChange"
|
||||
>
|
||||
</el-switch>
|
||||
</div>
|
||||
<template v-if="show">
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.type') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="annotationConfig.type"
|
||||
@change="onChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in annotationTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover
|
||||
:style="{ backgroundColor: annotationConfig.color }"
|
||||
></span>
|
||||
<el-popover ref="popover" placement="bottom" trigger="hover">
|
||||
<Color
|
||||
:color="annotationConfig.color"
|
||||
@change="onColorChange"
|
||||
></Color>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.lineWidth') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
v-model="annotationConfig.strokeWidth"
|
||||
placeholder=""
|
||||
@change="onChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in lineWidthList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
>
|
||||
<span
|
||||
v-if="item > 0"
|
||||
class="borderLine"
|
||||
:class="{ isDark: isDark }"
|
||||
:style="{ height: item + 'px' }"
|
||||
></span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.padding') }}</span>
|
||||
<el-input-number
|
||||
v-model="annotationConfig.padding"
|
||||
:step="5"
|
||||
size="mini"
|
||||
@change="onChange"
|
||||
></el-input-number>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.animate') }}</span>
|
||||
<el-switch
|
||||
v-model="annotationConfig.animate"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
@change="onChange"
|
||||
>
|
||||
</el-switch>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
slot="reference"
|
||||
class="toolbarBtn"
|
||||
:style="{
|
||||
marginLeft: dir === 'v' ? '0px' : '20px',
|
||||
marginTop: dir === 'v' ? '10px' : '0px'
|
||||
}"
|
||||
:class="{
|
||||
disabled: activeNodes.length <= 0 || hasGeneralization
|
||||
}"
|
||||
>
|
||||
<span class="icon iconfont iconhighlight"></span>
|
||||
<span class="text">{{ $t('annotation.mark') }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { lineWidthList } from '@/config'
|
||||
import Color from './Color'
|
||||
|
||||
const defaultConfig = {
|
||||
type: 'circle',
|
||||
color: '',
|
||||
strokeWidth: 1,
|
||||
animate: true,
|
||||
padding: 20
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Color
|
||||
},
|
||||
props: {
|
||||
isDark: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dir: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lineWidthList: lineWidthList.slice(1),
|
||||
activeNodes: [],
|
||||
show: false,
|
||||
annotationConfig: {
|
||||
...defaultConfig
|
||||
},
|
||||
annotationTypeList: [
|
||||
{
|
||||
label: '圆',
|
||||
value: 'circle'
|
||||
},
|
||||
{
|
||||
label: '边框',
|
||||
value: 'box'
|
||||
},
|
||||
{
|
||||
label: '高亮',
|
||||
value: 'highlight'
|
||||
},
|
||||
{
|
||||
label: '下划线',
|
||||
value: 'underline'
|
||||
},
|
||||
{
|
||||
label: '删除线',
|
||||
value: 'strike-through'
|
||||
},
|
||||
{
|
||||
label: '叉',
|
||||
value: 'crossed-off'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasGeneralization() {
|
||||
return (
|
||||
this.activeNodes.findIndex(node => {
|
||||
return node.isGeneralization
|
||||
}) !== -1
|
||||
)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$bus.$on('node_active', this.onNodeActive)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('node_active', this.onNodeActive)
|
||||
},
|
||||
methods: {
|
||||
onNodeActive(...args) {
|
||||
this.activeNodes = [...args[1]]
|
||||
const node = this.activeNodes[0]
|
||||
if (node) {
|
||||
const notationData = node.getData('notation')
|
||||
if (notationData) {
|
||||
const { show, config } = notationData
|
||||
this.show = show
|
||||
this.annotationConfig = {
|
||||
...defaultConfig,
|
||||
...config
|
||||
}
|
||||
} else {
|
||||
this.reset()
|
||||
}
|
||||
} else {
|
||||
this.reset()
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.show = false
|
||||
this.annotationConfig = {
|
||||
...defaultConfig
|
||||
}
|
||||
},
|
||||
|
||||
onChange() {
|
||||
this.$emit('setAnnotation', this.show, {
|
||||
...this.annotationConfig
|
||||
})
|
||||
},
|
||||
|
||||
onColorChange(color) {
|
||||
this.annotationConfig.color = color
|
||||
this.onChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.annotationConfigBox {
|
||||
&.isDark {
|
||||
.annotationConfigItem {
|
||||
.name {
|
||||
color: hsla(0, 0%, 100%, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.annotationConfigItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex-shrink: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.block {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.borderLine {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background-color: #000;
|
||||
|
||||
&.isDark {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -189,8 +189,9 @@ export default {
|
||||
'tag',
|
||||
'summary',
|
||||
'associativeLine',
|
||||
'formula'
|
||||
// 'attachment'
|
||||
'formula',
|
||||
// 'attachment',
|
||||
'annotation'
|
||||
],
|
||||
horizontalList: [],
|
||||
verticalList: [],
|
||||
|
||||
@ -167,14 +167,22 @@
|
||||
<span class="icon iconfont iconfujian"></span>
|
||||
<span class="text">{{ $t('toolbar.attachment') }}</span>
|
||||
</div>
|
||||
<NodeAnnotationBtn
|
||||
v-if="item === 'annotation' && supportMark"
|
||||
:isDark="isDark"
|
||||
:dir="dir"
|
||||
@setAnnotation="onSetAnnotation"
|
||||
></NodeAnnotationBtn>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import NodeAnnotationBtn from './NodeAnnotationBtn.vue'
|
||||
|
||||
export default {
|
||||
components: { NodeAnnotationBtn },
|
||||
props: {
|
||||
dir: {
|
||||
type: String,
|
||||
@ -200,7 +208,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportMark: state => state.supportMark
|
||||
}),
|
||||
hasRoot() {
|
||||
return (
|
||||
@ -274,12 +283,17 @@ export default {
|
||||
// 选择附件
|
||||
selectAttachmentFile() {
|
||||
this.$bus.$emit('selectAttachment', this.activeNodes)
|
||||
},
|
||||
|
||||
// 设置标记
|
||||
onSetAnnotation(...args) {
|
||||
this.$bus.$emit('execCommand', 'SET_NOTATION', this.activeNodes, ...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
<style lang="less">
|
||||
.toolbarNodeBtnList {
|
||||
display: flex;
|
||||
|
||||
|
||||
@ -21,13 +21,15 @@ const store = new Vuex.Store({
|
||||
// 是否开启手绘风格
|
||||
isUseHandDrawnLikeStyle: false,
|
||||
// 是否是暗黑模式
|
||||
isDark: false,
|
||||
isDark: false
|
||||
},
|
||||
activeSidebar: '', // 当前显示的侧边栏
|
||||
isOutlineEdit: false, // 是否是大纲编辑模式
|
||||
isReadonly: false, // 是否只读
|
||||
isSourceCodeEdit: false, // 是否是源码编辑模式
|
||||
extraTextOnExport: ''// 导出时底部添加的文字
|
||||
extraTextOnExport: '', // 导出时底部添加的文字
|
||||
supportHandDrawnLikeStyle: false, // 是否支持设置手绘风格
|
||||
supportMark: false // 是否支持标记
|
||||
},
|
||||
mutations: {
|
||||
// 设置思维导图数据
|
||||
@ -72,6 +74,16 @@ const store = new Vuex.Store({
|
||||
// 设置导出时底部添加的文字
|
||||
setExtraTextOnExport(state, data) {
|
||||
state.extraTextOnExport = data
|
||||
},
|
||||
|
||||
// 设置是否支持手绘风格
|
||||
setSupportHandDrawnLikeStyle(state, data) {
|
||||
state.supportHandDrawnLikeStyle = data
|
||||
},
|
||||
|
||||
// 设置是否支持标记
|
||||
setSupportMark(state, data) {
|
||||
state.supportMark = data
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user