vue+D3项目拓扑图缩放,拖拽,保存布局等

1 篇文章 0 订阅
1 篇文章 0 订阅

注意:vue+D3里面的当数据更新的时候,需要先将之前的数据绘画的点清除 (选择所有的点清除,才可以重新绘画),否则将会重新绘画两次,因为之前的数据渲染的视图并没有清除,这该d3和query功能差不多 ,都是原生js的一些封装,所以不会像那些表格插件一个,选择的时候,初始化一下。故这里需要手动初始化。

 

找了很多资料对vue+D3实现的这些拓扑图的代码比较,

getLinksData:function(nodesData,obj ){   //获取链路的信息数据集合
				this.linksData=[];
				let that=this;
				this.$ajax.get('/topology/links'+'?token='+this.token)
				.then(res => {
					if(res.status==200 && res.data.status==0){
							that.linksData=res.data.data;	
//							that.backupLink=res.data.data;

						this.dealForm(obj,nodesData,that.linksData)
					}
				}).catch(e => {console.log(e)})
			},
			setTopo:function(nodesData,linksData){//设置拓扑图的展示
				d3.select('svg').select('g').remove()
				var width = 890,
				  height = 470;
				var text_dx = -20;
				var text_dy = 20;
				var img_w=16,img_h=16;
				var radius=16;
				linksData.some(function(v, i) {
			        nodesData.some(function(w, j) {
			            if (v.source_node == w.node.id) {
			                v.source_val= w;
			            }
			            if (v.target_node == w.node.id) {
			                v.target_val= w;
			            }
			        });
			        v.index = ++i;
			   });
				
				let that=this
				var linkForce=d3.forceLink(linksData)
				.id(function(d){})
				
				let simulation = d3.forceSimulation()
				.nodes(nodesData)
				
				let centerForce = d3.forceCenter(width / 2, height / 2);
				
				let chargeForce = d3.forceManyBody()
				
				simulation
				.force('chargeForce', chargeForce)
		      	.force('centerForce', centerForce)
		      	.force('links', linkForce)

				simulation.on('tick', tickActions)
				
				var  svg = d3.select('svg')
	            .attr('width',width)
	            .attr('height',height)
//	            
	            var g = svg.append('g');

	            var nodes_text = g.selectAll('.node_text')
	            .data(nodesData)
	            .enter()
	            .append('text')
	            .attr('class','font')
	            .text(function(d){
	            	return d.node.name
	            })
	            var links_text=g.selectAll('.link_text')
	            .data(linksData)
	            .enter()
	            .append('text')
	            .attr('class','links_text')
				.text(function(d){
					return d.bandwidth
	          })
//			    .attr('class', 'link')
				
	        let link = g.append('g') 
	        	.attr('class', 'link')
			    .selectAll('line')
			    .data(linksData)
			    .enter()
			    .append('line')
			    .style('stroke-width', linkWidth)
			    .style('stroke', linkColour)
			    .attr('class',function(d){//对数据进行处理
			    	if(typeof d.speedColor =='undefined'){   //流量的显示不存在的时候   这个时候关闭   返回默认的颜色
			    		return linkColour;
			    	}else {  //当存在  流量的时候    显示流量
			    		return d.speedColor;
			    	}
			    })
			    .on('click',function(d){
			    	var cls=document.getElementsByTagName('line');
			    	for (let index=0;index<cls.length;index++) {
							cls[index].style.strokeWidth='2';
						}
		            	this.style.strokeWidth='8';
		            	let obj={}
		            	if(d.type==='link'){
		            		obj={
		            			id:d.id,
		            			type:'link'
		            		}
		            	}else{
		            		obj={
		            			id:d.id,
		            			type:'cloun'
		            		}
		            	}
		            	that.$emit('sendlink',true)
		            	that.bus.$emit('sendlink',obj);
		            	that.$store.commit('sendLink',obj);
			    })

	            function linkWidth(d){
	            	return 2;
	            }
	            function linkColour(d){
					if(d.status=='UP'){
						return '#6BC7E2'
					}else if(d.status=='DOWN'){
						return '#444242'
					}else if(d.status=='running'){
						return '#9254DE';
					}
				}
				
//				function baseColor(d){
//					if(d.status=='UP'){
//			    		d.color='linkUP'
//			    	}else if(d.status=='DOWN'){
//			    		d.color='linkDOWN'
//			    		
//			    	}else if(d.status=='running'){
//			    		d.color='linkRun'
//			    	}
//			    	return d.color
//				}
				
				let node = g.append('g')
			    	.attr('class', 'nodes')
			      	.selectAll('circle')
			      	.data(nodesData)
			      	.enter()
			      	.append('image')
			      	.attr('r', radius)
					.attr('xlink:href',nodeTypeImage)
					.attr('height',img_h)
					.attr('width',img_w)
					.attr('x',function(d){
						return d.x-img_w/2
					})
					.attr('y',function(d){
						return d.y-img_h/2
					})
//				节点的拖拽	
		       let dragHandler = d3.drag()
			      	.on('start', dragStart)
			      	.on('drag', dragDrag)
			      	.on('end', dragEnd)
			
			    dragHandler(node)  
			    
		        node.on('click',function(d){

					that.$store.commit('newAuthor',d.node.id)  //向数据仓库传值
//		        	//向父节点传值
		        	that.$emit('parentDelta',true)
		        	that.bus.$emit('sendNodeID',d.node.id);
		        	that.nodeId=d.node.id;
		        })
				//节点的缩放
			    function zoomActions () {
			      g.attr('transform', d3.event.transform)
			    }
				let zoomHandler = d3.zoom()
			      	.on('zoom', zoomActions)
			
			    zoomHandler(svg)
				
				

				d3.select('#big').on('click',function(d){
					zoomHandler.scaleBy(svg, 1.1); // 执行该方法后 会触发zoomHandler事件
            		let tran = d3.zoomTransform(svg.node());			
				})
				d3.select('#small').on('click',function(){
					zoomHandler.scaleBy(svg, 0.9); // 执行该方法后 会触发zoomHandler事件
            		let tran = d3.zoomTransform(svg.node());
				})
//				let newData=[];//用来保存拖拽后的所有的节点
				let newObj={};//保存拖拽后的每个节点数据
				function tickActions () {
		            node.attr("x", function(d) { return d.x-img_w/2; })
				        .attr("y", function(d) { return d.y-img_h/2; });
//					nodesData.forEach((d,i) => {   //设置边界
//						d.x= d.x - img_w/2 < 0 ? img_w/2 : d.x;
//						d.y=d.y - img_h/2 < 0? img_h/2 : d.y;
//					});
					link.attr("x1", function(d) {
						if(d.source_val){
							return d.source_val.x;
						}
					})
		                .attr("y1", function(d) {
		                	if(d.source_val){
		                		return d.source_val.y;
		                	}
		                	 })
		                .attr("x2", function(d) {
		                	if(d.target_val){
		                		return d.target_val.x;
		                	}
		                	 })
		                .attr("y2", function(d) {
		                	if(d.target_val){
		                		return d.target_val.y;
		                	}
		                	})
				   nodes_text.attr('x',function(d){d.fx=d.x;return d.x-12})
				            .attr("y", function(d) { d.fy=d.y;return d.y-12 });
		           links_text.attr("x", function(d) { 
		           	if(d.source_val && d.target_val){
		           		return (d.source_val.x+d.target_val.x)/2;
		           	}
		           	 })
		                .attr("y", function(d) {
		                	if(d.source_val && d.target_val){
		                		return (d.source_val.y+d.target_val.y)/2;
		                	}
		                	 })
			   	}
				function nodeTypeImage(nodes){
					if(nodes.type==='node'){
						return require('../../../assets/images/newTopo/node.png')
					}else if(nodes.type==='阿里云'){
						return require('../../../assets/images/newTopo/ali.png')					
					}else if(nodes.type==='腾讯云'){
						return require('../../../assets/images/newTopo/tencent.png')
						
					}else if(nodes.type==='华为云'){
						return require('../../../assets/images/newTopo/huawei.png')
									
					}else if(nodes.type==='UCloud'){
						return require('../../../assets/images/newTopo/ucloud.png')
								
					}else{
						return require('../../../assets/images/newTopo/error.png')
					}
				}
		        function dragStart (d) {
			      if (!d3.event.active) simulation.alphaTarget(0.3).restart()
			      d.fx = d.x
			      d.fy = d.y
			    }
			
			    // make sure you can't drag the circle outside the box
			    function dragDrag (d) {
			      d.fx = d3.event.x
			      d.fy = d3.event.y
			    }
			
			    function dragEnd (d) {
			      if (!d3.event.active) simulation.alphaTarget(0)
			      d.fx = null
			      d.fy = null
			      
			      newObj={
			      	id:d.id,
			      	x:d.x,
			      	y:d.y
			      }
			      that.saveData.push(newObj);
			    }
			},
以上代码就是将数据绘画到组件内渲染的代码

 

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js是一个基于JavaScript的开源框架,用于构建用户界面。而D3.js是一个用于在网页上创建可交互数据可视化的JavaScript库。结合Vue.js和D3.js可以很方便地绘制流程图。 首先,我们需要在Vue.js项目中安装D3.js,可以通过npm安装。在终端中运行以下命令: npm install d3 安装完成后,在Vue.js组件中引入D3.js库: import * as d3 from 'd3'; 接下来,我们可以在Vue.js组件的生命周期函数中创建一个D3.js绘制流程图的函数。比如,在mounted钩子函数中: mounted() { this.drawFlowChart(); } 然后,在drawFlowChart函数中,我们可以使用D3.js提供的方法和API来绘制流程图。这个过程可以分为以下几步: 1. 创建svg元素,用于承载流程图的绘制: const svg = d3.select('body') .append('svg') .attr('width', '100%') .attr('height', '100%'); 2. 定义绘制流程图所需的数据,比如节点和连接线的位置和样式信息: const nodes = [ { id: 1, name: 'Node 1' }, { id: 2, name: 'Node 2' }, { id: 3, name: 'Node 3' }, // ... ]; const links = [ { source: 1, target: 2 }, { source: 2, target: 3 }, // ... ]; 3. 创建节点和连接线的元素,并设置其位置和样式: const node = svg.selectAll('.node') .data(nodes) .enter() .append('g') .attr('class', 'node') .attr('transform', d => `translate(${d.x}, ${d.y})`); node.append('rect') .attr('width', 100) .attr('height', 50); const link = svg.selectAll('.link') .data(links) .enter() .append('line') .attr('class', 'link') .attr('x1', d => d.source.x) .attr('y1', d => d.source.y) .attr('x2', d => d.target.x) .attr('y2', d => d.target.y); 4. 可以根据需要添加交互功能,比如节点的点击事件、鼠标悬停效果等等。 至此,我们使用Vue.js和D3.js成功绘制了一个流程图。通过Vue.js的数据绑定和D3.js的数据驱动视图的特性,可以很方便地更新流程图的数据和样式,实现交互和动态效果。同时,D3.js也提供了丰富的API可以用于进行复杂的数据可视化操作,比如节点之间的动画过渡效果、缩放拖拽等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值