Demo:新增节点标记功能

This commit is contained in:
街角小林 2024-06-13 15:01:22 +08:00
parent d14fb0b666
commit e7f1608605
12 changed files with 346 additions and 14 deletions

View File

@ -314,7 +314,8 @@ export const nodeDataNoStylePropList = [
'associativeLinePoint',
'associativeLineText',
'attachmentUrl',
'attachmentName'
'attachmentName',
'notation'
]
// 错误类型

View File

@ -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";
}

View File

@ -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'
}
}

View File

@ -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: '开启动画'
}
}

View File

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

View 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>

View File

@ -189,8 +189,9 @@ export default {
'tag',
'summary',
'associativeLine',
'formula'
// 'attachment'
'formula',
// 'attachment',
'annotation'
],
horizontalList: [],
verticalList: [],

View File

@ -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;

View File

@ -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: {