完成导出功能
This commit is contained in:
parent
7a977d74dc
commit
df60f103cc
@ -1,16 +1,16 @@
|
|||||||
const createFullData = () => {
|
const createFullData = () => {
|
||||||
return {
|
return {
|
||||||
// "image": "http://aliyuncdn.lxqnsys.com/whbm/enJFNMHnedQTYTESGfDkctCp2",
|
"image": "http://192.168.3.118:8080/enJFNMHnedQTYTESGfDkctCp2.jpeg",
|
||||||
// "imageTitle": "图片名称",
|
"imageTitle": "图片名称",
|
||||||
// "imageSize": {
|
"imageSize": {
|
||||||
// "width": 1000,
|
"width": 1000,
|
||||||
// "height": 563
|
"height": 563
|
||||||
// },
|
},
|
||||||
// "icon": ['priority_1'],
|
"icon": ['priority_1'],
|
||||||
// "tag": ["标签1", "标签2"],
|
"tag": ["标签1", "标签2"],
|
||||||
// "hyperlink": "http://lxqnsys.com/",
|
"hyperlink": "http://lxqnsys.com/",
|
||||||
// "hyperlinkTitle": "理想青年实验室",
|
"hyperlinkTitle": "理想青年实验室",
|
||||||
// "note": "理想青年实验室\n一个有意思的角落"
|
"note": "理想青年实验室\n一个有意思的角落"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ const createFullData = () => {
|
|||||||
export default {
|
export default {
|
||||||
"root": {
|
"root": {
|
||||||
"data": {
|
"data": {
|
||||||
"text": "根节点",
|
"text": "根节点"
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
@ -38,7 +38,6 @@ export default {
|
|||||||
}, {
|
}, {
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点1-2",
|
"text": "子节点1-2",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},]
|
},]
|
||||||
},
|
},
|
||||||
@ -56,31 +55,26 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-1",
|
"text": "子节点2-1-1",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-2",
|
"text": "子节点2-1-2",
|
||||||
...createFullData()
|
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-2-1",
|
"text": "子节点2-1-2-1",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-2-2",
|
"text": "子节点2-1-2-2",
|
||||||
...createFullData()
|
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-2-2-1",
|
"text": "子节点2-1-2-2-1",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -92,7 +86,6 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-2-2-3",
|
"text": "子节点2-1-2-2-3",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -108,7 +101,6 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-1-3",
|
"text": "子节点2-1-3",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -116,7 +108,6 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点2-2",
|
"text": "子节点2-2",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -129,7 +120,6 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点3-1",
|
"text": "子节点3-1",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -148,19 +138,16 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点4-1",
|
"text": "子节点4-1",
|
||||||
...createFullData()
|
|
||||||
},
|
},
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点4-1-1",
|
"text": "子节点4-1-1",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点4-1-2",
|
"text": "子节点4-1-2",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -174,7 +161,6 @@ export default {
|
|||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"text": "子节点4-2",
|
"text": "子节点4-2",
|
||||||
...createFullData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -7,11 +7,12 @@ import Style from './src/Style'
|
|||||||
import KeyCommand from './src/KeyCommand'
|
import KeyCommand from './src/KeyCommand'
|
||||||
import Command from './src/Command'
|
import Command from './src/Command'
|
||||||
import BatchExecution from './src/BatchExecution'
|
import BatchExecution from './src/BatchExecution'
|
||||||
|
import Export from './src/Export';
|
||||||
import {
|
import {
|
||||||
SVG
|
SVG
|
||||||
} from '@svgdotjs/svg.js'
|
} from '@svgdotjs/svg.js'
|
||||||
|
|
||||||
// 默认选项
|
// 默认选项配置
|
||||||
const defaultOpt = {
|
const defaultOpt = {
|
||||||
// 布局
|
// 布局
|
||||||
layout: 'logicalStructure',
|
layout: 'logicalStructure',
|
||||||
@ -19,8 +20,12 @@ const defaultOpt = {
|
|||||||
theme: 'default', // 内置主题:default(默认主题)
|
theme: 'default', // 内置主题:default(默认主题)
|
||||||
// 主题配置,会和所选择的主题进行合并
|
// 主题配置,会和所选择的主题进行合并
|
||||||
themeConfig: {},
|
themeConfig: {},
|
||||||
// 放大缩小的增量比例,即step = scaleRatio * width|height
|
// 放大缩小的增量比例
|
||||||
scaleRatio: 0.1
|
scaleRatio: 0.1,
|
||||||
|
// 设置鼠标左键还是右键按下拖动,1(左键)、2(右键)
|
||||||
|
dragButton: 1,
|
||||||
|
// 最多显示几个标签
|
||||||
|
maxTag: 5
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +43,7 @@ class MindMap {
|
|||||||
*/
|
*/
|
||||||
constructor(opt = {}) {
|
constructor(opt = {}) {
|
||||||
// 合并选项
|
// 合并选项
|
||||||
this.opt = merge(defaultOpt, opt)
|
this.opt = this.handleOpt(merge(defaultOpt, opt))
|
||||||
|
|
||||||
// 容器元素
|
// 容器元素
|
||||||
this.el = this.opt.el
|
this.el = this.opt.el
|
||||||
@ -51,8 +56,9 @@ class MindMap {
|
|||||||
this.width = width
|
this.width = width
|
||||||
this.height = height
|
this.height = height
|
||||||
|
|
||||||
// 画笔
|
// 画布
|
||||||
this.draw = SVG().addTo(this.el).size(width, height)
|
this.svg = SVG().addTo(this.el).size(width, height)
|
||||||
|
this.draw = this.svg.group()
|
||||||
|
|
||||||
// 节点id
|
// 节点id
|
||||||
this.uid = 0
|
this.uid = 0
|
||||||
@ -86,6 +92,11 @@ class MindMap {
|
|||||||
draw: this.draw
|
draw: this.draw
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 导出类
|
||||||
|
this.doExport = new Export({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
// 批量执行类
|
// 批量执行类
|
||||||
this.batchExecution = new BatchExecution()
|
this.batchExecution = new BatchExecution()
|
||||||
|
|
||||||
@ -96,6 +107,23 @@ class MindMap {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:15:22
|
||||||
|
* @Desc: 配置参数处理
|
||||||
|
*/
|
||||||
|
handleOpt(opt) {
|
||||||
|
// 检查布局配置
|
||||||
|
if (!['logicalStructure'].includes(opt.layout)) {
|
||||||
|
opt.layout = 'logicalStructure'
|
||||||
|
}
|
||||||
|
// 检查主题配置
|
||||||
|
opt.theme = opt.theme && theme[opt.theme] ? opt.theme : 'default'
|
||||||
|
// 检查鼠标键值
|
||||||
|
opt.dragButton = [1, 3].includes(opt.dragButton) ? opt.dragButton : 1
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* javascript comment
|
* javascript comment
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
@ -144,7 +172,7 @@ class MindMap {
|
|||||||
*/
|
*/
|
||||||
initTheme() {
|
initTheme() {
|
||||||
// 合并主题配置
|
// 合并主题配置
|
||||||
this.themeConfig = merge(this.opt.theme && theme[this.opt.theme] ? theme[this.opt.theme] : theme.default, this.opt.themeConfig)
|
this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig)
|
||||||
// 设置背景样式
|
// 设置背景样式
|
||||||
Style.setBackgroundStyle(this.el, this.themeConfig)
|
Style.setBackgroundStyle(this.el, this.themeConfig)
|
||||||
}
|
}
|
||||||
@ -195,6 +223,16 @@ class MindMap {
|
|||||||
execCommand(...args) {
|
execCommand(...args) {
|
||||||
this.command.exec(...args)
|
this.command.exec(...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:06:38
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
async export(...args) {
|
||||||
|
let result = await this.doExport.export(...args)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MindMap
|
export default MindMap
|
||||||
@ -5,6 +5,7 @@
|
|||||||
"scripts": {},
|
"scripts": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@svgdotjs/svg.js": "^3.0.16",
|
"@svgdotjs/svg.js": "^3.0.16",
|
||||||
|
"canvg": "^3.0.7",
|
||||||
"deepmerge": "^1.5.2",
|
"deepmerge": "^1.5.2",
|
||||||
"eventemitter3": "^4.0.7"
|
"eventemitter3": "^4.0.7"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,11 +55,16 @@ class Event extends EventEmitter {
|
|||||||
* @Desc: 绑定事件
|
* @Desc: 绑定事件
|
||||||
*/
|
*/
|
||||||
bind() {
|
bind() {
|
||||||
this.mindMap.draw.on('click', this.onDrawClick)
|
this.mindMap.svg.on('click', this.onDrawClick)
|
||||||
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
|
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
|
||||||
window.addEventListener('mousemove', this.onMousemove)
|
window.addEventListener('mousemove', this.onMousemove)
|
||||||
window.addEventListener('mouseup', this.onMouseup)
|
window.addEventListener('mouseup', this.onMouseup)
|
||||||
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
// 兼容火狐浏览器
|
||||||
|
if(window.navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
|
||||||
|
this.mindMap.el.addEventListener('DOMMouseScroll', this.onMousewheel)
|
||||||
|
} else {
|
||||||
|
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,6 +96,9 @@ class Event extends EventEmitter {
|
|||||||
* @Desc: 鼠标按下事件
|
* @Desc: 鼠标按下事件
|
||||||
*/
|
*/
|
||||||
onMousedown(e) {
|
onMousedown(e) {
|
||||||
|
if (e.which !== this.mindMap.opt.dragButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.isMousedown = true
|
this.isMousedown = true
|
||||||
this.mousedownPos.x = e.clientX
|
this.mousedownPos.x = e.clientX
|
||||||
@ -137,7 +145,7 @@ class Event extends EventEmitter {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
let dir
|
let dir
|
||||||
if (e.wheelDeltaY > 0) {
|
if ((e.wheelDeltaY || e.detail) > 0) {
|
||||||
dir = 'up'
|
dir = 'up'
|
||||||
} else {
|
} else {
|
||||||
dir = 'down'
|
dir = 'down'
|
||||||
|
|||||||
203
simple-mind-map/src/Export.js
Normal file
203
simple-mind-map/src/Export.js
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import { imgToDataUrl, downloadFile } from './utils';
|
||||||
|
const URL = window.URL || window.webkitURL || window
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:05:16
|
||||||
|
* @Desc: 导出类
|
||||||
|
*/
|
||||||
|
class Export {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:05:42
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt) {
|
||||||
|
this.mindMap = opt.mindMap
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-02 07:44:06
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
async export(type, isDownload = true) {
|
||||||
|
if (this[type]) {
|
||||||
|
let result = await this[type]()
|
||||||
|
if (isDownload) {
|
||||||
|
downloadFile(result, '思维导图.' + type)
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 14:57:40
|
||||||
|
* @Desc: 获取svg数据
|
||||||
|
*/
|
||||||
|
async getSvgData() {
|
||||||
|
const svg = this.mindMap.svg
|
||||||
|
const draw = this.mindMap.draw
|
||||||
|
// 保存原始信息
|
||||||
|
const origWidth = svg.width()
|
||||||
|
const origHeight = svg.height()
|
||||||
|
const origTransform = draw.transform()
|
||||||
|
// 去除变换效果
|
||||||
|
draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY).translate(0, 0)
|
||||||
|
// 获取实际内容当前变换后的位置信息
|
||||||
|
const rect = draw.rbox()
|
||||||
|
// 将svg设置为实际内容的宽高
|
||||||
|
svg.size(rect.wdith, rect.height)
|
||||||
|
// 把实际内容变换
|
||||||
|
draw.translate(-rect.x, -rect.y)
|
||||||
|
// 克隆一份数据
|
||||||
|
const clone = svg.clone()
|
||||||
|
// 恢复原先的大小和变换信息
|
||||||
|
svg.size(origWidth, origHeight)
|
||||||
|
draw.transform(origTransform)
|
||||||
|
// 把图片的url转换成data:url类型,否则导出会丢失图片
|
||||||
|
let imageList = clone.find('image')
|
||||||
|
let task = imageList.map(async (item) => {
|
||||||
|
let imgUlr = item.attr('href') || item.attr('xlink:href')
|
||||||
|
let imgData = await imgToDataUrl(imgUlr)
|
||||||
|
item.attr('href', imgData)
|
||||||
|
})
|
||||||
|
await Promise.all(task)
|
||||||
|
return {
|
||||||
|
node: clone,
|
||||||
|
str: clone.svg()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:25:19
|
||||||
|
* @Desc: svg转png
|
||||||
|
*/
|
||||||
|
svgToPng(svgSrc) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||||
|
img.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
img.onload = async () => {
|
||||||
|
try {
|
||||||
|
let canvas = document.createElement('canvas')
|
||||||
|
canvas.width = img.width
|
||||||
|
canvas.height = img.height
|
||||||
|
let ctx = canvas.getContext('2d')
|
||||||
|
// 绘制背景
|
||||||
|
await this.drawBackgroundToCanvas(ctx, img.width, img.height)
|
||||||
|
// 图片绘制到canvas里
|
||||||
|
ctx.drawImage(img, 0, 0, img.width, img.height)
|
||||||
|
resolve(canvas.toDataURL())
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.onerror = (e) => {
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
img.src = svgSrc
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:32:07
|
||||||
|
* @Desc: 在canvas上绘制思维导图背景
|
||||||
|
*/
|
||||||
|
drawBackgroundToCanvas(ctx, width, height) {
|
||||||
|
return new Promise((resolve, rejct) => {
|
||||||
|
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig
|
||||||
|
// 背景颜色
|
||||||
|
ctx.save()
|
||||||
|
ctx.rect(0, 0, width, height)
|
||||||
|
ctx.fillStyle = backgroundColor
|
||||||
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
// 背景图片
|
||||||
|
if (backgroundImage && backgroundImage !== 'none') {
|
||||||
|
ctx.save()
|
||||||
|
let img = new Image()
|
||||||
|
img.src = backgroundImage
|
||||||
|
img.onload = () => {
|
||||||
|
let pat = ctx.createPattern(img, backgroundRepeat)
|
||||||
|
ctx.rect(0, 0, width, height)
|
||||||
|
ctx.fillStyle = pat
|
||||||
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
img.onerror = (e) => {
|
||||||
|
rejct(e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:09:51
|
||||||
|
* @Desc: 导出为png
|
||||||
|
* 方法1.把svg的图片都转化成data:url格式,再转换
|
||||||
|
* 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
|
||||||
|
*/
|
||||||
|
async png() {
|
||||||
|
let { str } = await this.getSvgData()
|
||||||
|
// 转换成blob数据
|
||||||
|
let blob = new Blob([str], {
|
||||||
|
type: 'image/svg+xml'
|
||||||
|
});
|
||||||
|
// 转换成data:url数据
|
||||||
|
let svgUrl = URL.createObjectURL(blob);
|
||||||
|
// 绘制到canvas上
|
||||||
|
let imgDataUrl = await this.svgToPng(svgUrl)
|
||||||
|
URL.revokeObjectURL(svgUrl);
|
||||||
|
return imgDataUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:32:07
|
||||||
|
* @Desc: 在svg上绘制思维导图背景
|
||||||
|
*/
|
||||||
|
drawBackgroundToSvg(svg) {
|
||||||
|
return new Promise(async (resolve, rejct) => {
|
||||||
|
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig
|
||||||
|
// 背景颜色
|
||||||
|
svg.css('background-color', backgroundColor)
|
||||||
|
// 背景图片
|
||||||
|
if (backgroundImage && backgroundImage !== 'none') {
|
||||||
|
let imgDataUrl = await imgToDataUrl(backgroundImage)
|
||||||
|
svg.css('background-image', `url(${imgDataUrl})`)
|
||||||
|
svg.css('background-repeat', backgroundRepeat)
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 14:54:07
|
||||||
|
* @Desc: 导出为svg
|
||||||
|
*/
|
||||||
|
async svg() {
|
||||||
|
let { node } = await this.getSvgData()
|
||||||
|
await this.drawBackgroundToSvg(node)
|
||||||
|
let str = node.svg()
|
||||||
|
// 转换成blob数据
|
||||||
|
let blob = new Blob([str], {
|
||||||
|
type: 'image/svg+xml'
|
||||||
|
});
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Export
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import Style from './Style'
|
import Style from './Style'
|
||||||
import {
|
import {
|
||||||
resizeImgSize,
|
resizeImgSize,
|
||||||
copyRenderTree
|
copyRenderTree,
|
||||||
|
imgToDataUrl
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import {
|
import {
|
||||||
Image,
|
Image,
|
||||||
@ -215,11 +216,12 @@ class Node {
|
|||||||
if (!_data.icon || _data.icon.length <= 0) {
|
if (!_data.icon || _data.icon.length <= 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
let iconSize = this.themeConfig.iconSize
|
||||||
return _data.icon.map((item) => {
|
return _data.icon.map((item) => {
|
||||||
return {
|
return {
|
||||||
node: SVG(iconsSvg.getNodeIconListIcon(item)).size(this.themeConfig.iconSize, this.themeConfig.iconSize),
|
node: SVG(iconsSvg.getNodeIconListIcon(item)).size(iconSize, iconSize),
|
||||||
width: this.themeConfig.iconSize,
|
width: iconSize,
|
||||||
height: this.themeConfig.iconSize
|
height: iconSize
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -231,10 +233,7 @@ class Node {
|
|||||||
* @Desc: 创建文本节点
|
* @Desc: 创建文本节点
|
||||||
*/
|
*/
|
||||||
createTextNode() {
|
createTextNode() {
|
||||||
if (!this.nodeData.data.text) {
|
let node = this.draw.text(this.nodeData.data.text || '')
|
||||||
return
|
|
||||||
}
|
|
||||||
let node = this.draw.text(this.nodeData.data.text)
|
|
||||||
this.style.text(node)
|
this.style.text(node)
|
||||||
let {
|
let {
|
||||||
width,
|
width,
|
||||||
@ -255,22 +254,24 @@ class Node {
|
|||||||
* @Desc: 创建超链接节点
|
* @Desc: 创建超链接节点
|
||||||
*/
|
*/
|
||||||
createHyperlinkNode() {
|
createHyperlinkNode() {
|
||||||
if (!this.nodeData.data.hyperlink) {
|
let { hyperlink, hyperlinkTitle } = this.nodeData.data
|
||||||
|
if (!hyperlink) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let iconSize = this.themeConfig.iconSize
|
let iconSize = this.themeConfig.iconSize
|
||||||
let node = this.draw.element('a')
|
let node = this.draw.link(hyperlink).target('_blank')
|
||||||
node.node.addEventListener('click', (e) => {
|
node.node.addEventListener('click', (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
node.attr('href', this.nodeData.data.hyperlink).attr('target', '_blank')
|
if (hyperlinkTitle) {
|
||||||
if (this.nodeData.data.hyperlinkTitle) {
|
node.attr('title', hyperlinkTitle)
|
||||||
node.attr('title', this.nodeData.data.hyperlinkTitle)
|
|
||||||
}
|
}
|
||||||
node.add(this.draw.rect(iconSize, iconSize).fill({ color: 'transparent' }))
|
node.rect(iconSize, iconSize).fill({ color: 'transparent' })
|
||||||
node.add(SVG(iconsSvg.hyperlink).size(iconSize, iconSize))
|
let iconNode = SVG(iconsSvg.hyperlink).size(iconSize, iconSize)
|
||||||
|
this.style.iconNode(iconNode)
|
||||||
|
node.add(iconNode)
|
||||||
return {
|
return {
|
||||||
node: this.draw.nested().add(node),
|
node: node,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
height: iconSize
|
height: iconSize
|
||||||
}
|
}
|
||||||
@ -282,12 +283,13 @@ class Node {
|
|||||||
* @Desc: 创建标签节点
|
* @Desc: 创建标签节点
|
||||||
*/
|
*/
|
||||||
createTagNode() {
|
createTagNode() {
|
||||||
if (!this.nodeData.data.tag || this.nodeData.data.tag.length <= 0) {
|
let tagData = this.nodeData.data.tag
|
||||||
|
if (!tagData || tagData.length <= 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
let nodes = []
|
let nodes = []
|
||||||
this.nodeData.data.tag.slice(0, 5).forEach((item, index) => {
|
tagData.slice(0, this.mindMap.opt.maxTag).forEach((item, index) => {
|
||||||
let tag = this.draw.nested()
|
let tag = this.draw.group()
|
||||||
let text = this.draw.text(item).x(8).cy(10)
|
let text = this.draw.text(item).x(8).cy(10)
|
||||||
this.style.tagText(text, index)
|
this.style.tagText(text, index)
|
||||||
let {
|
let {
|
||||||
@ -317,10 +319,12 @@ class Node {
|
|||||||
if (!this.nodeData.data.note) {
|
if (!this.nodeData.data.note) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let node = this.draw.nested().attr('cursor', 'pointer')
|
let node = this.draw.group().attr('cursor', 'pointer')
|
||||||
let iconSize = this.themeConfig.iconSize
|
let iconSize = this.themeConfig.iconSize
|
||||||
node.add(this.draw.rect(iconSize, iconSize).fill({ color: 'transparent' }))
|
node.add(this.draw.rect(iconSize, iconSize).fill({ color: 'transparent' }))
|
||||||
node.add(SVG(iconsSvg.note).size(iconSize, iconSize))
|
let iconNode = SVG(iconsSvg.note).size(iconSize, iconSize)
|
||||||
|
this.style.iconNode(iconNode)
|
||||||
|
node.add(iconNode)
|
||||||
let el = document.createElement('div')
|
let el = document.createElement('div')
|
||||||
el.style.cssText = `
|
el.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -377,11 +381,11 @@ class Node {
|
|||||||
imgObj.node.cx(left + width / 2).y(top + paddingY)
|
imgObj.node.cx(left + width / 2).y(top + paddingY)
|
||||||
}
|
}
|
||||||
// 内容节点
|
// 内容节点
|
||||||
let textContentNested = this.draw.nested()
|
let textContentNested = this.draw.group()
|
||||||
let textContentOffsetX = 0
|
let textContentOffsetX = 0
|
||||||
// icon
|
// icon
|
||||||
let iconObjs = this.createIconNode()
|
let iconObjs = this.createIconNode()
|
||||||
let iconNested = this.draw.nested()
|
let iconNested = this.draw.group()
|
||||||
if (iconObjs && iconObjs.length > 0) {
|
if (iconObjs && iconObjs.length > 0) {
|
||||||
let iconLeft = 0
|
let iconLeft = 0
|
||||||
iconObjs.forEach((item) => {
|
iconObjs.forEach((item) => {
|
||||||
@ -403,13 +407,13 @@ class Node {
|
|||||||
// 超链接
|
// 超链接
|
||||||
let hyperlinkObj = this.createHyperlinkNode()
|
let hyperlinkObj = this.createHyperlinkNode()
|
||||||
if (hyperlinkObj) {
|
if (hyperlinkObj) {
|
||||||
hyperlinkObj.node.x(textContentOffsetX).y((_textContentHeight - hyperlinkObj.height) / 2)
|
hyperlinkObj.node.translate(textContentOffsetX, (_textContentHeight - hyperlinkObj.height) / 2)
|
||||||
textContentNested.add(hyperlinkObj.node)
|
textContentNested.add(hyperlinkObj.node)
|
||||||
textContentOffsetX += hyperlinkObj.width + _textContentItemMargin
|
textContentOffsetX += hyperlinkObj.width + _textContentItemMargin
|
||||||
}
|
}
|
||||||
// 标签
|
// 标签
|
||||||
let tagObjs = this.createTagNode()
|
let tagObjs = this.createTagNode()
|
||||||
let tagNested = this.draw.nested()
|
let tagNested = this.draw.group()
|
||||||
if (tagObjs && tagObjs.length > 0) {
|
if (tagObjs && tagObjs.length > 0) {
|
||||||
let tagLeft = 0
|
let tagLeft = 0
|
||||||
tagObjs.forEach((item) => {
|
tagObjs.forEach((item) => {
|
||||||
@ -423,12 +427,15 @@ class Node {
|
|||||||
// 备注
|
// 备注
|
||||||
let noteObj = this.createNoteNode()
|
let noteObj = this.createNoteNode()
|
||||||
if (noteObj) {
|
if (noteObj) {
|
||||||
noteObj.node.x(textContentOffsetX).y((_textContentHeight - noteObj.height) / 2)
|
noteObj.node.translate(textContentOffsetX, (_textContentHeight - noteObj.height) / 2)
|
||||||
textContentNested.add(noteObj.node)
|
textContentNested.add(noteObj.node)
|
||||||
textContentOffsetX += noteObj.width
|
textContentOffsetX += noteObj.width
|
||||||
}
|
}
|
||||||
// 文字内容整体
|
// 文字内容整体
|
||||||
textContentNested.x(left + width / 2).dx(-textContentNested.bbox().width / 2).y(top + imgHeight + paddingY + (imgHeight > 0 && _textContentHeight > 0 ? this._blockContentMargin : 0))
|
textContentNested.translate(
|
||||||
|
left + width / 2 - textContentNested.bbox().width / 2,
|
||||||
|
top + imgHeight + paddingY + (imgHeight > 0 && _textContentHeight > 0 ? this._blockContentMargin : 0)
|
||||||
|
)
|
||||||
group.add(textContentNested)
|
group.add(textContentNested)
|
||||||
// 单击事件
|
// 单击事件
|
||||||
group.click((e) => {
|
group.click((e) => {
|
||||||
|
|||||||
@ -13,13 +13,11 @@ class Style {
|
|||||||
* @Desc: 设置背景样式
|
* @Desc: 设置背景样式
|
||||||
*/
|
*/
|
||||||
static setBackgroundStyle(el, themeConfig) {
|
static setBackgroundStyle(el, themeConfig) {
|
||||||
let { backgroundColor, backgroundImage, backgroundRepeat, backgroundSize, backgroundPosition } = themeConfig
|
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
|
||||||
el.style.backgroundColor = backgroundColor
|
el.style.backgroundColor = backgroundColor
|
||||||
if (backgroundImage) {
|
if (backgroundImage) {
|
||||||
el.style.backgroundImage = `url(${backgroundImage})`
|
el.style.backgroundImage = `url(${backgroundImage})`
|
||||||
el.style.backgroundRepeat = backgroundRepeat
|
el.style.backgroundRepeat = backgroundRepeat
|
||||||
el.style.backgroundSize = backgroundSize
|
|
||||||
el.style.backgroundPosition = backgroundPosition
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +125,17 @@ class Style {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-03 22:37:19
|
||||||
|
* @Desc: 内置图标
|
||||||
|
*/
|
||||||
|
iconNode(node) {
|
||||||
|
node.attr({
|
||||||
|
fill: this.merge('color')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-11 14:50:49
|
* @Date: 2021-04-11 14:50:49
|
||||||
|
|||||||
@ -59,9 +59,6 @@ export default class TextEdit {
|
|||||||
* @Desc: 显示文本编辑框
|
* @Desc: 显示文本编辑框
|
||||||
*/
|
*/
|
||||||
show(node) {
|
show(node) {
|
||||||
if (!node.nodeData.data.text) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showEditTextBox(node, node.textNode.node.node.getBoundingClientRect())
|
this.showEditTextBox(node, node.textNode.node.node.getBoundingClientRect())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +95,9 @@ export default class TextEdit {
|
|||||||
}
|
}
|
||||||
this.renderer.activeNodeList.forEach((node) => {
|
this.renderer.activeNodeList.forEach((node) => {
|
||||||
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
||||||
node.nodeData.data.text = str
|
this.mindMap.execCommand('UPDATE_NODE_DATA', node, {
|
||||||
console.log(8)
|
text: str
|
||||||
|
})
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
})
|
})
|
||||||
this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList)
|
this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList)
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import merge from 'deepmerge'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* javascript comment
|
* javascript comment
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
@ -16,19 +14,11 @@ class View {
|
|||||||
constructor(opt = {}) {
|
constructor(opt = {}) {
|
||||||
this.opt = opt
|
this.opt = opt
|
||||||
this.mindMap = this.opt.mindMap
|
this.mindMap = this.opt.mindMap
|
||||||
this.viewBox = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: this.mindMap.width,
|
|
||||||
height: this.mindMap.height
|
|
||||||
}
|
|
||||||
this.cacheViewBox = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: this.mindMap.width,
|
|
||||||
height: this.mindMap.height
|
|
||||||
}
|
|
||||||
this.scale = 1
|
this.scale = 1
|
||||||
|
this.sx = 0
|
||||||
|
this.sy = 0
|
||||||
|
this.x = 0
|
||||||
|
this.y = 0
|
||||||
this.bind()
|
this.bind()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,29 +31,35 @@ class View {
|
|||||||
bind() {
|
bind() {
|
||||||
// 拖动视图
|
// 拖动视图
|
||||||
this.mindMap.event.on('mousedown', () => {
|
this.mindMap.event.on('mousedown', () => {
|
||||||
this.cacheViewBox = merge({}, this.viewBox)
|
this.sx = this.x
|
||||||
|
this.sy = this.y
|
||||||
})
|
})
|
||||||
this.mindMap.event.on('drag', (e, event) => {
|
this.mindMap.event.on('drag', (e, event) => {
|
||||||
// 视图放大缩小后拖动的距离也要相应变化
|
this.x = this.sx + event.mousemoveOffset.x
|
||||||
this.viewBox.x = this.cacheViewBox.x - event.mousemoveOffset.x * this.scale
|
this.y = this.sy + event.mousemoveOffset.y
|
||||||
this.viewBox.y = this.cacheViewBox.y - event.mousemoveOffset.y * this.scale
|
this.mindMap.draw.transform({
|
||||||
this.setViewBox()
|
scale: this.scale,
|
||||||
|
origin: 'left center',
|
||||||
|
translate: [this.x, this.y],
|
||||||
|
})
|
||||||
})
|
})
|
||||||
// 放大缩小视图
|
// 放大缩小视图
|
||||||
this.mindMap.event.on('mousewheel', (e, dir) => {
|
this.mindMap.event.on('mousewheel', (e, dir) => {
|
||||||
let stepWidth = this.viewBox.width * this.mindMap.opt.scaleRatio
|
// // 放大
|
||||||
let stepHeight = this.viewBox.height * this.mindMap.opt.scaleRatio
|
|
||||||
// 放大
|
|
||||||
if (dir === 'down') {
|
if (dir === 'down') {
|
||||||
this.scale += this.mindMap.opt.scaleRatio
|
this.scale += this.mindMap.opt.scaleRatio
|
||||||
this.viewBox.width += stepWidth
|
|
||||||
this.viewBox.height += stepHeight
|
|
||||||
} else { // 缩小
|
} else { // 缩小
|
||||||
this.scale -= this.mindMap.opt.scaleRatio
|
if (this.scale - this.mindMap.opt.scaleRatio > 0.1) {
|
||||||
this.viewBox.width -= stepWidth
|
this.scale -= this.mindMap.opt.scaleRatio
|
||||||
this.viewBox.height -= stepHeight
|
} else {
|
||||||
|
this.scale = 0.1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.setViewBox()
|
this.mindMap.draw.transform({
|
||||||
|
scale: this.scale,
|
||||||
|
origin: 'left center',
|
||||||
|
translate: [this.x, this.y],
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,13 +69,10 @@ class View {
|
|||||||
* @Date: 2021-04-07 15:43:26
|
* @Date: 2021-04-07 15:43:26
|
||||||
* @Desc: 设置视图
|
* @Desc: 设置视图
|
||||||
*/
|
*/
|
||||||
setViewBox() {
|
setViewBox({ x,
|
||||||
let {
|
y,
|
||||||
x,
|
width,
|
||||||
y,
|
height }) {
|
||||||
width,
|
|
||||||
height
|
|
||||||
} = this.viewBox
|
|
||||||
this.opt.draw.viewbox(x, y, width, height)
|
this.opt.draw.viewbox(x, y, width, height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,6 @@ class Base {
|
|||||||
this.mindMap = renderer.mindMap
|
this.mindMap = renderer.mindMap
|
||||||
// 渲染树
|
// 渲染树
|
||||||
this.renderTree = renderer.renderTree
|
this.renderTree = renderer.renderTree
|
||||||
// 主题配置
|
|
||||||
this.themeConfig = this.mindMap.themeConfig
|
|
||||||
// 绘图对象
|
// 绘图对象
|
||||||
this.draw = this.mindMap.draw
|
this.draw = this.mindMap.draw
|
||||||
// 根节点
|
// 根节点
|
||||||
@ -97,7 +95,7 @@ class Base {
|
|||||||
* @Desc: 获取节点的marginX
|
* @Desc: 获取节点的marginX
|
||||||
*/
|
*/
|
||||||
getMarginX(layerIndex) {
|
getMarginX(layerIndex) {
|
||||||
return layerIndex === 1 ? this.themeConfig.second.marginX : this.themeConfig.node.marginX;
|
return layerIndex === 1 ? this.mindMap.themeConfig.second.marginX : this.mindMap.themeConfig.node.marginX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +104,7 @@ class Base {
|
|||||||
* @Desc: 获取节点的marginY
|
* @Desc: 获取节点的marginY
|
||||||
*/
|
*/
|
||||||
getMarginY(layerIndex) {
|
getMarginY(layerIndex) {
|
||||||
return layerIndex === 1 ? this.themeConfig.second.marginY : this.themeConfig.node.marginY;
|
return layerIndex === 1 ? this.mindMap.themeConfig.second.marginY : this.mindMap.themeConfig.node.marginY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class LogicalStructure extends Base {
|
|||||||
this.root = newNode
|
this.root = newNode
|
||||||
} else {
|
} else {
|
||||||
// 非根节点
|
// 非根节点
|
||||||
let marginX = layerIndex === 1 ? this.themeConfig.second.marginX : this.themeConfig.node.marginX
|
let marginX = layerIndex === 1 ? this.mindMap.themeConfig.second.marginX : this.mindMap.themeConfig.node.marginX
|
||||||
// 定位到父节点右侧
|
// 定位到父节点右侧
|
||||||
newNode.left = parent._node.left + parent._node.width + marginX
|
newNode.left = parent._node.left + parent._node.width + marginX
|
||||||
// 互相收集
|
// 互相收集
|
||||||
|
|||||||
@ -23,10 +23,6 @@ export default {
|
|||||||
backgroundImage: 'none',
|
backgroundImage: 'none',
|
||||||
// 背景重复
|
// 背景重复
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
// 背景图像大小
|
|
||||||
backgroundSize: 'auto',
|
|
||||||
// 背景图像定位
|
|
||||||
backgroundPosition: '0% 0%',
|
|
||||||
// 根节点样式
|
// 根节点样式
|
||||||
root: {
|
root: {
|
||||||
fillColor: '#549688',
|
fillColor: '#549688',
|
||||||
|
|||||||
@ -131,4 +131,46 @@ export const copyRenderTree = (tree, root) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return tree;
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 09:08:43
|
||||||
|
* @Desc: 图片转成dataURL
|
||||||
|
*/
|
||||||
|
export const imgToDataUrl = (src) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||||
|
img.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
img.onload = () => {
|
||||||
|
try {
|
||||||
|
let canvas = document.createElement('canvas')
|
||||||
|
canvas.width = img.width
|
||||||
|
canvas.height = img.height
|
||||||
|
let ctx = canvas.getContext('2d')
|
||||||
|
// 图片绘制到canvas里
|
||||||
|
ctx.drawImage(img, 0, 0, img.width, img.height)
|
||||||
|
resolve(canvas.toDataURL())
|
||||||
|
} catch (error) {
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.onerror = (e) => {
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
img.src = src
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 16:20:06
|
||||||
|
* @Desc: 下载文件
|
||||||
|
*/
|
||||||
|
export const downloadFile = (file, fileName) => {
|
||||||
|
let a = document.createElement('a')
|
||||||
|
a.href = file
|
||||||
|
a.download = fileName
|
||||||
|
a.click()
|
||||||
}
|
}
|
||||||
BIN
web/public/enJFNMHnedQTYTESGfDkctCp2.jpeg
Normal file
BIN
web/public/enJFNMHnedQTYTESGfDkctCp2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 695 KiB |
@ -147,22 +147,6 @@ export const backgroundRepeatList = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// 背景图片大小
|
|
||||||
export const backgroundSizeList = [
|
|
||||||
{
|
|
||||||
name: '自动',
|
|
||||||
value: 'auto'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '完全覆盖',
|
|
||||||
value: 'cover'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '最合适',
|
|
||||||
value: 'contain'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// 背景图片定位
|
// 背景图片定位
|
||||||
export const backgroundPositionList = [
|
export const backgroundPositionList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
<span class="name">图片重复</span>
|
<span class="name">图片重复</span>
|
||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
style="width: 80px"
|
style="width: 120px"
|
||||||
v-model="style.backgroundRepeat"
|
v-model="style.backgroundRepeat"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
@change="
|
@change="
|
||||||
@ -47,50 +47,6 @@
|
|||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="rowItem">
|
|
||||||
<span class="name">图片大小</span>
|
|
||||||
<el-select
|
|
||||||
size="mini"
|
|
||||||
style="width: 80px"
|
|
||||||
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>
|
|
||||||
<div class="rowItem">
|
|
||||||
<span class="name">图片定位</span>
|
|
||||||
<el-select
|
|
||||||
size="mini"
|
|
||||||
style="width: 80px"
|
|
||||||
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>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
@ -220,6 +176,44 @@
|
|||||||
></el-slider>
|
></el-slider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 二级节点外边距 -->
|
||||||
|
<div class="title noTop">节点外边距</div>
|
||||||
|
<div class="row column">
|
||||||
|
<el-tabs
|
||||||
|
class="tab"
|
||||||
|
v-model="marginActiveTab"
|
||||||
|
@tab-click="initMarginStyle"
|
||||||
|
>
|
||||||
|
<el-tab-pane label="二级节点" name="second"></el-tab-pane>
|
||||||
|
<el-tab-pane label="三级及以下节点" name="node"></el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<div class="rowItem">
|
||||||
|
<span class="name">水平</span>
|
||||||
|
<el-slider
|
||||||
|
:max="200"
|
||||||
|
style="width: 200px"
|
||||||
|
v-model="style.marginX"
|
||||||
|
@change="
|
||||||
|
(value) => {
|
||||||
|
updateMargin('marginX', value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
></el-slider>
|
||||||
|
</div>
|
||||||
|
<div class="rowItem">
|
||||||
|
<span class="name">垂直</span>
|
||||||
|
<el-slider
|
||||||
|
:max="200"
|
||||||
|
style="width: 200px"
|
||||||
|
v-model="style.marginY"
|
||||||
|
@change="
|
||||||
|
(value) => {
|
||||||
|
updateMargin('marginY', value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
></el-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
</template>
|
</template>
|
||||||
@ -229,9 +223,7 @@ import Sidebar from "./Sidebar";
|
|||||||
import Color from "./Color";
|
import Color from "./Color";
|
||||||
import {
|
import {
|
||||||
lineWidthList,
|
lineWidthList,
|
||||||
backgroundRepeatList,
|
backgroundRepeatList
|
||||||
backgroundSizeList,
|
|
||||||
backgroundPositionList,
|
|
||||||
} from "@/config";
|
} from "@/config";
|
||||||
import ImgUpload from "@/components/ImgUpload";
|
import ImgUpload from "@/components/ImgUpload";
|
||||||
|
|
||||||
@ -260,9 +252,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
lineWidthList,
|
lineWidthList,
|
||||||
backgroundRepeatList,
|
backgroundRepeatList,
|
||||||
backgroundSizeList,
|
|
||||||
backgroundPositionList,
|
|
||||||
activeTab: "color",
|
activeTab: "color",
|
||||||
|
marginActiveTab: "second",
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: "",
|
backgroundColor: "",
|
||||||
lineColor: "",
|
lineColor: "",
|
||||||
@ -274,8 +265,8 @@ export default {
|
|||||||
iconSize: 0,
|
iconSize: 0,
|
||||||
backgroundImage: "",
|
backgroundImage: "",
|
||||||
backgroundRepeat: "no-repeat",
|
backgroundRepeat: "no-repeat",
|
||||||
backgroundSize: "auto",
|
marginX: 0,
|
||||||
backgroundPosition: "0% 0%",
|
marginY: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -306,10 +297,24 @@ export default {
|
|||||||
"iconSize",
|
"iconSize",
|
||||||
"backgroundImage",
|
"backgroundImage",
|
||||||
"backgroundRepeat",
|
"backgroundRepeat",
|
||||||
"backgroundSize",
|
|
||||||
"backgroundPosition",
|
|
||||||
].forEach((key) => {
|
].forEach((key) => {
|
||||||
this.style[key] = this.mindMap.getThemeConfig(key);
|
this.style[key] = this.mindMap.getThemeConfig(key);
|
||||||
|
if (key === "backgroundImage" && this.style[key] === "none") {
|
||||||
|
this.style[key] = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.initMarginStyle();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-03 22:27:32
|
||||||
|
* @Desc: margin初始值
|
||||||
|
*/
|
||||||
|
initMarginStyle() {
|
||||||
|
["marginX", "marginY"].forEach((key) => {
|
||||||
|
this.style[key] =
|
||||||
|
this.mindMap.getThemeConfig()[this.marginActiveTab][key];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -319,9 +324,27 @@ export default {
|
|||||||
* @Desc: 更新配置
|
* @Desc: 更新配置
|
||||||
*/
|
*/
|
||||||
update(key, value) {
|
update(key, value) {
|
||||||
this.style[key] = value;
|
if (key === "backgroundImage" && value === "none") {
|
||||||
|
this.style[key] = "";
|
||||||
|
} else {
|
||||||
|
this.style[key] = value;
|
||||||
|
}
|
||||||
this.data.theme.config[key] = value;
|
this.data.theme.config[key] = value;
|
||||||
this.$emit("change");
|
this.mindMap.setThemeConfig(this.data.theme.config);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-03 22:08:12
|
||||||
|
* @Desc: 设置margin
|
||||||
|
*/
|
||||||
|
updateMargin(type, value) {
|
||||||
|
this.style[type] = value;
|
||||||
|
if (!this.data.theme.config[this.marginActiveTab]) {
|
||||||
|
this.data.theme.config[this.marginActiveTab] = {};
|
||||||
|
}
|
||||||
|
this.data.theme.config[this.marginActiveTab][type] = value;
|
||||||
|
this.mindMap.setThemeConfig(this.data.theme.config);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -350,6 +373,10 @@ export default {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
&.column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@ -371,7 +398,7 @@ export default {
|
|||||||
|
|
||||||
.name {
|
.name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-right: 5px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
|
|||||||
82
web/src/pages/Edit/components/Count.vue
Normal file
82
web/src/pages/Edit/components/Count.vue
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div class="countContainer">
|
||||||
|
<div class="item">
|
||||||
|
<span class="name">字数</span>
|
||||||
|
<span class="value">{{ words }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="name">节点</span>
|
||||||
|
<span class="value">{{ num }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-24 22:53:10
|
||||||
|
* @Desc: 字数及节点数量统计
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "Count",
|
||||||
|
props: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
words: 0,
|
||||||
|
num: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$bus.$on("data_change", (data) => {
|
||||||
|
this.words = 0;
|
||||||
|
this.num = 0;
|
||||||
|
this.walk(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-30 22:13:07
|
||||||
|
* @Desc: 遍历
|
||||||
|
*/
|
||||||
|
walk(data) {
|
||||||
|
this.num++;
|
||||||
|
this.words += (String(data.data.text) || "").length;
|
||||||
|
if (data.children && data.children.length > 0) {
|
||||||
|
data.children.forEach((item) => {
|
||||||
|
this.walk(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.countContainer {
|
||||||
|
padding: 0 12px;
|
||||||
|
position: fixed;
|
||||||
|
left: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
background: hsla(0, 0%, 100%, 0.6);
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.8;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
color: #555;
|
||||||
|
margin-right: 15px;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,13 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editContainer">
|
<div class="editContainer">
|
||||||
<div class="mindMapContainer" ref="mindMapContainer"></div>
|
<div class="mindMapContainer" ref="mindMapContainer"></div>
|
||||||
|
<Count></Count>
|
||||||
<Outline></Outline>
|
<Outline></Outline>
|
||||||
<Style></Style>
|
<Style></Style>
|
||||||
<BaseStyle
|
<BaseStyle :data="mindMapData" :mindMap="mindMap"></BaseStyle>
|
||||||
:data="mindMapData"
|
|
||||||
:mindMap="mindMap"
|
|
||||||
@change="changeThemeConfig"
|
|
||||||
></BaseStyle>
|
|
||||||
<Theme :mindMap="mindMap"></Theme>
|
<Theme :mindMap="mindMap"></Theme>
|
||||||
<Structure :mindMap="mindMap"></Structure>
|
<Structure :mindMap="mindMap"></Structure>
|
||||||
</div>
|
</div>
|
||||||
@ -20,7 +17,8 @@ import Style from "./Style";
|
|||||||
import BaseStyle from "./BaseStyle";
|
import BaseStyle from "./BaseStyle";
|
||||||
import exampleData from "simple-mind-map/example/exampleData";
|
import exampleData from "simple-mind-map/example/exampleData";
|
||||||
import Theme from "./Theme";
|
import Theme from "./Theme";
|
||||||
import Structure from './Structure';
|
import Structure from "./Structure";
|
||||||
|
import Count from "./Count";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
@ -34,20 +32,32 @@ export default {
|
|||||||
Style,
|
Style,
|
||||||
BaseStyle,
|
BaseStyle,
|
||||||
Theme,
|
Theme,
|
||||||
Structure
|
Structure,
|
||||||
|
Count,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mindMap: null,
|
mindMap: null,
|
||||||
mindMapData: exampleData,
|
mindMapData: null,
|
||||||
|
prevImg: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getData();
|
||||||
this.init();
|
this.init();
|
||||||
this.$bus.$on("execCommand", this.execCommand);
|
this.$bus.$on("execCommand", this.execCommand);
|
||||||
|
this.$bus.$on("export", this.export);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-03 22:11:37
|
||||||
|
* @Desc: 获取思维导图数据,实际应该调接口获取
|
||||||
|
*/
|
||||||
|
getData() {
|
||||||
|
this.mindMapData = exampleData;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-10 15:01:01
|
* @Date: 2021-04-10 15:01:01
|
||||||
@ -70,22 +80,12 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: 王林
|
|
||||||
* @Date: 2021-05-05 13:49:25
|
|
||||||
* @Desc: 修改主题配置
|
|
||||||
*/
|
|
||||||
changeThemeConfig() {
|
|
||||||
this.mindMap.setThemeConfig(this.mindMapData.theme.config);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-05-05 13:32:11
|
* @Date: 2021-05-05 13:32:11
|
||||||
* @Desc: 重新渲染
|
* @Desc: 重新渲染
|
||||||
*/
|
*/
|
||||||
reRender() {
|
reRender() {
|
||||||
console.log(12)
|
|
||||||
this.mindMap.render();
|
this.mindMap.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -97,6 +97,19 @@ export default {
|
|||||||
execCommand(...args) {
|
execCommand(...args) {
|
||||||
this.mindMap.execCommand(...args);
|
this.mindMap.execCommand(...args);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:33:02
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
async export(...args) {
|
||||||
|
try {
|
||||||
|
this.mindMap.export(...args);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
78
web/src/pages/Edit/components/Export.vue
Normal file
78
web/src/pages/Edit/components/Export.vue
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
class="nodeDialog"
|
||||||
|
title="导出"
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
width="500"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="nameInputBox">
|
||||||
|
<span class="name">导出文件名称</span>
|
||||||
|
<el-input style="width: 300px" v-model="fileName" size="mini"></el-input>
|
||||||
|
</div>
|
||||||
|
<el-radio-group v-model="exportType">
|
||||||
|
<el-radio label="png">图片文件(PNG)</el-radio>
|
||||||
|
<el-radio label="svg">svg文件(SVG)</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-24 22:53:54
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "Export",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
exportType: "png",
|
||||||
|
fileName: '思维导图'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$bus.$on("showExport", () => {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-22 22:08:11
|
||||||
|
* @Desc: 取消
|
||||||
|
*/
|
||||||
|
cancel() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-06 22:28:20
|
||||||
|
* @Desc: 确定
|
||||||
|
*/
|
||||||
|
confirm() {
|
||||||
|
this.$bus.$emit("export", this.exportType);
|
||||||
|
this.cancel();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.nodeDialog {
|
||||||
|
.nameInputBox {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -9,6 +9,7 @@
|
|||||||
v-model="tag"
|
v-model="tag"
|
||||||
@keyup.native.enter="add"
|
@keyup.native.enter="add"
|
||||||
:disabled="tagArr.length >= max"
|
:disabled="tagArr.length >= max"
|
||||||
|
placeholder="请按回车键添加"
|
||||||
>
|
>
|
||||||
</el-input>
|
</el-input>
|
||||||
<div class="tagList">
|
<div class="tagList">
|
||||||
|
|||||||
@ -190,7 +190,7 @@
|
|||||||
<div class="rowItem">
|
<div class="rowItem">
|
||||||
<span class="name">水平</span>
|
<span class="name">水平</span>
|
||||||
<el-slider
|
<el-slider
|
||||||
style="width: 230px"
|
style="width: 200px"
|
||||||
v-model="style.paddingX"
|
v-model="style.paddingX"
|
||||||
@change="update('paddingX')"
|
@change="update('paddingX')"
|
||||||
></el-slider>
|
></el-slider>
|
||||||
@ -200,7 +200,7 @@
|
|||||||
<div class="rowItem">
|
<div class="rowItem">
|
||||||
<span class="name">垂直</span>
|
<span class="name">垂直</span>
|
||||||
<el-slider
|
<el-slider
|
||||||
style="width: 230px"
|
style="width: 200px"
|
||||||
v-model="style.paddingY"
|
v-model="style.paddingY"
|
||||||
@change="update('paddingY')"
|
@change="update('paddingY')"
|
||||||
></el-slider>
|
></el-slider>
|
||||||
@ -222,10 +222,10 @@ import {
|
|||||||
borderRadiusList,
|
borderRadiusList,
|
||||||
} from "@/config";
|
} from "@/config";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-06-24 22:54:47
|
* @Date: 2021-06-24 22:54:47
|
||||||
* @Desc: 节点样式设置
|
* @Desc: 节点样式设置
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
name: "Style",
|
name: "Style",
|
||||||
@ -320,6 +320,7 @@ export default {
|
|||||||
* @Desc: 修改样式
|
* @Desc: 修改样式
|
||||||
*/
|
*/
|
||||||
update(prop) {
|
update(prop) {
|
||||||
|
console.log(this.style[prop])
|
||||||
this.activeNode.setStyle(
|
this.activeNode.setStyle(
|
||||||
prop,
|
prop,
|
||||||
this.style[prop],
|
this.style[prop],
|
||||||
@ -436,7 +437,7 @@ export default {
|
|||||||
|
|
||||||
.name {
|
.name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-right: 5px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="toolbarContainer">
|
<div class="toolbarContainer">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<!-- 节点操作 -->
|
<!-- 节点操作 -->
|
||||||
<div class="left">
|
<div class="toolbarBlock">
|
||||||
<div
|
<div
|
||||||
class="toolbarBtn"
|
class="toolbarBtn"
|
||||||
:class="{
|
:class="{
|
||||||
@ -85,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 通用操作 -->
|
<!-- 通用操作 -->
|
||||||
<div class="center">
|
<div class="toolbarBlock">
|
||||||
<div class="toolbarBtn" @click="$bus.$emit('showOutline')">
|
<div class="toolbarBtn" @click="$bus.$emit('showOutline')">
|
||||||
<span class="icon iconfont iconfuhao-dagangshu"></span>
|
<span class="icon iconfont iconfuhao-dagangshu"></span>
|
||||||
<span class="text">显示大纲</span>
|
<span class="text">显示大纲</span>
|
||||||
@ -103,12 +103,20 @@
|
|||||||
<span class="text">结构</span>
|
<span class="text">结构</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 导出 -->
|
||||||
|
<div class="toolbarBlock">
|
||||||
|
<div class="toolbarBtn" @click="$bus.$emit('showExport')">
|
||||||
|
<span class="icon iconfont icondaochu"></span>
|
||||||
|
<span class="text">导出</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<NodeImage></NodeImage>
|
<NodeImage></NodeImage>
|
||||||
<NodeHyperlink></NodeHyperlink>
|
<NodeHyperlink></NodeHyperlink>
|
||||||
<NodeIcon></NodeIcon>
|
<NodeIcon></NodeIcon>
|
||||||
<NodeNote></NodeNote>
|
<NodeNote></NodeNote>
|
||||||
<NodeTag></NodeTag>
|
<NodeTag></NodeTag>
|
||||||
|
<Export></Export>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -118,6 +126,7 @@ import NodeHyperlink from "./NodeHyperlink";
|
|||||||
import NodeIcon from "./NodeIcon";
|
import NodeIcon from "./NodeIcon";
|
||||||
import NodeNote from "./NodeNote";
|
import NodeNote from "./NodeNote";
|
||||||
import NodeTag from "./NodeTag";
|
import NodeTag from "./NodeTag";
|
||||||
|
import Export from './Export';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
@ -132,6 +141,7 @@ export default {
|
|||||||
NodeIcon,
|
NodeIcon,
|
||||||
NodeNote,
|
NodeNote,
|
||||||
NodeTag,
|
NodeTag,
|
||||||
|
Export
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -159,7 +169,6 @@ export default {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
@ -169,8 +178,7 @@ export default {
|
|||||||
color: rgba(26, 26, 26, 0.8);
|
color: rgba(26, 26, 26, 0.8);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
.left,
|
.toolbarBlock {
|
||||||
.center {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
@ -178,6 +186,10 @@ export default {
|
|||||||
box-shadow: 0 2px 16px 0 rgb(0 0 0 / 6%);
|
box-shadow: 0 2px 16px 0 rgb(0 0 0 / 6%);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbarBtn {
|
.toolbarBtn {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user