利用canvas实现的中点Bresenham算法

Bresenham提出的直线生成算法的基本原理是,每次在最大位移方向上走一步,而另一个方向是走步还是不走步取决于误差项的判别,具体的实现过程大家可以去问度娘。我主要是利用canvas画布技术实现了这个过程,算法可能还是有点小问题,欢迎大家给我留言建议,一定虚心接受。

    <!DOCTYPE html>
    <html lang="en">
    <head>
	<meta charset="UTF-8">
	<title>中点Bresenham算法</title>
	<style>
	    * {
	    	margin: 0;
	    	padding: 0;
	    }
	    body {
	        font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei UI", "Microsoft YaHei", SimHei, "\5B8B\4F53", simsun, sans-serif;
	        color: #555;
	    }
		.left {
			float: left;
			margin: 20px 0 0 calc((100% - 401px - 602px)/2);
			 400px;
			height: 600px;
			border: 1px solid #cccccc;
			border-right: none; 
		}
		.left header {
			margin: 0 10px;
			-webkit-box-sizing: border-box;
			-moz-box-sizing: border-box;
			box-sizing: border-box;
			height: 60px;
			line-height: 60px;
			font-size: 18px;
			/*text-align: center;*/
			border-bottom: 2px solid #aaa;
		}
		.start {
			margin: 0 25px;
			line-height: 80px;
			/*text-align: center;*/
		}
		.left input[type="text"] {
			padding: 2px 5px;
			 30px;
			-webkit-box-sizing: border-box;
			-moz-box-sizing: border-box;
			box-sizing: border-box;
			background-color: #f5f5f5;
			border: 1px solid #cccccc;
		}
		button {
			border: none;
			display: inline-block;
			outline: 0;
			padding: 6px 16px;
			margin-bottom: 10px;
			vertical-align: middle;
			overflow: hidden;
			text-decoration: none;
			color: #fff;
			background-color: #F88E8B;
			text-align: center;
			transition: .2s ease-out;
			cursor: pointer;
			white-space: nowrap;
			box-shadow: 0px 1px 3px rgba(0,0,0,0.12), 0px 1px 2px rgba(0,0,0,0.24);
		}
		button:hover {
			background-color: #F35F5C;
		}
		#stroke {
			margin-left: 25px;
		}
		#reset {
			margin-left: 10px;
		}
		/*.left button {
			display: block;
			margin: 0 auto;
		}*/
		#xy {
			/*display: none;*/
		}
		.left p {
			line-height: 40px;
			text-align: center;
		}
		.table {
			position: relative;
			padding-top: 30px;
			max-height: 373px;
			overflow-y: auto;
			-webkit-box-sizing: border-box;
			-moz-box-sizing: border-box;
			box-sizing: border-box;
		}
		#thead {
			position: absolute;
			z-index: 999;
			 370px;
			margin-left: 10px;
		}
		.left table {
			margin: 0 0 10px 10px;
			 370px;
			border-collapse:collapse;
		}
		.left table th{
			 33.3333%;
			height: 30px;
			border: 1px solid #cccccc;
			background-color: #f1f1f1;
		}
		.left table td{
			 33.3333%;
			height: 30px;
			text-align: center;
			border: 1px solid #cccccc;
		}
		#myCanvas {
			display: block;
			float: left;
			margin-top: 20px;
			background-color: #fffdf6;
			border: 1px solid #cccccc;
		}
	</style>
    </head>
    <body>
	<div class="left" id="left">
		<header>&nbsp;&nbsp;中点 <strong>Bresenham</strong> 算法</header>
		<div class="start">
			直线方程 : 
			<input type="text" id="A" required autocomplete="off"> x + <input type="text" id="B" required autocomplete="off"> y + <input type="text" id="C" required autocomplete="off"> = 0
		</div>
		<button id="stroke">开始绘制</button>
		<button id="reset">重置</button>
		
		<div id="xy" style="display: none;">
			<p><strong>坐标值</strong></p>
			<table id="thead">
				<tr>
					<th> X </th>
					<th> Y </th>
					<th> d </th>
				</tr>
			</table>
			<div class="table">
				<table id="table">
					<!-- <tr>
						<th> X </th>
						<th> Y </th>
						<th> d </th>
					</tr> -->
				</table>
			</div>
		</div>
		
	</div>
	<canvas id="myCanvas" width="600" height="600">
		您的浏览器不支持canvas,请升级浏览器!
	</canvas>

	<script>

		//*-----------------canvas画坐标表格---------------------*
		var canvas=document.getElementById("myCanvas");
		var context=canvas.getContext("2d");

		function drowAxes() {
			// 描绘边框
			var grid_cols = 20;
			var grid_rows = 20;
			var cell_height = canvas.height / grid_rows;
			var cell_width = canvas.width / grid_cols;
			context.lineWidth = 1;
			context.strokeStyle = "#cccccc";

			// 结束边框描绘
			context.beginPath();
			// 准备画横线
			for (var col = 1; col <= grid_cols; col++) {
			  var x = col * cell_width;
			  if(col == 10) {
			  	context.beginPath();
			  	context.strokeStyle = "#2FB9D6";
			  	context.moveTo(x+0.5,0);
			  	context.lineTo(x+0.5,canvas.height);
			  	context.stroke();
			  }
			  else {
			  	context.beginPath();
			  	context.strokeStyle = "#cccccc";
			  	context.moveTo(x+0.5,0);
			  	context.lineTo(x+0.5,canvas.height);
			  	context.stroke();
			  }
			}
			//准备画竖线
			for(var row = 1; row <= grid_rows; row++){
			  var y = row * cell_height;
			  if(row == 10) {
			  	context.beginPath();
			  	context.strokeStyle = "#2FB9D6";
			  	context.moveTo(0,y+0.5);
			  	context.lineTo(canvas.width, y+0.5);
			  	context.stroke();
			  }
			  else {
			  	context.beginPath();
			  	context.strokeStyle = "#cccccc";
			  	context.moveTo(0,y+0.5);
			    context.lineTo(canvas.width, y+0.5);
			  	context.stroke();
			  }
			}
			context.stroke();

			//给坐标轴加刻度
			for(var i=0;i <= grid_cols;i++) {
				var x = i * cell_width;
				context.font="13px Arial";
				context.fillStyle="#000";
				context.fillText(-10+i,5 + x,315);
			}
			for(var i=0;i <= grid_rows;i++) {
				var y = i * cell_height;
				context.font="13px Arial";
				context.fillStyle="#000";
				context.fillText(10-i,305,15 + y);
			}
		}

		//坐标生成及Canvas画点函数
		function drawDot(x,y,d) {
			var tr=document.createElement("tr");
			var td1=document.createElement("td");
			var node1=document.createTextNode(" "+Math.round(x)+" ");
			td1.appendChild(node1);
			tr.appendChild(td1);

			var td2=document.createElement("td");
			var node2=document.createTextNode(" "+Math.round(y)+" ");
			td2.appendChild(node2);
			tr.appendChild(td2);

			var td3=document.createElement("td");
			var node3=document.createTextNode(" "+d.toFixed(2)+" ");
			td3.appendChild(node3);
			tr.appendChild(td3);

			document.getElementById("table").appendChild(tr);

			//坐标处理
			var X,Y;
			X= Math.round(x)*30;
			Y=- Math.round(y)*30;
			//表格中绘制坐标点
			context.fillStyle="#2FB9D6";
			context.beginPath();
			context.arc(X,Y,4,0,Math.PI*2,true);
			context.closePath();
			context.fill();
		}
	    
	    //判断输入的字符是否为整数    
	    function IsInteger()     
	    {       
	            var str1 = document.getElementById('A').value.trim();    
	            var str2 = document.getElementById('B').value.trim();    
	            var str3 = document.getElementById('C').value.trim();    
	            if(str1.length!=0 && str2.length!=0 && str3.length!=0){    
		            reg=/^[-+]?\d*$/;     
		            if(!reg.test(str1) || !reg.test(str2) || !reg.test(str3)){    
		                alert("对不起,请输入整数!");//请将“整数类型”要换成你要验证的那个属性名称! 
		                return false;   
		            } 
		            else {return true;}   
	            }    
	    } 

		window.onload = drowAxes();
		var canvas_flag=0;//设置是否画线的标记变量

		//*-----------------中点Bresenham算法求坐标--------------------*
		document.getElementById("stroke").onclick=function Bresenham(){
			var xy=document.getElementById("xy");

			var A=document.getElementById("A").value;
			var B=document.getElementById("B").value;
			var C=document.getElementById("C").value;

			if(A.length == 0 || B.length == 0 || C.length == 0) {alert("请填写直线方程的系数!")}
			//直线上取两个点
			if(xy.style.display === 'none' && A.length != 0 && B.length != 0 && C.length != 0 && IsInteger()) {
				if(A==0 && B==0 && C!=0) {alert("输入错误,请重新输入!");}
				else if(A==0 && B==0 && C==0) {alert("输入数据不能全部为0!")}
				else if(A==0 && B!=0) { //y=c 类方程
					context.translate(300,300);//将坐标原点移到(300,300)处
					
					//绘制直线
					var c=-Math.round(C/B)*30;
					context.beginPath();
					context.strokeStyle="#2FB9D6";
					context.moveTo(-300,c);
					context.lineTo(300,c);
					context.closePath();
					context.stroke();

					canvas_flag=1;//标记变量置1

				}
				else if(A!=0 && B==0) { //x=c 类方程
					context.translate(300,300);//将坐标原点移到(300,300)处
					
					//绘制直线
					var c=-Math.round(C/A)*30;
					context.beginPath();
					context.strokeStyle="#2FB9D6";
					context.moveTo(c,-300);
					context.lineTo(c,300);
					context.closePath();
					context.stroke();

					canvas_flag=1;//标记变量置1

				}
				else if(-A/B>=0){  //斜率大于等于0的情况
					xy.style.display = 'block';
					var x0,y0,x1,y1;
					var vx,vy;
					var d; //增长量
					var m,n; //循环变量
					var x,y;

					var k = -A/B;
					if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
						x0 = -5;x1 = 5;
						y0 = (-C -A*x0)/B;
						y1 = (-C -A*x1)/B;
						vx = x1 - x0,vy = y1 - y0;
						x = x0,y = y0;
						n = x0;
						m = x1;
						d = vx - 2*vy; //初始化d
					}
					else if(k>1) { //k大于1的情况 
						y0 = -5;y1 = 5;
						x0 = (-C -B*y0)/A;
						x1 = (-C -B*y1)/A;
						vx = x1 - x0,vy = y1 - y0;
						x = x0,y = y0;
						n = y0;
						m = y1;
						d = 2*vx - vy; //初始化d
					}
					context.translate(300,300);//将坐标原点移到(300,300)处
					for(var i=n;i<=m;i++) {

						//----------------算法核心代码---------------
						if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
							drawDot(x,y,d);
							if(d<0) {
								x = x + 1;
								y = y + 1;
								d = d + 2*vx - 2*vy;
							}
							else {
								x = x + 1;
								y = y;
								d = d - 2*vy;
							}
						}
						else if(k>1) { //k大于1的情况
							drawDot(x,y,d);
							if(d<0) {
								x = x;
								y = y + 1;
								d = d + 2*vx;
							}
							else {
								x = x + 1;
								y = y + 1;
								d = d - 2*vy + 2*vx;
							} 
						}
						
					}
					//绘制直线
					var X0,Y0,X1,Y1;
					X0= Math.round(x0)*30;
					Y0=-Math.round(y0)*30;
					X1=Math.round(x1)*30;
					Y1=-Math.round(y1)*30;
					context.beginPath();
					context.strokeStyle="#2FB9D6";
					context.moveTo(X0,Y0);
					context.lineTo(X1,Y1);
					context.closePath();
					context.stroke();

					canvas_flag=1;//标记变量置1
				}
				else if(-A/B<0){ //斜率小于0的情况
					//将直线转化为斜率大于等于0的情况,然后求关于x轴对称的直线就行
					xy.style.display = 'block';
					A = -A; 
					var x0,y0,x1,y1;
					var vx,vy;
					var d; //增长量
					var m,n; //循环变量
					var x,y;

					var k = -A/B;
					if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
						x0 = -5;x1 = 5;
						y0 = (-C -A*x0)/B;
						y1 = (-C -A*x1)/B;
						vx = x1 - x0,vy = y1 - y0;
						x = x0,y = y0;
						n = x0;
						m = x1;
						d = vx - 2*vy; //初始化d
					}
					else if(k>1) { //k大于1的情况 
						y0 = -5;y1 = 5;
						x0 = (-C -B*y0)/A;
						x1 = (-C -B*y1)/A;
						vx = x1 - x0,vy = y1 - y0;
						x = x0,y = y0;
						n = y0;
						m = y1;
						d = 2*vx - vy; //初始化d
					}
					context.translate(300,300);//将坐标原点移到(300,300)处
					for(var i=n;i<=m;i++) {

						//----------------算法核心代码---------------
						if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
							drawDot(-x,y,d);
							if(d<0) {
								x = x + 1;
								y = y + 1;
								d = d + 2*vx - 2*vy;
							}
							else {
								x = x + 1;
								y = y;
								d = d - 2*vy;
							}
						}
						else if(k>1) { //k大于1的情况
							drawDot(-x,y,d);
							if(d<0) {
								x = x;
								y = y + 1;
								d = d + 2*vx;
							}
							else {
								x = x + 1;
								y = y + 1;
								d = d - 2*vy + 2*vx;
							} 
						}
						
					}
					//绘制直线
					var X0,Y0,X1,Y1;
					X0= Math.round(-x0)*30;
					Y0=-Math.round(y0)*30;
					X1=Math.round(-x1)*30;
					Y1=-Math.round(y1)*30;
					context.beginPath();
					context.strokeStyle="#2FB9D6";
					context.moveTo(X0,Y0);
					context.lineTo(X1,Y1);
					context.closePath();
					context.stroke();

					canvas_flag=1;//标记变量置1
				}
			}
			
		};

		//重新绘制
		document.getElementById("reset").onclick=function reset(){

			var A=document.getElementById("A").value;
			var B=document.getElementById("B").value;
			var C=document.getElementById("C").value;
			if(A.length == 0 && B.length == 0 && C.length == 0) {alert("没有输入数据!")}
			else {
				//清空input输入框
				document.getElementById("A").value="";
				document.getElementById("B").value="";
				document.getElementById("C").value="";
			}
			if(canvas_flag==1) {
				context.clearRect(-300,-300,600,600); //清空画布
				context.translate(-300,-300); //将坐标原点还原
				drowAxes(); //重绘坐标轴

				canvas_flag=0;
			}
			if(document.getElementById("xy").style.display === 'block') {
				document.getElementById("xy").style.display = 'none';

				var table = document.getElementById("table");
			    while(table.hasChildNodes()) //当table下还存在子节点时 循环继续
			    {
			        table.removeChild(table.firstChild);
			    }
			}
		};

	    </script> 
        </body>
        </html>
原文地址:https://www.cnblogs.com/sunmaer/p/6014121.html