Demo:支持调整节点图片和标签布局方式的设置

This commit is contained in:
wanglin2
2025-01-24 21:30:43 +08:00
parent 774609f209
commit c774bf01ef
11 changed files with 250 additions and 39 deletions

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2479351 */
src: url('iconfont.woff2?t=1737022296799') format('woff2'),
url('iconfont.woff?t=1737022296799') format('woff'),
url('iconfont.ttf?t=1737022296799') format('truetype');
src: url('iconfont.woff2?t=1737722825571') format('woff2'),
url('iconfont.woff?t=1737722825571') format('woff'),
url('iconfont.ttf?t=1737722825571') format('truetype');
}
.iconfont {
@@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale;
}
.iconcontentleft:before {
content: "\e8c9";
}
.iconjuzhongduiqi:before {
content: "\ec80";
}

View File

@@ -73,7 +73,6 @@ export default {
watermarkTextOpacity: 'Text opacity',
watermarkTextFontSize: 'Font size',
belowNode: 'Display below nodes',
tagPosition: 'Node tag position',
tagPositionRight: 'Text right',
tagPositionBottom: 'Text bottom',
alwaysShowExpandBtn: 'Always show expand btn',
@@ -264,7 +263,14 @@ export default {
openLineFlow: 'Open line flow',
lineFlowDuration: 'Line flow duration',
forward: 'Forward',
reverse: 'Reverse'
reverse: 'Reverse',
img: 'Image',
placement: 'Placement',
top: 'Top',
bottom: 'Bottom',
left: 'Left',
right: 'Right',
tag: 'Tag',
},
theme: {
title: 'Theme',

View File

@@ -71,7 +71,6 @@ export default {
watermarkTextOpacity: '文字透明度',
watermarkTextFontSize: '文字字号',
belowNode: '显示在节点下方',
tagPosition: '节点标签显示的位置',
tagPositionRight: '文本右侧',
tagPositionBottom: '文本下面',
alwaysShowExpandBtn: '是否一直显示展开收起按钮',
@@ -260,7 +259,14 @@ export default {
openLineFlow: '开启流动效果',
lineFlowDuration: '一个流动周期的时间',
forward: '正向',
reverse: '反向'
reverse: '反向',
img: '图片',
placement: '布局',
top: '上',
bottom: '下',
left: '左',
right: '右',
tag: '标签',
},
theme: {
title: '主题',

View File

@@ -41,7 +41,6 @@ export default {
rainbowLines: '彩虹線條',
notUseRainbowLines: '不使用彩虹線條',
outerFramePadding: '外框內距',
tagPosition: '節點標簽顯示的位置',
tagPositionRight: '文本右側',
tagPositionBottom: '文本下面',
alwaysShowExpandBtn: '是否壹直顯示展開收起按鈕',
@@ -260,7 +259,14 @@ export default {
openLineFlow: '開啓流動效果',
lineFlowDuration: '一個流動周期的時間',
forward: '正向',
reverse: '反向'
reverse: '反向',
img: '圖片',
placement: '布局',
top: '上',
bottom: '下',
left: '左',
right: '右',
tag: '標簽',
},
theme: {
title: '主題',

View File

@@ -43,6 +43,10 @@
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
<Setting :data="mindMapData" :mindMap="mindMap"></Setting>
<NodeImgPlacementToolbar
v-if="mindMap"
:mindMap="mindMap"
></NodeImgPlacementToolbar>
<div
class="dragMask"
v-if="showDragMask"
@@ -127,6 +131,7 @@ import NodeOuterFrame from './NodeOuterFrame.vue'
import NodeTagStyle from './NodeTagStyle.vue'
import Setting from './Setting.vue'
import AssociativeLineStyle from './AssociativeLineStyle.vue'
import NodeImgPlacementToolbar from './NodeImgPlacementToolbar.vue'
// 注册插件
MindMap.usePlugin(MiniMap)
@@ -180,7 +185,8 @@ export default {
NodeOuterFrame,
NodeTagStyle,
Setting,
AssociativeLineStyle
AssociativeLineStyle,
NodeImgPlacementToolbar
},
data() {
return {

View File

@@ -0,0 +1,164 @@
<template>
<div
class="nodeImgPlacementToolbar"
ref="nodeImgPlacementToolbar"
:style="style"
@click.stop.passive
v-show="showImgPlacementToolbar"
>
<div
class="imgPlacementItem iconfont iconcontentleft"
v-for="item in imgPlacementList"
:key="item"
:class="[
{
selected: imgPlacement === item
},
'icon_' + item
]"
@click="updateImgPlacement(item)"
></div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
name: 'NodeImgPlacementToolbar',
components: {},
props: {
mindMap: {
type: Object
}
},
data() {
return {
showImgPlacementToolbar: false,
style: {
left: 0,
top: 0
},
imgPlacementList: ['top', 'bottom', 'left', 'right'],
node: null,
imgNode: null,
imgPlacement: ''
}
},
computed: {},
created() {
this.mindMap.on('node_img_click', this.show)
this.mindMap.on('draw_click', this.close)
this.mindMap.on('svg_mousedown', this.close)
this.mindMap.on('node_dblclick', this.close)
this.mindMap.on('node_active', this.onNodeActive)
this.mindMap.on('scale', this.onScale)
},
mounted() {
document.body.append(this.$refs.nodeImgPlacementToolbar)
},
beforeDestroy() {
this.mindMap.off('node_img_click', this.show)
this.mindMap.off('draw_click', this.close)
this.mindMap.off('svg_mousedown', this.close)
this.mindMap.off('node_dblclick', this.close)
this.mindMap.off('node_active', this.onNodeActive)
this.mindMap.off('scale', this.onScale)
},
methods: {
show(node, imgNode) {
this.node = node
this.imgPlacement = node.getStyle('imgPlacement')
this.imgNode = imgNode
this.showImgPlacementToolbar = true
this.$nextTick(() => {
this.updatePos()
})
},
close() {
this.showImgPlacementToolbar = false
this.node = null
this.imgPlacement = ''
this.imgNode = null
this.style.left = 0
this.style.top = 0
},
updatePos() {
if (!this.imgNode) return
const {
width,
height
} = this.$refs.nodeImgPlacementToolbar.getBoundingClientRect()
const { width: imgWidth, x, y } = this.imgNode.rbox()
this.style.left = x + imgWidth / 2 - width / 2 + 'px'
this.style.top = y - height - 5 + 'px'
},
onScale() {
this.updatePos()
},
onNodeActive(node) {
if (node === this.node) {
return
}
this.close()
},
updateImgPlacement(item) {
this.imgPlacement = item
this.node.setStyle('imgPlacement', item)
this.close()
}
}
}
</script>
<style lang="less" scoped>
.nodeImgPlacementToolbar {
position: fixed;
z-index: 2000;
height: 40px;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 8px;
box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
padding: 0 10px;
.imgPlacementItem {
width: 30px;
height: 30px;
margin: 5px;
cursor: pointer;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
&:hover {
background-color: rgb(237, 237, 237);
}
&.icon_top {
transform: rotateZ(90deg);
}
&.icon_bottom {
transform: rotateZ(-90deg);
}
&.icon_right {
transform: rotateZ(180deg);
}
&.selected {
background-color: rgb(237, 237, 237);
}
}
}
</style>

View File

@@ -321,32 +321,6 @@
</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>
@@ -379,7 +353,6 @@ export default {
mousewheelAction: 'zoom',
mousewheelZoomActionReverse: false,
createNewNodeBehavior: 'default',
tagPosition: 'right',
openRealtimeRenderOnNodeTextEdit: true,
alwaysShowExpandBtn: false,
enableAutoEnterTextEditWhenKeydown: true
@@ -474,7 +447,7 @@ export default {
storeConfig({
config: this.data.config
})
if (['tagPosition', 'alwaysShowExpandBtn'].includes(key)) {
if (['alwaysShowExpandBtn'].includes(key)) {
this.mindMap.reRender()
}
},

View File

@@ -497,6 +497,50 @@
></el-slider>
</div>
</div>
<!-- 节点图片布局 -->
<div class="title noTop">{{ $t('style.img') }}</div>
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('style.placement') }}</span>
<el-radio-group
v-model="style.imgPlacement"
size="mini"
@change="update('imgPlacement')"
>
<el-radio-button label="top">{{
$t('style.top')
}}</el-radio-button>
<el-radio-button label="bottom">{{
$t('style.bottom')
}}</el-radio-button>
<el-radio-button label="left">{{
$t('style.left')
}}</el-radio-button>
<el-radio-button label="right">{{
$t('style.right')
}}</el-radio-button>
</el-radio-group>
</div>
</div>
<!-- 节点标签布局 -->
<div class="title noTop">{{ $t('style.tag') }}</div>
<div class="row">
<div class="rowItem">
<span class="name">{{ $t('style.placement') }}</span>
<el-radio-group
v-model="style.tagPlacement"
size="mini"
@change="update('tagPlacement')"
>
<el-radio-button label="right">{{
$t('style.right')
}}</el-radio-button>
<el-radio-button label="bottom">{{
$t('style.bottom')
}}</el-radio-button>
</el-radio-group>
</div>
</div>
</div>
</div>
<div class="tipBox" v-else>
@@ -565,7 +609,9 @@ export default {
lineFlow: false,
lineFlowForward: true,
lineFlowDuration: 1,
textAlign: ''
textAlign: '',
imgPlacement: '',
tagPlacement: ''
}
}
},