mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 14:04:47 +08:00
Demo:支持调整节点图片和标签布局方式的设置
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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',
|
||||
|
||||
@@ -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: '主题',
|
||||
|
||||
@@ -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: '主題',
|
||||
|
||||
@@ -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 {
|
||||
|
||||
164
web/src/pages/Edit/components/NodeImgPlacementToolbar.vue
Normal file
164
web/src/pages/Edit/components/NodeImgPlacementToolbar.vue
Normal 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>
|
||||
@@ -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()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user