1.修复删除背景图片不生效的问题;2.背景图片展示增加位置和大小设置;3.修复节点拖拽到根节点时连接线跑到根节点上方的问题

This commit is contained in:
wanglin2 2023-01-31 15:04:38 +08:00
parent c26149fa42
commit f547f741f2
9 changed files with 1388 additions and 1206 deletions

View File

@ -21,8 +21,10 @@ const layouts = {
}
// 渲染
class Render {
// 构造函数
constructor(opt = {}) {
this.opt = opt
this.mindMap = opt.mindMap
@ -49,6 +51,7 @@ class Render {
}
// 设置布局结构
setLayout() {
this.layout = new (
layouts[this.mindMap.opt.layout]
@ -58,6 +61,7 @@ class Render {
}
// 绑定事件
bindEvent() {
// 点击事件
this.mindMap.on('draw_click', () => {
@ -69,6 +73,7 @@ class Render {
}
// 注册命令
registerCommands() {
// 全选
this.selectAll = this.selectAll.bind(this)
@ -170,6 +175,7 @@ class Render {
}
// 注册快捷键
registerShortcutKeys() {
// 插入下级节点
this.mindMap.keyCommand.addShortcut('Tab', () => {
@ -214,6 +220,7 @@ class Render {
}
// 开启文字编辑,会禁用回车键和删除键相关快捷键防止冲突
startTextEdit() {
this.mindMap.keyCommand.save()
// this.mindMap.keyCommand.removeShortcut('Del|Backspace')
@ -222,6 +229,7 @@ class Render {
}
// 结束文字编辑,会恢复回车键和删除键相关快捷键
endTextEdit() {
this.mindMap.keyCommand.restore()
// this.mindMap.keyCommand.addShortcut('Del|Backspace', this.removeNodeWrap)
@ -230,6 +238,7 @@ class Render {
}
// 渲染
render() {
if (this.reRender) {
this.clearActive()
@ -244,6 +253,7 @@ class Render {
}
// 清除当前激活的节点
clearActive() {
this.activeNodeList.forEach(item => {
this.setNodeActive(item, false)
@ -252,6 +262,7 @@ class Render {
}
// 清除当前所有激活节点,并会触发事件
clearAllActive() {
if (this.activeNodeList.length <= 0) {
return
@ -261,6 +272,7 @@ class Render {
}
// 添加节点到激活列表里
addActiveNode(node) {
let index = this.findActiveNodeIndex(node)
if (index === -1) {
@ -269,6 +281,7 @@ class Render {
}
// 在激活列表里移除某个节点
removeActiveNode(node) {
let index = this.findActiveNodeIndex(node)
if (index === -1) {
@ -278,6 +291,7 @@ class Render {
}
// 检索某个节点在激活列表里的索引
findActiveNodeIndex(node) {
return this.activeNodeList.findIndex(item => {
return item === node
@ -285,6 +299,7 @@ class Render {
}
// 获取节点在同级里的索引位置
getNodeIndex(node) {
return node.parent
? node.parent.children.findIndex(item => {
@ -294,6 +309,7 @@ class Render {
}
// 全选
selectAll() {
walk(
this.root,
@ -315,6 +331,7 @@ class Render {
}
// 回退
back(step) {
this.clearAllActive()
let data = this.mindMap.command.back(step)
@ -325,6 +342,7 @@ class Render {
}
// 前进
forward(step) {
this.clearAllActive()
let data = this.mindMap.command.forward(step)
@ -335,6 +353,7 @@ class Render {
}
// 插入同级节点,多个节点只会操作第一个节点
insertNode() {
if (this.activeNodeList.length <= 0) {
return
@ -361,6 +380,7 @@ class Render {
}
// 插入子节点
insertChildNode() {
if (this.activeNodeList.length <= 0) {
return
@ -391,6 +411,7 @@ class Render {
}
// 上移节点,多个节点只会操作第一个节点
upNode() {
if (this.activeNodeList.length <= 0) {
return
@ -418,6 +439,7 @@ class Render {
}
// 下移节点,多个节点只会操作第一个节点
downNode() {
if (this.activeNodeList.length <= 0) {
return
@ -445,6 +467,7 @@ class Render {
}
// 将节点移动到另一个节点的前面
insertBefore(node, exist) {
if (node.isRoot) {
return
@ -476,6 +499,7 @@ class Render {
}
// 将节点移动到另一个节点的后面
insertAfter(node, exist) {
if (node.isRoot) {
return
@ -508,6 +532,7 @@ class Render {
}
// 移除节点
removeNode() {
if (this.activeNodeList.length <= 0) {
return
@ -540,6 +565,7 @@ class Render {
}
// 移除某个指定节点
removeOneNode(node) {
let index = this.getNodeIndex(node)
node.remove()
@ -548,6 +574,7 @@ class Render {
}
// 复制节点,多个节点只会操作第一个节点
copyNode() {
if (this.activeNodeList.length <= 0) {
return
@ -556,6 +583,7 @@ class Render {
}
// 剪切节点,多个节点只会操作第一个节点
cutNode(callback) {
if (this.activeNodeList.length <= 0) {
return
@ -575,6 +603,7 @@ class Render {
}
// 移动一个节点作为另一个节点的子节点
moveNodeTo(node, toNode) {
if (node.isRoot) {
return
@ -585,9 +614,13 @@ class Render {
this.mindMap.emit('node_active', null, this.activeNodeList)
toNode.nodeData.children.push(copyData)
this.mindMap.render()
if (toNode.isRoot) {
toNode.renderNode()
}
}
// 粘贴节点到节点
pasteNode(data) {
if (this.activeNodeList.length <= 0) {
return
@ -599,6 +632,7 @@ class Render {
}
// 设置节点样式
setNodeStyle(node, prop, value, isActive) {
let data = {}
if (isActive) {
@ -621,6 +655,7 @@ class Render {
}
// 设置节点是否激活
setNodeActive(node, active) {
this.setNodeData(node, {
isActive: active
@ -629,6 +664,7 @@ class Render {
}
// 设置节点是否展开
setNodeExpand(node, expand) {
this.setNodeData(node, {
expand
@ -652,6 +688,7 @@ class Render {
}
// 展开所有
expandAllNode() {
walk(
this.renderTree,
@ -670,6 +707,7 @@ class Render {
}
// 收起所有
unexpandAllNode() {
walk(
this.renderTree,
@ -689,6 +727,7 @@ class Render {
}
// 展开到指定层级
expandToLevel(level) {
walk(
this.renderTree,
@ -706,6 +745,7 @@ class Render {
}
// 切换激活节点的展开状态
toggleActiveExpand() {
this.activeNodeList.forEach(node => {
if (node.nodeData.children.length <= 0) {
@ -716,6 +756,7 @@ class Render {
}
// 切换节点展开状态
toggleNodeExpand(node) {
this.mindMap.execCommand(
'SET_NODE_EXPAND',
@ -725,6 +766,7 @@ class Render {
}
// 设置节点文本
setNodeText(node, text) {
this.setNodeDataRender(node, {
text
@ -732,6 +774,7 @@ class Render {
}
// 设置节点图片
setNodeImage(node, { url, title, width, height }) {
this.setNodeDataRender(node, {
image: url,
@ -744,6 +787,7 @@ class Render {
}
// 设置节点图标
setNodeIcon(node, icons) {
this.setNodeDataRender(node, {
icon: icons
@ -751,6 +795,7 @@ class Render {
}
// 设置节点超链接
setNodeHyperlink(node, link, title = '') {
this.setNodeDataRender(node, {
hyperlink: link,
@ -759,6 +804,7 @@ class Render {
}
// 设置节点备注
setNodeNote(node, note) {
this.setNodeDataRender(node, {
note
@ -766,6 +812,7 @@ class Render {
}
// 设置节点标签
setNodeTag(node, tag) {
this.setNodeDataRender(node, {
tag
@ -773,6 +820,7 @@ class Render {
}
// 添加节点概要
addGeneralization(data) {
if (this.activeNodeList.length <= 0) {
return
@ -792,6 +840,7 @@ class Render {
}
// 删除节点概要
removeGeneralization() {
if (this.activeNodeList.length <= 0) {
return
@ -809,6 +858,7 @@ class Render {
}
// 设置节点自定义位置
setNodeCustomPosition(node, left = undefined, top = undefined) {
let nodeList = [node] || this.activeNodeList
nodeList.forEach(item => {
@ -820,6 +870,7 @@ class Render {
}
// 一键整理布局,即去除自定义位置
resetLayout() {
walk(
this.root,
@ -841,6 +892,7 @@ class Render {
}
// 设置节点形状
setNodeShape(node, shape) {
if (!shape || !shapeList.includes(shape)) {
return
@ -852,6 +904,7 @@ class Render {
}
// 更新节点数据
setNodeData(node, data) {
Object.keys(data).forEach(key => {
node.nodeData.data[key] = data[key]
@ -859,6 +912,7 @@ class Render {
}
// 设置节点数据,并判断是否渲染
setNodeDataRender(node, data) {
this.setNodeData(node, data)
let changed = node.getSize()
@ -873,6 +927,7 @@ class Render {
}
// 移动节点到画布中心
moveNodeToCenter(node) {
let halfWidth = this.mindMap.width / 2
let halfHeight = this.mindMap.height / 2

View File

@ -2,29 +2,38 @@ import { tagColorList } from './utils/constant'
const rootProp = ['paddingX', 'paddingY']
// 样式类
class Style {
// 设置背景样式
static setBackgroundStyle(el, themeConfig) {
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig
el.style.backgroundColor = backgroundColor
if (backgroundImage) {
el.style.backgroundImage = `url(${backgroundImage})`
el.style.backgroundRepeat = backgroundRepeat
el.style.backgroundPosition = backgroundPosition
el.style.backgroundSize = backgroundSize
} else {
el.style.backgroundImage = 'none'
}
}
// 构造函数
constructor(ctx, themeConfig) {
this.ctx = ctx
this.themeConfig = themeConfig
}
// 更新主题配置
updateThemeConfig(themeConfig) {
this.themeConfig = themeConfig
}
// 合并样式
merge(prop, root, isActive) {
// 三级及以下节点
let defaultConfig = this.themeConfig.node
@ -59,22 +68,26 @@ class Style {
}
// 获取某个样式值
getStyle(prop, root, isActive) {
return this.merge(prop, root, isActive)
}
// 获取自身自定义样式
getSelfStyle(prop) {
return this.ctx.nodeData.data[prop]
}
// 矩形
rect(node) {
this.shape(node)
node.radius(this.merge('borderRadius'))
}
// 矩形外的其他形状
shape(node) {
node.fill({
color: this.merge('fillColor')
@ -96,6 +109,7 @@ class Style {
}
// 文字
text(node) {
node
.fill({
@ -111,6 +125,7 @@ class Style {
}
// html文字节点
domText(node, fontSizeScale = 1) {
node.style.fontFamily = this.merge('fontFamily')
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
@ -118,6 +133,7 @@ class Style {
}
// 标签文字
tagText(node, index) {
node
.fill({
@ -129,6 +145,7 @@ class Style {
}
// 标签矩形
tagRect(node, index) {
node.fill({
color: tagColorList[index].background
@ -136,6 +153,7 @@ class Style {
}
// 内置图标
iconNode(node) {
node.attr({
fill: this.merge('color')
@ -143,11 +161,13 @@ class Style {
}
// 连线
line(node, { width, color, dasharray } = {}) {
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
}
// 概要连线
generalizationLine(node) {
node
.stroke({
@ -158,6 +178,7 @@ class Style {
}
// 按钮
iconBtn(node, fillNode) {
node.fill({ color: '#808080' })
fillNode.fill({ color: '#fff' })

View File

@ -1,4 +1,5 @@
// 默认主题
export default {
// 节点内边距
paddingX: 15,
@ -31,6 +32,10 @@ export default {
backgroundImage: 'none',
// 背景重复
backgroundRepeat: 'no-repeat',
// 设置背景图像的起始位置
backgroundPosition: 'center center',
// 设置背景图片大小
backgroundSize: 'cover',
// 节点使用横线样式
nodeUseLineStyle: false,
// 根节点样式

View File

@ -166,6 +166,22 @@ export const backgroundPositionList = [
}
]
// 背景图片大小
export const backgroundSizeList = [
{
name: 'Auto',
value: 'auto'
},
{
name: 'Cover',
value: 'cover'
},
{
name: 'Contain',
value: 'contain'
}
]
// 快捷键列表
export const shortcutKeyList = [
{

View File

@ -14,7 +14,8 @@ import {
backgroundPositionList as backgroundPositionListZh,
shortcutKeyList as shortcutKeyListZh,
shapeList as shapeListZh,
sidebarTriggerList as sidebarTriggerListZh
sidebarTriggerList as sidebarTriggerListZh,
backgroundSizeList as backgroundSizeListZh
} from './zh'
import {
fontFamilyList as fontFamilyListEn,
@ -24,7 +25,8 @@ import {
backgroundPositionList as backgroundPositionListEn,
shortcutKeyList as shortcutKeyListEn,
shapeList as shapeListEn,
sidebarTriggerList as sidebarTriggerListEn
sidebarTriggerList as sidebarTriggerListEn,
backgroundSizeList as backgroundSizeListEn
} from './en'
const fontFamilyList = {
@ -52,6 +54,11 @@ const backgroundPositionList = {
en: backgroundPositionListEn
}
const backgroundSizeList = {
zh: backgroundSizeListZh,
en: backgroundSizeListEn
}
const shortcutKeyList = {
zh: shortcutKeyListZh,
en: shortcutKeyListEn
@ -81,6 +88,7 @@ export {
lineStyleList,
backgroundRepeatList,
backgroundPositionList,
backgroundSizeList,
shortcutKeyList,
shapeList,
sidebarTriggerList

View File

@ -221,6 +221,22 @@ export const backgroundPositionList = [
}
]
// 背景图片大小
export const backgroundSizeList = [
{
name: '自动',
value: 'auto'
},
{
name: '覆盖',
value: 'cover'
},
{
name: '保持',
value: 'contain'
}
]
// 数据存储
export const store = {
sidebarZIndex: 1 //侧边栏zIndex

View File

@ -5,6 +5,8 @@ export default {
color: 'Color',
image: 'Image',
imageRepeat: 'Image repeat',
imagePosition: 'Image position',
imageSize: 'Image size',
line: 'Line',
width: 'Width',
style: 'Style',

View File

@ -5,6 +5,8 @@ export default {
color: '颜色',
image: '图片',
imageRepeat: '图片重复',
imagePosition: '图片位置',
imageSize: '图片大小',
line: '连线',
width: '粗细',
style: '风格',

View File

@ -25,6 +25,7 @@
}
"
></ImgUpload>
<!-- 图片重复方式 -->
<div class="rowItem">
<span class="name">{{ $t('baseStyle.imageRepeat') }}</span>
<el-select
@ -47,6 +48,52 @@
</el-option>
</el-select>
</div>
<!-- 图片位置 -->
<div class="rowItem">
<span class="name">{{ $t('baseStyle.imagePosition') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="style.backgroundPosition"
placeholder=""
@change="
value => {
update('backgroundPosition', value)
}
"
>
<el-option
v-for="item in backgroundPositionList"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
</div>
<!-- 图片大小 -->
<div class="rowItem">
<span class="name">{{ $t('baseStyle.imageSize') }}</span>
<el-select
size="mini"
style="width: 120px"
v-model="style.backgroundSize"
placeholder=""
@change="
value => {
update('backgroundSize', value)
}
"
>
<el-option
v-for="item in backgroundSizeList"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
</div>
</el-tab-pane>
</el-tabs>
</div>
@ -389,7 +436,7 @@
<script>
import Sidebar from './Sidebar'
import Color from './Color'
import { lineWidthList, lineStyleList, backgroundRepeatList } from '@/config'
import { lineWidthList, lineStyleList, backgroundRepeatList, backgroundPositionList, backgroundSizeList } from '@/config'
import ImgUpload from '@/components/ImgUpload'
import { storeConfig } from '@/api'
import { mapState } from 'vuex'
@ -434,6 +481,8 @@ export default {
iconSize: 0,
backgroundImage: '',
backgroundRepeat: 'no-repeat',
backgroundPosition: '',
backgroundSize: '',
marginX: 0,
marginY: 0,
nodeUseLineStyle: false
@ -464,7 +513,13 @@ export default {
},
backgroundRepeatList() {
return backgroundRepeatList[this.$i18n.locale] || backgroundRepeatList.zh
}
},
backgroundPositionList() {
return backgroundPositionList[this.$i18n.locale] || backgroundPositionList.zh
},
backgroundSizeList() {
return backgroundSizeList[this.$i18n.locale] || backgroundSizeList.zh
},
},
watch: {
activeSidebar(val) {
@ -499,6 +554,8 @@ export default {
'iconSize',
'backgroundImage',
'backgroundRepeat',
'backgroundPosition',
'backgroundSize',
'nodeUseLineStyle'
].forEach(key => {
this.style[key] = this.mindMap.getThemeConfig(key)