使用原生canvas实现环形布局

 

先上图

使用原生canvas实现环形布局

以下是实现代码

<html>
<div id="graph">
</div>
<div id="drawing" style="position: relative;">
</div>
<canvas id="processCanvas"></canvas>
<div style="position: relative;">
	
</div>
<div style="position: relative;">
	<canvas id="myCanvas"></canvas>
</div>
</html>
<script>

var lines = [
{
	beginNodeId:"1",
	beginNode:"测试节点1",
	endNodeId:"2",
	endNode:"测试节点2"
},
{
	beginNodeId:"2",
	beginNode:"测试节点2",
	endNodeId:"3",
	endNode:"测试节点3"
},
{
	beginNodeId:"3",
	beginNode:"测试节点3",
	endNodeId:"4",
	endNode:"测试节点4"
},
{
	beginNodeId:"4",
	beginNode:"测试节点4",
	endNodeId:"5",
	endNode:"测试节点5"
},
{
	beginNodeId:"5",
	beginNode:"测试节点5",
	endNodeId:"6",
	endNode:"测试节点6"
},
{
	beginNodeId:"5",
	beginNode:"测试节点5",
	endNodeId:"1",
	endNode:"测试节点1"
}
];

var allNodesArr = [];
var allStartNodes = [];
var allEndNodes = [];
var onlyStartNodes=[];//只是起始节点
var onlyEndNodes = [];//只是结束节点
	
//获取起点
function getStartEndNodes(allnodes){
	
	for(var i in allnodes){
		var node = allnodes[i];
		var beginNode = {
						id:node.beginNodeId,
						name:node.beginNode
						};
		var endNode = {
						id:node.endNodeId,
						name:node.endNode
						};
		allNodesArr.push(beginNode);
		allNodesArr.push(endNode);

		allStartNodes.push(beginNode);
		allEndNodes.push(endNode);
	}
	allNodesArr = unique(allNodesArr);//去重
	allStartNodes = unique(allStartNodes);
	allEndNodes = unique(allEndNodes);
	//仅是开始节点
	onlyStartNodes = allStartNodes.filter(function(node){
		var flag = true;
		for(var i in lines){
			if(lines[i].endNodeId == node.id){
				flag = false;
			}
		}
		return flag;
	});
	console.log(onlyStartNodes);
	
}

// 对象数组去重
function unique(inputArr){
	var obj = {};
	var outputArr = [];
	for(var i in inputArr){
		if(!obj[inputArr[i].id]){
			outputArr.push(inputArr[i]);
			obj[inputArr[i].id] = true;
		}
	}
	return outputArr;
}
//运行
getStartEndNodes(lines);

//有向图邻接表
// var targetNodesHtml = "";

// for(var i in allNodesArr){
// 	var node = allNodesArr[i]
// 	targetNodesHtml = targetNodesHtml + "<div class='graph-block target-node'>"+node.name+"</div>";
// }

// var firstLineHtml = "<div class='graph-line '><div class='graph-block source-node target-node'></div>"+targetNodesHtml+"</div>";

// var allEdgeHtml = ""
// for(var i in allNodesArr){
// 	var edgeArr = [];//线数组
	
// 	var sourceNode = allNodesArr[i];//源节点
	
// 	var edgeHtml = "<div class='graph-line'><div class='graph-block source-node'>"+sourceNode.name+"</div>";
	
// 	for(var j in allNodesArr){
// 		var targetNode = allNodesArr[j];//目的节点
// 		var inFlag = false;
// 		for(var k in lines){
// 			var line = lines[k]; 
// 			if(line.beginNodeId==sourceNode.id && line.endNodeId==targetNode.id){
// 				inFlag = true;
// 			}
// 		}
// 		if(inFlag){
// 			edgeArr.push(1)
// 		}else{
// 			edgeArr.push(0);
// 		}
// 	}
// 	for(var m in edgeArr){
// 		if(edgeArr[m]==1){//着色
// 			edgeHtml = edgeHtml + "<div class='graph-block' style='font-weight: bold;background-color:#4ff181;'>"+edgeArr[m]+"</div>";
// 		}else{
// 			edgeHtml = edgeHtml + "<div class='graph-block'>"+edgeArr[m]+"</div>";
// 		}
// 	}
// 	edgeHtml = edgeHtml + "</div>";
// 	allEdgeHtml = allEdgeHtml + edgeHtml
// }

// var graph = document.getElementById("graph");
// graph.innerHTML = firstLineHtml + allEdgeHtml;

//canvas画图-----开始
var processCanvas = document.getElementById('processCanvas');

var canvasHeight = allNodesArr.length * 60
processCanvas.height = canvasHeight;
processCanvas.width = canvasHeight;
var ctx = processCanvas.getContext("2d");

var num = allNodesArr.length;//有多少个点
var angle = Math.PI * 2 / num;//分角

var x = processCanvas.width/2;//大圆心x坐标
var y = processCanvas.height/2;//大圆心y坐标
var r = x>y ? (y-40) : (x-40);//大圆半径

var xTemp=x-r;//小圆心x坐标
var yTemp=y;//小圆心y坐标
var rTemp=40;//小圆半径

//画小圆
for(var i in allNodesArr){
	var nodeId = allNodesArr[i].id;//点的id
	var nodeName = allNodesArr[i].name;//
	
	//点中心的坐标
	xTemp = x + r*Math.sin(i*angle);
	yTemp = y + r*Math.cos(i*angle);

	ctx.beginPath();
	ctx.arc(xTemp, yTemp, rTemp, Math.PI * 2, false);
	ctx.closePath();
	
	if(onlyStartNodes.includes(nodeId)){//开始节点涂色
		ctx.fillStyle = 'green';
	}else if(onlyEndNodes.includes(nodeId)){//结束节点涂色
		ctx.fillStyle = 'red';
	}else{
		ctx.fillStyle = 'rgb(79,241,129,1)';
	}
	
	ctx.fill();
	
	// 设置字体
	ctx.font = "12px bold 黑体";
	// 设置颜色
	ctx.fillStyle = 'rgb(0,0,0,1)';
	// 设置水平对齐方式
	ctx.textAlign = "center";
	// 设置垂直对齐方式
	ctx.textBaseline = "middle";
	ctx.fillText(nodeName, xTemp, yTemp);
	
	allNodesArr[i].x = xTemp;
	allNodesArr[i].y = yTemp;
	
}
//画线
for(var i in lines){

	var startNode = allNodesArr.find(function(node){
		return node.id == lines[i].beginNodeId;
	})
	var endNode = allNodesArr.find(function(node){
		return node.id == lines[i].endNodeId;
	});
	
	ctx.strokeStyle="gray";
	ctx.fillStyle="blue";
	ctx.lineWidth=1;
	
	// 开始画线	
	ctx.beginPath();
	var lineLength = distance(startNode,endNode);
	//重新计算线的起点
	var x1 = rTemp/lineLength*(endNode.x-startNode.x)+startNode.x;//交点的x值
	var y1 = rTemp/lineLength*(endNode.y-startNode.y)+startNode.y;//交点的y值
	var lineStart = {x:x1,y:y1};
	ctx.moveTo(x1,y1);
	//重新计算线的终点
	var x2 = (lineLength-rTemp)/lineLength*(endNode.x-startNode.x)+startNode.x;//交点的x值
	var y2 = (lineLength-rTemp)/lineLength*(endNode.y-startNode.y)+startNode.y;//交点的y值
	var lineEnd = {x:x2,y:y2};
	ctx.lineTo(x2,y2);
	ctx.stroke();
	ctx.closePath();
	
	//绘制箭头
	var angleLength = 15;//设置角的长度 
	var theta = 20*Math.PI/180;//设置角的角度

	var lineK=(lineStart.x-lineEnd.x)/(lineStart.y-lineEnd.y);//直线斜率
	//直线与水平线夹角(-90 ~ 90)
	var lineTheta = Math.atan(lineK);
	//极坐标系转换为平面坐标系
	var leftTheta = lineTheta+theta;
	var rightTheta = lineTheta-theta;
	
	var x4=0,y4=0;//箭头左侧坐标
	var x5=0,y5=0;//箭头右侧坐标
	
	if(endNode.y - startNode.y > 0){//向量夹角在0-180度之间(0--PI)
		x4 = x2 - angleLength*Math.sin(leftTheta);
		y4 = y2 - angleLength*Math.cos(leftTheta);
		
		x5 = x2 - angleLength*Math.sin(rightTheta);
		y5 = y2 - angleLength*Math.cos(rightTheta);
	}else{//向量夹角在180度-360度之间(PI--2*PI)
		x4 = x2 + angleLength*Math.sin(leftTheta);
		y4 = y2 + angleLength*Math.cos(leftTheta);
		
		x5 = x2 + angleLength*Math.sin(rightTheta);
		y5 = y2 + angleLength*Math.cos(rightTheta);
	}

	
	/**
	var x3 = (lineLength-rTemp-angleLength)/lineLength*(endNode.x-startNode.x)+startNode.x;//交点的x值
	var y3 = (lineLength-rTemp-angleLength)/lineLength*(endNode.y-startNode.y)+startNode.y;//交点的y值
	var intersection = {x:x3,y:y3};//垂线与直线交点
	var k = 1/lineK;//正交线斜率 垂线y=kx+b
	var b = y3-k*x3;//求出直线偏移
	*/
	

	//以x2 和y2为起点,左右各成一定角度画箭头
	ctx.save();//入栈
	
	ctx.beginPath();
	ctx.strokeStyle="gray";
	
	ctx.moveTo(x2,y2);
	ctx.lineTo(x4,y4);
	ctx.moveTo(x2,y2);
	ctx.lineTo(x5,y5);
	ctx.closePath();
	ctx.stroke();
	ctx.restore();//出栈

}
//求两个点之间的距离
function distance(start,end){
	return Math.sqrt(Math.pow((start.x - end.x),2)+Math.pow((start.y - end.y),2));
}
	
processCanvas.οnmοusedοwn=function (e) {
	console.log("οnmοusedοwn");
	processCanvas.onmousemove = function(e){
	console.log("onmousemove");
		 var x = e.clientX;
		 var y = e.clientY;
		console.log("x="+x);
	};

	processCanvas.onmouseup = function(){
		//canva.onmousemove = null;
		//canva.onmouseup = null;
	};
}

getMaxPath();
function getMaxPath(){
	var pathArr = [];
	for(var i in onlyStartNodes){
		var startNode = onlyStartNodes[i];
		var pathTemp = [];
		var result = []
		getPath(startNode,pathTemp,result);
		console.log(result);
	}
}
function getPath(startNode,prePath,result){
	for(var i in lines){
		if(lines[i].beginNodeId == startNode.id){
			prePath.push(startNode);
			result.push(prePath);
			startNode = allNodesArr.find(function(node){
				return node.id == lines[i].endNodeId;
			})
			getPath(startNode,prePath,result);
		}
	}
}
</script>
<style>
.front-arrow{
	position:absolute;
    right: -5px;
	bottom:0px;
    width: 10px;
    height: 10px;
    border: 1px solid black;
    border-top: none;
    border-right: none;
    transform: rotate(-45deg);
	}
.back-arrow{
	position:absolute;
    top: 0px;
	left:-5px;
    width: 10px;
    height: 10px;
    border: 1px solid black;
    border-top: none;
    border-right: none;
    transform: rotate(135deg);
}
.edge-front{
	position:absolute;
	border-top:1px solid;
	border-left:1px solid;
	border-right:1px solid;
}
.edge-back{
	position:absolute;
	border-bottom:1px solid;
	border-left:1px solid;
	border-right:1px solid;
}
.drawing-line{
	display:flex;
	position:absolute;
}
.drawing-block{
	width:60px;
	height:60px;
	border:1px solid #CCC;
	border-radius: 30px;
    line-height: 60px;
    text-align: center;
	margin: 9px;
	background-color:#4ff181;
}
.graph-line{
	display:flex;
}
.graph-block{
	width:60px;
	text-align: center;
	border-bottom: 1px solid #CCC;
	border-right: 1px solid #CCC;
    height: 40px;
    line-height: 40px;
}
.target-node{
	background-color:red;
	height: 200px;
    line-height: 20px;
}
.source-node{
	background-color:green;
	width: 240px;
    font-size: 12px;
}
</style>

 

上一篇:​【路径规划】基于蚁群算法求解带时间窗车辆路径问题(VRPTW)matlab代码


下一篇:安装hive使用mysql作为元数据遇到的一些问题