|
@@ -1,149 +1,148 @@
|
|
|
<template>
|
|
|
- <div class="node-chart-content">
|
|
|
- <div :id="id" />
|
|
|
+ <div class="node-chart-content" style="position: relative;">
|
|
|
+ <div :id="chartContentId" />
|
|
|
</div>
|
|
|
</template>
|
|
|
<script>
|
|
|
import G6 from '@antv/g6'
|
|
|
export default {
|
|
|
props: {
|
|
|
- id: {
|
|
|
+ chartContentId: {
|
|
|
type: String,
|
|
|
default: ''
|
|
|
+ },
|
|
|
+ graphData: {
|
|
|
+ type: Object,
|
|
|
+ default: () => {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
- data() {
|
|
|
- return {}
|
|
|
+ watch: {
|
|
|
+ 'graphData': {
|
|
|
+ handler(newValue, oldValue) {
|
|
|
+ if (newValue) {
|
|
|
+ this.init(newValue)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
},
|
|
|
mounted() {
|
|
|
- this.init()
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.init(this.graphData)
|
|
|
+ })
|
|
|
},
|
|
|
methods: {
|
|
|
- init() {
|
|
|
+ init(data) {
|
|
|
/**
|
|
|
* by Shiwu
|
|
|
*/
|
|
|
-
|
|
|
- const data = {
|
|
|
- nodes: [
|
|
|
- {
|
|
|
- id: 'person A',
|
|
|
- label: 'person A',
|
|
|
- // the attributes for drawing donut
|
|
|
- donutAttrs: {
|
|
|
- 'income': 10,
|
|
|
- 'outcome': 20,
|
|
|
- 'unknown': 25
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'person B',
|
|
|
- label: 'person B',
|
|
|
- donutAttrs: {
|
|
|
- 'income': 20,
|
|
|
- 'outcome': 10,
|
|
|
- 'unknown': 5
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'person C',
|
|
|
- label: 'person C',
|
|
|
- donutAttrs: {
|
|
|
- 'income': 200,
|
|
|
- 'outcome': 20,
|
|
|
- 'unknown': 25
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'person D',
|
|
|
- label: 'person D',
|
|
|
- donutAttrs: {
|
|
|
- 'income': 50,
|
|
|
- 'outcome': 10,
|
|
|
- 'unknown': 15
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'person E',
|
|
|
- label: 'person E',
|
|
|
- donutAttrs: {
|
|
|
- 'income': 80,
|
|
|
- 'outcome': 40,
|
|
|
- 'unknown': 45
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- id: 'person F',
|
|
|
- label: 'person F',
|
|
|
- donutAttrs: {
|
|
|
- 'income': 90,
|
|
|
- 'outcome': 110,
|
|
|
- 'unknown': 15
|
|
|
- }
|
|
|
- }
|
|
|
- ],
|
|
|
- edges: [
|
|
|
- { source: 'person C', target: 'person F', size: 10 },
|
|
|
- { source: 'person B', target: 'person A', size: 5 },
|
|
|
- { source: 'person D', target: 'person E', size: 20 },
|
|
|
- { source: 'person D', target: 'person C', size: 5 },
|
|
|
- { source: 'person B', target: 'person C', size: 10 },
|
|
|
- { source: 'person A', target: 'person C', size: 5 }
|
|
|
- ]
|
|
|
- }
|
|
|
-
|
|
|
data.edges.forEach(edge => {
|
|
|
- edge.label = `Transfer $${edge.size}`
|
|
|
+ edge.label = `${edge.relation}`
|
|
|
})
|
|
|
|
|
|
const colors = {
|
|
|
- 'income': '#61DDAA',
|
|
|
- 'outcome': '#F08BB4',
|
|
|
- 'unknown': '#65789B'
|
|
|
+ 'err': '#F44C4C',
|
|
|
+ 'ok': '#53F44C'
|
|
|
}
|
|
|
-
|
|
|
+ const imgObj = {
|
|
|
+ cpp: require('../../../../assets/G6-icons/cpp.svg'),
|
|
|
+ dotnet: require('../../../../assets/G6-icons/dot-net.svg'),
|
|
|
+ erlang: require('../../../../assets/G6-icons/erlang.svg'),
|
|
|
+ go: require('../../../../assets/G6-icons/go.svg'),
|
|
|
+ java: require('../../../../assets/G6-icons/java.svg'),
|
|
|
+ nodejs: require('../../../../assets/G6-icons/nodejs.svg'),
|
|
|
+ php: require('../../../../assets/G6-icons/php.svg'),
|
|
|
+ python: require('../../../../assets/G6-icons/python.svg'),
|
|
|
+ ruby: require('../../../../assets/G6-icons/ruby.svg'),
|
|
|
+ rust: require('../../../../assets/G6-icons/rust.svg'),
|
|
|
+ swift: require('../../../../assets/G6-icons/swift.svg'),
|
|
|
+ webjs: require('../../../../assets/G6-icons/webjs.svg'),
|
|
|
+ mysql: require('../../../../assets/G6-icons/mysql.svg'),
|
|
|
+ oracle: require('../../../../assets/G6-icons/oracle.svg'),
|
|
|
+ postgresql: require('../../../../assets/G6-icons/postgresql.svg'),
|
|
|
+ hive: require('../../../../assets/G6-icons/hive.svg'),
|
|
|
+ progress: require('../../../../assets/G6-icons/progress.svg'),
|
|
|
+ hsqldb: require('../../../../assets/G6-icons/hsqldb.svg'),
|
|
|
+ kafka: require('../../../../assets/G6-icons/kafka.svg'),
|
|
|
+ rabbitmq: require('../../../../assets/G6-icons/rabbitmq.svg'),
|
|
|
+ rocketmq: require('../../../../assets/G6-icons/rocketmq.svg'),
|
|
|
+ activemq: require('../../../../assets/G6-icons/activemq.svg'),
|
|
|
+ servicebus: require('../../../../assets/G6-icons/serviceBus.svg'),
|
|
|
+ client: require('../../../../assets/G6-icons/client.svg'),
|
|
|
+ aws_sqs: require('../../../../assets/G6-icons/aws.svg'),
|
|
|
+ default: require(`../../../../assets/G6-icons/default.svg`)
|
|
|
+ }
|
|
|
data.nodes.forEach(node => {
|
|
|
node.donutColorMap = colors
|
|
|
node.size = 0
|
|
|
+ node.label = node.name
|
|
|
+ node.iconType = node.type
|
|
|
+ node.donutAttrs = node.attrs// donutAttrs
|
|
|
Object.keys(node.donutAttrs).forEach(key => {
|
|
|
- node.size += node.donutAttrs[key]
|
|
|
+ node.size += Number(node.donutAttrs[key])
|
|
|
})
|
|
|
- node.size = Math.sqrt(node.size) * 5
|
|
|
+ node.size = Math.sqrt(node.size) * 60
|
|
|
+ delete node.type
|
|
|
})
|
|
|
|
|
|
const legendData = {
|
|
|
nodes: [{
|
|
|
- id: 'income',
|
|
|
- label: 'Income',
|
|
|
+ id: 'err',
|
|
|
+ label: 'Err',
|
|
|
order: 0,
|
|
|
style: {
|
|
|
- fill: '#61DDAA'
|
|
|
- }
|
|
|
- }, {
|
|
|
- id: 'outcome',
|
|
|
- label: 'Outcome',
|
|
|
- order: 2,
|
|
|
- style: {
|
|
|
- fill: '#F08BB4'
|
|
|
+ fill: '#F44C4C'
|
|
|
}
|
|
|
}, {
|
|
|
- id: 'unknown',
|
|
|
- label: 'Unknown',
|
|
|
+ id: 'ok',
|
|
|
+ label: '0k',
|
|
|
order: 2,
|
|
|
style: {
|
|
|
- fill: '#65789B'
|
|
|
+ fill: '#53F44C'
|
|
|
}
|
|
|
}]
|
|
|
}
|
|
|
+ const tooltip = new G6.Tooltip({
|
|
|
+ // offsetX and offsetY include the padding of the parent container
|
|
|
+ offsetX: 20,
|
|
|
+ offsetY: 30,
|
|
|
+ itemTypes: ['node'],
|
|
|
+ getContent: (e) => {
|
|
|
+ const outDiv = document.createElement('div')
|
|
|
+ // outDiv.style.padding = '0px 0px 20px 0px';
|
|
|
+ const nodeName = e.item.getModel().name
|
|
|
+ const item = e.item.getModel()
|
|
|
+ outDiv.innerHTML = `
|
|
|
+ <div style="margin-bottom:8px box-shadow: rgb(174, 174, 174) 0px 0px 10px;
|
|
|
+ width: fit-content;
|
|
|
+ color: #fff;
|
|
|
+ border-radius = 4px;">
|
|
|
+ <span style='display:inline-block;width:120px;text-align:right;'>Ok:</span>
|
|
|
+ <span style='display:inline-block;'>${item}</span>
|
|
|
+ </div>
|
|
|
+ <div style="margin-bottom:8px">
|
|
|
+ <span style='display:inline-block;width:120px;text-align:right;'>Err:</span>
|
|
|
+ <span style='display:inline-block;'>${item}</span>
|
|
|
+ </div>
|
|
|
+ `
|
|
|
+ return outDiv
|
|
|
+ },
|
|
|
+ shouldBegin: (e) => {
|
|
|
+ if (e.target.get('name') === 'name-shape' || e.target.get('name') === 'mask-label-shape') return true
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ })
|
|
|
const legend = new G6.Legend({
|
|
|
data: legendData,
|
|
|
align: 'center',
|
|
|
layout: 'horizontal', // vertical
|
|
|
- position: 'bottom-left',
|
|
|
+ position: 'top-left',
|
|
|
vertiSep: 12,
|
|
|
horiSep: 24,
|
|
|
offsetY: -24,
|
|
|
- padding: [4, 16, 8, 16],
|
|
|
+ padding: [4, 8, 4, 8],
|
|
|
containerStyle: {
|
|
|
fill: '#ccc',
|
|
|
lineWidth: 1
|
|
@@ -154,78 +153,101 @@ export default {
|
|
|
}
|
|
|
|
|
|
})
|
|
|
- const container = document.getElementById(this.id)
|
|
|
- const width = container.scrollWidth
|
|
|
- console.log('width-----', width)
|
|
|
- const height = container.scrollHeight || 500
|
|
|
- const graph = new G6.Graph({
|
|
|
- container: this.id,
|
|
|
- width,
|
|
|
- height,
|
|
|
- // translate the graph to align the canvas's center, support by v3.5.1
|
|
|
- fitCenter: true,
|
|
|
- plugins: [legend],
|
|
|
- modes: {
|
|
|
- default: ['drag-canvas', 'drag-node']
|
|
|
- },
|
|
|
- layout: {
|
|
|
- type: 'radial',
|
|
|
- focusNode: 'li',
|
|
|
- linkDistance: 200,
|
|
|
- unitRadius: 200
|
|
|
- },
|
|
|
- defaultEdge: {
|
|
|
- style: {
|
|
|
- endArrow: true
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const container = document.getElementById('serviceDrawerContainer')
|
|
|
+ const width = container.scrollWidth
|
|
|
+ const height = container.scrollHeight || 500
|
|
|
+ const graph = new G6.Graph({
|
|
|
+ container: 'serviceDrawerContainer',
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ fitView: data.nodes.length > 2 ? true:false,
|
|
|
+ maxZoom: 8, // 默认值是10
|
|
|
+ minZoom: 0.02, // 默认值是0.02
|
|
|
+ // translate the graph to align the canvas's center, support by v3.5.1
|
|
|
+ fitCenter: true,
|
|
|
+ plugins: [legend],
|
|
|
+ modes: {
|
|
|
+ default: ['drag-canvas', 'drag-node', 'zoom-canvas',
|
|
|
+ {
|
|
|
+ type: 'tooltip', // 提示框
|
|
|
+ // offset:0,
|
|
|
+ formatText(model) {
|
|
|
+ // 提示框文本内容
|
|
|
+ return `<div style="background-color: rgba(0,0,0, 0.65); box-shadow: rgb(174, 174, 174) 0px 0px 10px;
|
|
|
+ width: fit-content;
|
|
|
+ color: #fff;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius:4px;">
|
|
|
+ <div style="margin-bottom:8px">
|
|
|
+ <span >Ok:</span>
|
|
|
+ <span>${model.attrs.ok == '0.00000' ? 0 : model.attrs.ok == '1.00000' ? 1 : model.attrs.ok}</span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <span >Err:</span>
|
|
|
+ <span>${model.attrs.err == '0.00000'? 0: (model.attrs.err == '1.00000' ? 1 : model.attrs.err)}</span>
|
|
|
+ </div>
|
|
|
+ </div>`
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ] // 启用拖拽画布和缩放画布的交互模式
|
|
|
+ },
|
|
|
+ layout: {
|
|
|
+ type: 'radial',
|
|
|
+ focusNode: 'li',
|
|
|
+ linkDistance: 200,
|
|
|
+ unitRadius: 200,
|
|
|
+ preventOverlap: true, // 防止节点重叠
|
|
|
+ nodeSpacing: 500,
|
|
|
+ // 防碰撞必须设置nodeSize或size,否则不生效,由于节点的size设置了40,虽然节点不碰撞了,但是节点之间的距离很近,label几乎都挤在一起,所以又重新设置了大一点的nodeSize,这样效果会好很多
|
|
|
+ nodeSize: 60,
|
|
|
+ strictRadial:false,
|
|
|
+ linkDistance: data.nodes.length>6? 400 : 200 // 指定边距离为150
|
|
|
},
|
|
|
- labelCfg: {
|
|
|
- autoRotate: true,
|
|
|
+ defaultEdge: {
|
|
|
style: {
|
|
|
- stroke: '#fff',
|
|
|
- lineWidth: 5
|
|
|
+ endArrow: true
|
|
|
+ },
|
|
|
+ labelCfg: { // 标签文本配置项
|
|
|
+ autoRotate: true,
|
|
|
+ style: {
|
|
|
+ stroke: '#fff',
|
|
|
+ lineWidth: 5
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- },
|
|
|
- defaultNode: {
|
|
|
- type: 'donut',
|
|
|
- style: {
|
|
|
- lineWidth: 0
|
|
|
},
|
|
|
- labelCfg: {
|
|
|
- position: 'bottom'
|
|
|
- },
|
|
|
- icon: {
|
|
|
- /* whether show the icon, false by default */
|
|
|
- show: true
|
|
|
- /* icon's img address, string type */
|
|
|
- // img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
|
|
- /* icon's size, 20 * 20 by default: */
|
|
|
- // width: 40,
|
|
|
- // height: 40
|
|
|
+ defaultNode: {
|
|
|
+ type: 'donut',
|
|
|
+ style: {
|
|
|
+ lineWidth: 0,
|
|
|
+ cursor: 'pointer'
|
|
|
+ },
|
|
|
+ labelCfg: {
|
|
|
+ position: 'bottom',
|
|
|
+ autoRotate: true,
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- graph.data(data)
|
|
|
- graph.render()
|
|
|
-
|
|
|
- graph.on('node:mouseenter', (evt) => {
|
|
|
- const { item } = evt
|
|
|
- graph.setItemState(item, 'active', true)
|
|
|
- })
|
|
|
-
|
|
|
- graph.on('node:mouseleave', (evt) => {
|
|
|
- const { item } = evt
|
|
|
- graph.setItemState(item, 'active', false)
|
|
|
- })
|
|
|
+ })
|
|
|
+ // 节点配置中使用
|
|
|
+ graph.node((node) => {
|
|
|
+ return {
|
|
|
+ icon: {
|
|
|
+ show: true,
|
|
|
+ // 使用函数动态指定图标路径 imgObj[node.iconType] || imgObj.default
|
|
|
+ img: imgObj[node.iconType] || imgObj.default
|
|
|
+ }
|
|
|
+ };
|
|
|
+ });
|
|
|
+ graph.data(data)
|
|
|
+ graph.render()
|
|
|
+ graph.on('node:mouseenter', (evt) => {
|
|
|
+ const { item } = evt
|
|
|
+ graph.setItemState(item, 'active', true)
|
|
|
+ })
|
|
|
|
|
|
- graph.on('node:click', (evt) => {
|
|
|
- const { item } = evt
|
|
|
- graph.setItemState(item, 'selected', true)
|
|
|
- })
|
|
|
- graph.on('canvas:click', (evt) => {
|
|
|
- graph.getNodes().forEach((node) => {
|
|
|
- graph.clearItemStates(node)
|
|
|
+ graph.on('node:mouseleave', (evt) => {
|
|
|
+ const { item } = evt
|
|
|
+ graph.setItemState(item, 'active', false)
|
|
|
})
|
|
|
})
|
|
|
}
|