可新增连线的拓扑图实现

G6实现可新增连线可拖拽的自定义拓扑图

容器:

<div id="container"></div>

图表实现:

init(){
	insertCss(`
		.g6-tooltip{
			border-radius:6px;
			font-size:14px;
			color:#fff;
			background-color:rgba(255,255,255,0.8);
			padding:2px 8px;
			text-align:center;
		}
	`)
	//自定义节点
	G6.registerNode('sql',{
		drawShape(cfg,group){
			const rect=group.addShape('rect',{
				attrs:{
					x:-60,
					y:-20,
					height:40,
					width:120,
					radius:10,
					stroke:"#5B8FF9",
					fill:"#C6E5FF",
					lineWidth:2
				},
				name:"rect-shape"
			})
			//添加label
			group.addShape('text',{
				attrs:{
					text:cfg.name,
					x:0,
					y:0,
					fill:"#00287E",
					fontSize:12,
					textAlign:"center",
					textBaseLine:"middle"
				},
				name:"text-shape"
			})
			return rect
		}
	},'single-node')
	//自定义事件
	G6.registerBehavior('click-add-edge',{
		getEvents(){
			return{
				'node:click':'onClick',
				'mousemove':'onMousemove',
				'edge:click':'onEdgeClick'
			}
		},
		//点击节点
		onClick(ev){
			const self=this
			const node=ev.item
			const graph=self.graph
			const point={x:ev.x,y:ev.y}
			const model=node.getModel()
			if(self.addingEdge && self.edge){
				graph.updateItem(self.edge,{
					terget:model.id
				})
				self.edge=null
				self.addingEdge=false
			}else{
				self.edge=graph.addItem('edge',{
					source:model.id,
					terget:model.id,
					style:{
						endArrow:true,
						stroke:"rgba(208,224,247)",
						lineWidth:2
					}
				})
				self.addingEdge=true
			}
		},
		onMousemove(ev){
			const self=this
			const point={x:ev.x,y:ev.y}
			if(self.addingEdge && self.edge){
				self.graph.updateItem(self.edge,{
					target.point
				})
			}
		},
		onEdgeClick(ev){
			const self=this
			const currentEdge=ev.item
			if(self.addingEdge && self.edge===currentEdge){
				self.graph.removeItem(self.edge)
				self.edge=null
				self.addingEdge=false
			}
		}
	})
	
	//连线的菜单
	const edgeMenu=new G6.Menu({
		getContent(evt){
			return`
				<button style='border-radius:4px;
				border:1px solid #1890ff;
				background-color:#1890ff;
				text-shadow:0 -1px 0 rgba(0,0,0,0.12);
				box-shadow:0 2px 0 rgba(0,0,0,0.45);
				width:50px;
				height:30px;
				cursor:pointer;
				text-align:center;
				color:#fff;'>删除</button>
			`
		},
		//连线菜单事件
		handleMenuClick:(terget,item)=>{
			const model=item.getmodel()
			let edge={
				source:model.source,
				target:model.target
			}
			let edgeArr=[]
			edgeArr.push(edge)
			let edges-this.graph.save().edges
			edge.forEach((item,index)=>{
				if(edge.source==item.source && edge.target==item.target){
					edge.splice(index,1)
				}
			})
			//重新给图表数据的连线赋值
			this.sysdata.edges=edges
			//假设节点有一栋,必须重新为nodes赋值 定位 渲染
			this,sysdata.nodes=this.graph.save().nodes
			this.graph.render()
		},
		offsetX:26,
		offsetY:0,
		itemTypes:['edge']
	})

	const container=document.getElementById("container")

	const fittingString=(str,maxwidth,fontsize)=>{
		let currrntWidth=0
		let res=str
		const pattern=new RegExp('[\u4E00-\u9FA5]+')
		str.split("").forEach((letter,i)=>{
			if(currentwidth>maxwidth) return;
			if(pattern.test(letter)){
				currentwidth += fontsize
			}else{
				currentwidth += G6.Util.getLetterWidth(letter,fontsize)
			}
			if(currentwidth > maxwidth){
				res=`${str.substr(0,i)}\n${str.substr(i)}`
			}
		})
		return res
	}
	//label字符串换行处理
	this.sysdata.nodes.forEach(item=>{
		item.name=fittingString(item.name,120,12)
	})

	//默认不适用任何布局
	this.graph=new G6.Graph({
		container:container,
		width:this.localWidth,
		height:this.localHeight,
		plugins:[edgeMenu],
		defaultNode:{
			type:'sql'
		},
		animate:true,
		modes:{
			addEdge:['click-add-edge','click-select','drag-node','activate-relations','drag-canvas']
		},
		nodeStateStyles:{
			selected:{
				stroke:"rgba(208,224,247)",
				lineWidth:2,
				fill:"#e9f1f9"
			}
		},
		defaultEdge:{
			type:"line",
			style:{
				offset:45,
				edgeArrow:true,
				lineWidth:2,
				stroke:"rgba(208,224,247)"
			}
		}
	})
	
	this.graph.setMode('addEge')
	this.graph.data(this.sysdata)

	//当edges为空时,添加布局,否则按照node的x y节点定位
	if(this.sysdata.edges.length>0){
		if(this.sysdata.nodes[0].x!==null){
			console.log("有连线有定位")
		}else{
			console.log("有连线没定位 dagre定位")
			this.graph.updataLayout({
				type:"dagre",
				ranksep:35
			})
		}
	}
	if(this.sysdata.edges.length==0){
		if(this.sysdata.nodes[0].x!==null){
			console.log("没连线有定位")
		}else{
			console.log("没连线没定位 grid布局")
			if(this.sysdata.nodes.length==1){
				this.graph.updataLayout({
					type:"grid",
					begin:[80,60]
				})
			}else{
				this.graph.updataLayout({
					type:"grid",
					rows:5,
					begin:[10,10],
					width:1500-20
				})
			}
		}
	}

	this.graph.render()

	//计算拖拽后的节点
	let dragstartX
	let dragstartY
	let dragX
	let dragY
	let count=0
	let counts=0
	let canvasY
	this.graph.on('canvas:dragstart',e=>{
		count++
		dragstartX=e.canvasX
		dragstartY=e.canvasY
	})
	this.graph.on('canvas:draged',e=>{
		count++
		if(count%2==1){
			canvasY=e.canvasY
			dragX=e.canvasX-dragstartX
			dragY=e.canvasY-dragstartY

			this.graph.save().nodes.forEach(item=>{
				item.x=item.x+dragX
				item.y=item.y+dragY
			})
		}
	})

}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的使用HTML5 Canvas和JavaScript实现网络拓扑图的示例。 HTML代码: ```html <!DOCTYPE html> <html> <head> <title>网络拓扑图Demo</title> <style> canvas { border: 1px solid #333; } </style> </head> <body> <canvas id="topology"></canvas> <script src="topology.js"></script> </body> </html> ``` JavaScript代码: ```javascript // 获取Canvas元素和上下文 var canvas = document.getElementById("topology"); var ctx = canvas.getContext("2d"); // 设置Canvas宽高 canvas.width = window.innerWidth; canvas.height = window.innerHeight; // 定义节点类 function Node(x, y, label) { this.x = x; this.y = y; this.label = label; } // 定义连线类 function Link(startNode, endNode) { this.startNode = startNode; this.endNode = endNode; } // 定义节点和连线列表 var nodes = [ new Node(100, 100, "Node 1"), new Node(200, 200, "Node 2"), new Node(300, 100, "Node 3"), new Node(400, 200, "Node 4") ]; var links = [ new Link(nodes[0], nodes[1]), new Link(nodes[1], nodes[2]), new Link(nodes[2], nodes[3]), new Link(nodes[3], nodes[0]) ]; // 绘制节点和连线 function drawTopology() { // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制连线 links.forEach(function(link) { ctx.beginPath(); ctx.moveTo(link.startNode.x, link.startNode.y); ctx.lineTo(link.endNode.x, link.endNode.y); ctx.stroke(); }); // 绘制节点 nodes.forEach(function(node) { ctx.beginPath(); ctx.arc(node.x, node.y, 20, 0, 2 * Math.PI); ctx.fillStyle = "#fff"; ctx.fill(); ctx.strokeStyle = "#333"; ctx.stroke(); ctx.fillStyle = "#333"; ctx.font = "12px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(node.label, node.x, node.y); }); } // 监听窗口大小改变事件,重新设置Canvas宽高 window.addEventListener("resize", function() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; drawTopology(); }); // 绘制初始状态的拓扑图 drawTopology(); ``` 这个示例中,我们定义了`Node`和`Link`两个类来表示节点和连线,然后创建了一个节点和连线的列表,最后在`drawTopology`函数中根据列表中的节点和连线绘制出拓扑图。我们还监听了窗口大小改变事件,当窗口大小改变时重新设置Canvas宽高并重新绘制拓扑图。 你可以根据自己的需求修改节点和连线的坐标、标签、样式等属性,进一步完善这个示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值