Vue2项目中使用AntV X6 自定义节点绘制组织树

  • Post author:
  • Post category:vue



1.安装X6组件库

npm install @antv/x6 –save


2.页面引入X6

import { Graph, Cell, Node, Color, Dom, Shape } from '@antv/x6';


3.实现自定义节点 组织树代码

<template>
	<div class="app-container home">
		<div class="leighhs">
			<div class="glydgs">
				<div v-show="Steps === 1" id="container"></div>
				<glydInfo :getNode="getNode" v-show="Steps === 2"></glydInfo>
			
			</div>
			
			<div class="back" @click="back">
				<img src="../../assets/images/home_glyd/back.png" alt="">
			</div>
		</div>
	</div>
</template>

<script>
import { Graph, Cell, Node, Color, Dom, Shape } from '@antv/x6';
import { selectClassRelePoi, selectPointDeta } from '@/http/index';
import glydInfo from './glydInfo.vue';
export default {
	name: 'demo5',
	components:{
		glydInfo
	},
	data() {
		return {
			getNode:undefined,//父传子数据
			Steps:1,//页面切换
			containerWidth: 0, //容器宽
			containerHeight: 0, //容器高
			childNodeWidth: 218, //子节点款
			childNodeHeight: 71, //子节点高
			level2Right: 0,
			topY: 0, //画布最低的Y值,即在视图中最上面的Y值
			HorizontalMargin:200, //node左右之间的间距
			VerticalMargin: 15, //node上下之间的间距
			level: 3, //层级
		};
	},
	mounted() {
		//Container的宽高
		this.$nextTick(() => {
			this.containerWidth = window.innerWidth;
			this.containerHeight = window.innerHeight;
		});
		this.initGraph();
	},
	beforeDestroy() {
		
	},
	methods: {
		back(){
			if(this.Steps>1){
				this.Steps -= 1;
			}
		},
		initGraph() {
			//自定义节点
			Graph.registerNode(
				'root-node',
				{
					width: 365,
					height: 365,
					markup: [
						{
							tagName: 'image',
							attrs: {
								class: 'image'
							}
						},
						{
							tagName: 'text',
							attrs: {
								class: 'name'
							}
						}
					],
					attrs: {
						//设置 image样式
						'.image': {
							x: 0,
							y: 0,
							width: 365,
							height: 365,
							opacity: 1.0
						},
						//设置 text样式
						'.name': {
							refX: 0.5,
							refY: 0.5,
							textAnchor: 'middle',
							textVerticalAnchor: 'middle',
							fill: '#fff',
							fontFamily: 'Arial',
							fontSize:48,
							fontWeight: '600'
						}
					}
				},
				true
			);
			Graph.registerNode(
				'second-node',
				{
					width: this.childNodeWidth,
					height: this.childNodeHeight,
					markup: [
						{
							tagName: 'image',
							attrs: {
								class: 'image'
							}
						},
						{
							tagName: 'text',
							attrs: {
								class: 'name'
							}
						}
					],
					attrs: {
						'.image': {
							x: 0,
							y: 0,
							width: this.childNodeWidth,
							height: this.childNodeHeight,
							opacity: 1.0
						},
						'.name': {
							refX: 0.5,
							refY: 0.5,
							textAnchor: 'middle',
							textVerticalAnchor: 'middle',
							fill: '#fff',
							fontFamily: 'Arial',
							fontSize:28,
							fontWeight: '600'
						}
					}
				},
				true
			);
			Graph.registerNode(
				'third-node',
				{
					width: 220,
					height: 58,
					markup: [
						{
							tagName: 'image',
							attrs: {
								class: 'image'
							}
						},
						{
							tagName: 'text',
							attrs: {
								class: 'name'
							}
						}
					],
					attrs: {
						'.image': {
							x: 0,
							y: 0,
							width: 220,
							height: 58,
							opacity: 1.0
						},
						'.name': {
							refX: 0.5,
							refY: 0.5,
							textAnchor: 'middle',
							textVerticalAnchor: 'middle',
							fill: '#fff',
							fontFamily: 'Arial',
							fontSize:24
						}
					},
				},
				true
			);
			// 自定义边
			Graph.registerEdge(
				'org-edge',
				{
					zIndex: -1,
					attrs: {
						line: {
							strokeWidth: 1,
							stroke: '#A2B1C3',
							sourceMarker: null,
							targetMarker: null
						}
					}
				},
				true
			);
			// 创建画布
			this.graph = new Graph({
				container: document.getElementById('container'),
				scroller: false, //是否滚动
				interacting: false,
				panning:true, //画布拖拽
			});
			//调用数据
			this.initData();
		},
		//获取数据
		initData() {
			selectClassRelePoi({ type: '2' }).then(res => {
				if (res?.code && res?.code == 200) {
					let treeData = {
						isRoot: true,
						name: '管理要点',
						img: require(`../../assets/images/home_glyd/class_a.png`),
						level: 0,
						id: 'root',
						code: 'root',
						content: null,
						parentId: '',
						children: res.data
					};
					//设置节点
					this.setNodes(treeData);
					//监听自定义事件
					this.setup();
				} else {
					this.$message.warning('没有获取到管理要点信息');
				}
			});
		},
		// 监听自定义事件
		setup() {
			this.graph.on('node:click', ({ e, node }) => {
				if (e.type == 'click') {
					let level = node.data.level;
					if (level >= 2) {
						if(node.data.children){
							this.getNode = node.data;
							this.$message.success('跳转新页面');
							this.Steps = 2;
							return;
						}else{
							this.$message.success('没有子节点了');
							return;
						}
						
						
					}
					let parent = node.getParent();
					if (parent) {
						let children = parent.children.filter(item => {
							return this.graph.isNode(item);
						});
						//点击删除 上次展示的节点
						if (children && children.length > 0) {
							children.forEach(item => {
								if (item.children && item.children.length > 0) {
									item.children.forEach(cell => {
										//判断是否节点
										if (this.graph.isNode(cell)) {
											//删除节点
											this.graph.removeNode(cell);
										}
										//判断是否线条
										if (this.graph.isEdge(cell)) {
											//判断是否线条
											this.graph.removeEdge(cell);
										}
									});
								}
							});
						}
					}
					if (node.data.children && node.data.children.length > 0) {
						this.level = node.data.level + 1;
						//设置子级的节点
						this.setChildrenNodes(node.data.children, { x: node.getBBox().x, y: node.getBBox().y });
					} else {
						//没有子节点了,如果level>=4,可以直接跳转详情页面
						if (node.data.level >= 4) {
							this.$message.success('跳转详情页面');
						} else {
							this.$message.success('没有子节点了');
						}
					}
				}
			});
			this.graph.on('node:show', ({ e, node }) => {
				if (e.type == 'touchstart') {
					if (node.data.content) {
					}
				} else {
					this.$message.warning('该节点没有可查看的详细内容');
				}
			});
		},
		//设置第一级节点
		setNodes(data) {
			let children = data.children;
			let totalHeight = (children.length - 1) * (this.childNodeHeight + this.VerticalMargin) + this.childNodeHeight; //子节点总高度
			let position = { x:80, y: totalHeight / 2 -100 };
			//第一级节点
			this.createNode(data.isRoot, 'root-node', data.id, data.name, data.img, data, position);
			this.setChildrenNodes(children, position);
		},
		//设置子级节点
		setChildrenNodes(nodes, position) {
			let nodesFromPoint = this.graph.getNodesFromPoint(position.x, position.y);
			let parentNode = nodesFromPoint[0];
			let parentBBox = parentNode.getBBox();
			let totalHeight = (nodes.length - 1) * (this.childNodeHeight + this.VerticalMargin) + this.childNodeHeight; //子节点总高度
			let Y = parentBBox.center.y - totalHeight / 2;
			// y轴 小于0 进行削正
			if(Y<15){
				Y = 15;
			}
			//大于935  超出屏幕 进行削正
			let size = nodes.length;
			if((Y + size * (this.childNodeHeight + this.VerticalMargin))>=800){
				let difference = (Y + (nodes.length-1) * (this.childNodeHeight + this.VerticalMargin)) - 800;
				//差 相减
				Y = Y-difference;
			}
			//便利
			for (let i = 0; i < nodes.length; i++) {
				let childNode = nodes[i];
				let level = childNode.level;
				childNode['img'] = require(level == 1 ? `../../assets/images/home_glyd/class_b.png` : `../../assets/images/home_glyd/class_c.png`);
				if(level >= 2){
					this.$set(childNode,'lineColor','#00E5F5')
				}
				if (childNode.level > this.level) {
					break;
				}
				let childX;
				//第一级 节点 定位 X轴坐标
				if (level == 1) {
					let centerPosition = 0;
					let cnt = 0;
					if (size % 2 === 0) {
						//偶数
						centerPosition = size / 2;
					} else {
						//奇数
						centerPosition = (size - 1) / 2;
						if (centerPosition === i) {
							cnt = 1;
						} else {
							cnt = Math.abs(centerPosition - i) + 1;
						}
					}
					childX = parentBBox.x + parentBBox.width + this.HorizontalMargin + (cnt - 1) * (this.HorizontalMargin / 5);
					if (i == 0) {
						this.level2Right = childX + this.childNodeWidth;
					}
				} else {
					childX = this.level2Right + this.HorizontalMargin;
				}

				let childY = Y + i * (this.childNodeHeight + this.VerticalMargin);
				
				let node = this.createNode(childNode.isRoot, level >= 2 ? 'third-node' : 'second-node', parentNode.id + childNode.id, childNode.name, childNode.img, childNode, {
					x: childX,
					y: childY
				});
				node.addTo(parentNode);
				// 添加线条
				this.createEdge(parentNode, node, parentNode.data.lineColor);
			}
		},
		//将节点添加到 画布
		createNode(isRoot, nodeType, id, name, bg, data, position) {
			if (isRoot) {
				//根节点
				return this.graph.addNode({
					shape: nodeType,
					id: id,
					position: position,
					data: data,
					attrs: {
						//xlinkHref 自定义图标
						'.image': { xlinkHref: bg },
						'.name': {
							//breakText 设置宽度 超出换行
							text: Dom.breakText(name, { width: 160, height: 45 })
						}
					}
				});
			} else {
				//非跟节点
				if (nodeType == 'second-node') {
					return this.graph.addNode({
						shape: nodeType,
						id: id,
						position: position,
						data: data,
						attrs: {
							//xlinkHref 自定义图标
							'.image': { xlinkHref: bg },
							'.name': {
								//breakText 设置宽度 超出换行
								text: Dom.breakText(name, { width: 160, height: 35 })
							}
						}
					});
				} else {
					return this.graph.addNode({
						shape: nodeType,
						id: id,
						position: position,
						data: data,
						attrs: {
							'.image': { xlinkHref: bg },
							'.name': {
								text: Dom.breakText(name, { width: 90, height: 35 })
							}
						}
					});
				}
			}
		},
		// 设置线条
		createEdge(source, target, lineColor) {
			
			let sourceBBox = source.getBBox();
			let targetBBox = target.getBBox();
			let x;
			let vertices = [];
			if (sourceBBox.y !== targetBBox.y) {
				if (target.data.level == 1) {
					x = sourceBBox.x + sourceBBox.width + this.HorizontalMargin / 2;
				} else {
					x = targetBBox.x - this.HorizontalMargin / 2;
				}
				vertices = [{ x, y: sourceBBox.center.y }, { x, y: targetBBox.center.y }];
			}
			//将线条添加到画布
			return this.graph.addEdge({
				shape: 'org-edge',
				source: { cell: source.id },
				target: { cell: target.id },
				vertices: vertices,
				router: { name: 'orth' },
				connector: { name: 'rounded' },
				attrs: {
					line: {
						//箭头
						targetMarker: {
							name: 'classic',
							size: 10
						},
						//颜色
						stroke: target.data.lineColor? target.data.lineColor:'#0BE1CB'
					}
				}
			});
		}
	}
};
</script>

<style scoped lang="scss">
.home {
	width: 100%;
	height: 100%;
	.leighhs {
		width: 100%;
		height: 100%;
		padding: 17px;
		background: #fff;
		background-color: #008b87;
		position: relative;
		.glydgs {
			width: 100%;
			height: 100%;
			background: url('~@/assets/images/home_glyd/glyd_bg.png') no-repeat;
			background-size: 100% 100%;
			#container {
				width: 100%;
				height: 100%;
				overflow: hidden;
			}
		}
		.back{
			background: url("../../assets/images/home_glyd/bg.png") no-repeat;
			background-size: 100% 100%;
			width: 40px;
			height: 40px;
			position: absolute;
			left: 60px;
			bottom: 40px;
			z-index: 9999;
			img{
				margin-top: 9px;
				margin-left: 5px;
				width: 30px;
				height: 22px;
				cursor: pointer;
			}
		}
	}
}
</style>





最终效果

在这里插入图片描述



版权声明:本文为weixin_45792972原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。