之前在想如何使用Javascript实现时钟的时候,被一个问题难到了:如何在像素级别绘制平滑的直线。
在网上查了一下,后来在图书馆里的一本关于计算机图形学的老书里发现了解决方案。针对这个问题,书上提供了三个算法,分别是简单DDA,对称DDA,Bresenham算法。
下面的是我使用简单DDA和Bresenham算法在浏览器上绘制Hello world的代码。
这里的Hello world 分别是定义了字母的一些”节点“,然后使用连线算法绘制出来的。
代码:
- //构造画布,使用DOM动态生成表格
- var_container=document.getElementById("container");
- varpixs=newArray();
- varcanvasTbody=document.createElement("tbody");
- varbgColor="black";
- varfontColor="green";
- varpix_size="4px";
- varpix_numbs=81;
- vartemp_tr;
- vartemp_td;
- vartemp_pixrow;
- for(vari=pix_numbs;i>=0;i--){
- temp_tr=document.createElement("tr");
- temp_tr.style.height=pix_size;
- temp_pixrow=newArray();
- for(varj=0;j<=pix_numbs;j++){
- temp_td=document.createElement("td");
- temp_td.style.width=pix_size;
- temp_td.style.backgroundColor=bgColor;
- temp_tr.appendChild(temp_td);
- temp_pixrow[j]=temp_td;
- }
- canvasTbody.appendChild(temp_tr);
- pixs[i]=temp_pixrow;
- }
- varcanvasTable=document.createElement("table");
- canvasTable.style.backgroundColor="black";
- canvasTable.setAttribute("cellspacing","0");
- canvasTable.setAttribute("cellpadding","0");
- canvasTable.appendChild(canvasTbody);
- _container.appendChild(canvasTable);
- //点类,包含坐标信息,有绘制和比较操作
- functionpoint(_x,_y){
- this.x=_x;
- this.y=_y;
- }
- function_draw(){
- if(this.x>pix_numbs||this.y>pix_numbs){
- return;
- }
- pixs[this.y][this.x].style.backgroundColor=fontColor;
- }
- point.prototype.draw=_draw;
- function_equal(_p){
- if(!_pinstanceofpoint){
- thrownewError();
- }
- if(this.x==_p.x&&this.y==_p.y){
- returntrue;
- }else{
- returnfalse;
- }
- }
- point.prototype.equal=_equal;
- //简单DDA算法构造直线
- functionDDA_line(_p1,_p2){
- varx1;
- vary1;
- varx2;
- vary2;
- var_x;
- var_y;
- var_p;
- vark;
- varb;
- if(_p1instanceofpoint&&_p2instanceofpoint){
- }else{
- return;
- }
- if(_p1.equal(_p2)){
- return;
- }
- if(_p1.x>_p2.x){
- x1=_p2.x;
- y1=_p2.y;
- x2=_p1.x;
- y2=_p1.y;
- }elseif(_p1.x<_p2.x){
- x1=_p1.x;
- y1=_p1.y;
- x2=_p2.x;
- y2=_p2.y;
- }elseif(_p1.x==_p2.x){
- if(_p1.y>_p2.y){
- x1=_p2.x;
- y1=_p2.y;
- x2=_p1.x;
- y2=_p1.y;
- }else{
- x1=_p1.x;
- y1=_p1.y;
- x2=_p2.x;
- y2=_p2.y;
- }
- }
- if(x1==x2){
- _x=x1;
- _y=y1;
- for(;_y!=y2;_y++){
- _p=newpoint(_x,_y);
- _p.draw();
- }
- }else{
- k=(y2-y1)/(x2-x1);
- b=y1-(k*x1);
- if(Math.abs(k)<=1){
- _x=x1;
- for(;_x!=x2;_x++){
- _y=(k*_x)+b;
- _y=Math.round(_y);
- _p=newpoint(_x,_y);
- _p.draw();
- }
- }else{
- _y=y1;
- while(_y!=y2){
- _x=(_y-b)/k;
- _x=Math.round(_x);
- _p=newpoint(_x,_y);
- _p.draw();
- if(y2>y1){
- _y++;
- }else{
- _y--;
- }
- }
- }
- }
- }
- //Bresenham算法构造直线
- functionBresenham_line(_p1,_p2){
- varx1;
- vary1;
- varx2;
- vary2;
- var_x;
- var_y;
- var_p;
- vark;
- vard;
- if(_p1instanceofpoint&&_p2instanceofpoint){
- }else{
- return;
- }
- if(_p1.equal(_p2)){
- return;
- }
- if(_p1.x>_p2.x){
- x1=_p2.x;
- y1=_p2.y;
- x2=_p1.x;
- y2=_p1.y;
- }elseif(_p1.x<_p2.x){
- x1=_p1.x;
- y1=_p1.y;
- x2=_p2.x;
- y2=_p2.y;
- }elseif(_p1.x==_p2.x){
- if(_p1.y>_p2.y){
- x1=_p2.x;
- y1=_p2.y;
- x2=_p1.x;
- y2=_p1.y;
- }else{
- x1=_p1.x;
- y1=_p1.y;
- x2=_p2.x;
- y2=_p2.y;
- }
- }
- if(x1==x2){
- _x=x1;
- _y=y1;
- for(;_y!=y2;_y++){
- _p=newpoint(_x,_y);
- _p.draw();
- }
- }else{
- k=(y2-y1)/(x2-x1);
- _x=x1;
- _y=y1;
- if(k>=0&&k<=1){
- d=2*(y2-y1)-(x2-x1);
- while(_x!=x2){
- if(d>=0){
- _y++;
- d=d-2*(x2-x1);
- }
- _p=newpoint(_x,_y);
- _p.draw();
- _x++;
- d=d+2*(y2-y1);
- }
- }elseif(k>1){
- d=2*(x2-x1)-(y2-y1);
- while(_y!=y2){
- if(d>=0){
- _x++;
- d=d-2*(y2-y1);
- }
- _p=newpoint(_x,_y);
- _p.draw();
- _y++;
- d=d+2*(x2-x1);
- }
- }elseif(k<0&&k>=-1){
- d=2*(y2-y1)+(x2-x1);
- while(_x!=x2){
- if(d<=0){
- _y--;
- d=d+2*(x2-x1);
- }
- _p=newpoint(_x,_y);
- _p.draw();
- _x++;
- d=d+2*(y2-y1);
- }
- }elseif(k<-1){
- d=2*(x2-x1)+(y2-y1);
- while(_y!=y2){
- if(d>=0){
- _x++;
- d=d-2*(y1-y2);
- }
- _p=newpoint(_x,_y);
- _p.draw();
- _y--;
- d=d+2*(x2-x1);
- }
- }
- }
- }
- //绘制X
- varx1=newpoint(5,60);
- x1.draw();
- varx2=newpoint(77,60);
- x2.draw();
- varx3=newpoint(5,25);
- x3.draw();
- varx4=newpoint(77,25);
- x4.draw();
- Bresenham_line(x1,x4);
- Bresenham_line(x2,x3);
- //绘制HELLOWORLD
- varp1=newpoint(5,20);
- p1.draw();
- varp2=newpoint(5,15);
- p2.draw();
- varp3=newpoint(5,10);
- p3.draw();
- varp4=newpoint(10,20);
- p4.draw();
- varp5=newpoint(10,15);
- p5.draw();
- varp6=newpoint(10,10);
- p6.draw();
- DDA_line(p1,p3);
- DDA_line(p2,p5);
- DDA_line(p4,p6);
- p1=newpoint(12,20);
- p1.draw();
- p2=newpoint(12,15);
- p2.draw();
- p3=newpoint(12,10);
- p3.draw();
- p4=newpoint(17,20);
- p4.draw();
- p5=newpoint(17,15);
- p5.draw();
- p6=newpoint(17,10);
- p6.draw();
- DDA_line(p1,p3);
- DDA_line(p1,p4);
- DDA_line(p2,p5);
- DDA_line(p3,p6);
- p1=newpoint(19,20);
- p1.draw();
- p2=newpoint(19,10);
- p2.draw();
- p3=newpoint(24,10);
- p3.draw();
- DDA_line(p1,p2);
- DDA_line(p2,p3);
- p1=newpoint(26,20);
- p1.draw();
- p2=newpoint(26,10);
- p2.draw();
- p3=newpoint(31,10);
- p3.draw();
- DDA_line(p1,p2);
- DDA_line(p2,p3);
- p1=newpoint(33,20);
- p1.draw();
- p2=newpoint(33,10);
- p2.draw();
- p3=newpoint(38,20);
- p3.draw();
- p4=newpoint(38,10);
- p4.draw();
- DDA_line(p1,p2);
- DDA_line(p3,p4);
- DDA_line(p1,p3);
- DDA_line(p2,p4);
- p1=newpoint(45,20);
- p1.draw();
- p2=newpoint(45,10);
- p2.draw();
- p3=newpoint(47,15);
- p3.draw();
- p4=newpoint(49,10);
- p4.draw();
- p5=newpoint(49,20);
- p5.draw();
- DDA_line(p1,p2);
- DDA_line(p2,p3);
- DDA_line(p3,p4);
- DDA_line(p4,p5);
- p1=newpoint(51,20);
- p1.draw();
- p2=newpoint(51,10);
- p2.draw();
- p3=newpoint(56,20);
- p3.draw();
- p4=newpoint(56,10);
- p4.draw();
- DDA_line(p1,p2);
- DDA_line(p3,p4);
- DDA_line(p1,p3);
- DDA_line(p2,p4);
- p1=newpoint(58,20);
- p1.draw();
- p2=newpoint(58,16);
- p2.draw();
- p3=newpoint(58,10);
- p3.draw();
- p4=newpoint(63,20);
- p4.draw();
- p5=newpoint(63,16);
- p5.draw();
- p6=newpoint(63,10);
- p6.draw();
- DDA_line(p1,p3);
- DDA_line(p1,p4);
- DDA_line(p4,p5);
- DDA_line(p2,p5);
- DDA_line(p2,p6);
- p1=newpoint(65,20);
- p1.draw();
- p2=newpoint(65,10);
- p2.draw();
- p3=newpoint(70,10);
- p3.draw();
- DDA_line(p1,p2);
- DDA_line(p2,p3);
- p1=newpoint(72,20);
- p1.draw();
- p2=newpoint(72,10);
- p2.draw();
- p3=newpoint(77,20);
- p3.draw();
- p4=newpoint(77,14);
- p4.draw();
- DDA_line(p1,p2);
- DDA_line(p3,p4);
- DDA_line(p1,p3);
- DDA_line(p2,p4);
使用方法是在网页中建一个id为”container“的容器,可以是”div“标签
然后把Javascript文件链接进来。即可。
说明:在IE中测试时,有点丑陋。是因为我不知道在IE中使用Javascript动态生成的tbody标签中的单元格之间的间距如何控制。
其他浏览器均可以正常显示。