Demo:支持调整节点图片和标签布局方式的设置
This commit is contained in:
parent
774609f209
commit
c774bf01ef
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 2479351 */
|
font-family: "iconfont"; /* Project id 2479351 */
|
||||||
src: url('iconfont.woff2?t=1737022296799') format('woff2'),
|
src: url('iconfont.woff2?t=1737722825571') format('woff2'),
|
||||||
url('iconfont.woff?t=1737022296799') format('woff'),
|
url('iconfont.woff?t=1737722825571') format('woff'),
|
||||||
url('iconfont.ttf?t=1737022296799') format('truetype');
|
url('iconfont.ttf?t=1737722825571') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,10 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconcontentleft:before {
|
||||||
|
content: "\e8c9";
|
||||||
|
}
|
||||||
|
|
||||||
.iconjuzhongduiqi:before {
|
.iconjuzhongduiqi:before {
|
||||||
content: "\ec80";
|
content: "\ec80";
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -73,7 +73,6 @@ export default {
|
|||||||
watermarkTextOpacity: 'Text opacity',
|
watermarkTextOpacity: 'Text opacity',
|
||||||
watermarkTextFontSize: 'Font size',
|
watermarkTextFontSize: 'Font size',
|
||||||
belowNode: 'Display below nodes',
|
belowNode: 'Display below nodes',
|
||||||
tagPosition: 'Node tag position',
|
|
||||||
tagPositionRight: 'Text right',
|
tagPositionRight: 'Text right',
|
||||||
tagPositionBottom: 'Text bottom',
|
tagPositionBottom: 'Text bottom',
|
||||||
alwaysShowExpandBtn: 'Always show expand btn',
|
alwaysShowExpandBtn: 'Always show expand btn',
|
||||||
@ -264,7 +263,14 @@ export default {
|
|||||||
openLineFlow: 'Open line flow',
|
openLineFlow: 'Open line flow',
|
||||||
lineFlowDuration: 'Line flow duration',
|
lineFlowDuration: 'Line flow duration',
|
||||||
forward: 'Forward',
|
forward: 'Forward',
|
||||||
reverse: 'Reverse'
|
reverse: 'Reverse',
|
||||||
|
img: 'Image',
|
||||||
|
placement: 'Placement',
|
||||||
|
top: 'Top',
|
||||||
|
bottom: 'Bottom',
|
||||||
|
left: 'Left',
|
||||||
|
right: 'Right',
|
||||||
|
tag: 'Tag',
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
title: 'Theme',
|
title: 'Theme',
|
||||||
|
|||||||
@ -71,7 +71,6 @@ export default {
|
|||||||
watermarkTextOpacity: '文字透明度',
|
watermarkTextOpacity: '文字透明度',
|
||||||
watermarkTextFontSize: '文字字号',
|
watermarkTextFontSize: '文字字号',
|
||||||
belowNode: '显示在节点下方',
|
belowNode: '显示在节点下方',
|
||||||
tagPosition: '节点标签显示的位置',
|
|
||||||
tagPositionRight: '文本右侧',
|
tagPositionRight: '文本右侧',
|
||||||
tagPositionBottom: '文本下面',
|
tagPositionBottom: '文本下面',
|
||||||
alwaysShowExpandBtn: '是否一直显示展开收起按钮',
|
alwaysShowExpandBtn: '是否一直显示展开收起按钮',
|
||||||
@ -260,7 +259,14 @@ export default {
|
|||||||
openLineFlow: '开启流动效果',
|
openLineFlow: '开启流动效果',
|
||||||
lineFlowDuration: '一个流动周期的时间',
|
lineFlowDuration: '一个流动周期的时间',
|
||||||
forward: '正向',
|
forward: '正向',
|
||||||
reverse: '反向'
|
reverse: '反向',
|
||||||
|
img: '图片',
|
||||||
|
placement: '布局',
|
||||||
|
top: '上',
|
||||||
|
bottom: '下',
|
||||||
|
left: '左',
|
||||||
|
right: '右',
|
||||||
|
tag: '标签',
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
title: '主题',
|
title: '主题',
|
||||||
|
|||||||
@ -41,7 +41,6 @@ export default {
|
|||||||
rainbowLines: '彩虹線條',
|
rainbowLines: '彩虹線條',
|
||||||
notUseRainbowLines: '不使用彩虹線條',
|
notUseRainbowLines: '不使用彩虹線條',
|
||||||
outerFramePadding: '外框內距',
|
outerFramePadding: '外框內距',
|
||||||
tagPosition: '節點標簽顯示的位置',
|
|
||||||
tagPositionRight: '文本右側',
|
tagPositionRight: '文本右側',
|
||||||
tagPositionBottom: '文本下面',
|
tagPositionBottom: '文本下面',
|
||||||
alwaysShowExpandBtn: '是否壹直顯示展開收起按鈕',
|
alwaysShowExpandBtn: '是否壹直顯示展開收起按鈕',
|
||||||
@ -260,7 +259,14 @@ export default {
|
|||||||
openLineFlow: '開啓流動效果',
|
openLineFlow: '開啓流動效果',
|
||||||
lineFlowDuration: '一個流動周期的時間',
|
lineFlowDuration: '一個流動周期的時間',
|
||||||
forward: '正向',
|
forward: '正向',
|
||||||
reverse: '反向'
|
reverse: '反向',
|
||||||
|
img: '圖片',
|
||||||
|
placement: '布局',
|
||||||
|
top: '上',
|
||||||
|
bottom: '下',
|
||||||
|
left: '左',
|
||||||
|
right: '右',
|
||||||
|
tag: '標簽',
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
title: '主題',
|
title: '主題',
|
||||||
|
|||||||
@ -43,6 +43,10 @@
|
|||||||
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
|
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
|
||||||
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
|
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
|
||||||
<Setting :data="mindMapData" :mindMap="mindMap"></Setting>
|
<Setting :data="mindMapData" :mindMap="mindMap"></Setting>
|
||||||
|
<NodeImgPlacementToolbar
|
||||||
|
v-if="mindMap"
|
||||||
|
:mindMap="mindMap"
|
||||||
|
></NodeImgPlacementToolbar>
|
||||||
<div
|
<div
|
||||||
class="dragMask"
|
class="dragMask"
|
||||||
v-if="showDragMask"
|
v-if="showDragMask"
|
||||||
@ -127,6 +131,7 @@ import NodeOuterFrame from './NodeOuterFrame.vue'
|
|||||||
import NodeTagStyle from './NodeTagStyle.vue'
|
import NodeTagStyle from './NodeTagStyle.vue'
|
||||||
import Setting from './Setting.vue'
|
import Setting from './Setting.vue'
|
||||||
import AssociativeLineStyle from './AssociativeLineStyle.vue'
|
import AssociativeLineStyle from './AssociativeLineStyle.vue'
|
||||||
|
import NodeImgPlacementToolbar from './NodeImgPlacementToolbar.vue'
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
MindMap.usePlugin(MiniMap)
|
MindMap.usePlugin(MiniMap)
|
||||||
@ -180,7 +185,8 @@ export default {
|
|||||||
NodeOuterFrame,
|
NodeOuterFrame,
|
||||||
NodeTagStyle,
|
NodeTagStyle,
|
||||||
Setting,
|
Setting,
|
||||||
AssociativeLineStyle
|
AssociativeLineStyle,
|
||||||
|
NodeImgPlacementToolbar
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
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>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
</template>
|
</template>
|
||||||
@ -379,7 +353,6 @@ export default {
|
|||||||
mousewheelAction: 'zoom',
|
mousewheelAction: 'zoom',
|
||||||
mousewheelZoomActionReverse: false,
|
mousewheelZoomActionReverse: false,
|
||||||
createNewNodeBehavior: 'default',
|
createNewNodeBehavior: 'default',
|
||||||
tagPosition: 'right',
|
|
||||||
openRealtimeRenderOnNodeTextEdit: true,
|
openRealtimeRenderOnNodeTextEdit: true,
|
||||||
alwaysShowExpandBtn: false,
|
alwaysShowExpandBtn: false,
|
||||||
enableAutoEnterTextEditWhenKeydown: true
|
enableAutoEnterTextEditWhenKeydown: true
|
||||||
@ -474,7 +447,7 @@ export default {
|
|||||||
storeConfig({
|
storeConfig({
|
||||||
config: this.data.config
|
config: this.data.config
|
||||||
})
|
})
|
||||||
if (['tagPosition', 'alwaysShowExpandBtn'].includes(key)) {
|
if (['alwaysShowExpandBtn'].includes(key)) {
|
||||||
this.mindMap.reRender()
|
this.mindMap.reRender()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -497,6 +497,50 @@
|
|||||||
></el-slider>
|
></el-slider>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
<div class="tipBox" v-else>
|
<div class="tipBox" v-else>
|
||||||
@ -565,7 +609,9 @@ export default {
|
|||||||
lineFlow: false,
|
lineFlow: false,
|
||||||
lineFlowForward: true,
|
lineFlowForward: true,
|
||||||
lineFlowDuration: 1,
|
lineFlowDuration: 1,
|
||||||
textAlign: ''
|
textAlign: '',
|
||||||
|
imgPlacement: '',
|
||||||
|
tagPlacement: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user