JS 绘图类(纯DIV绘图)
很早之前写的一个绘图类,那时候VML和SVG的图库还不是十分流行,最初的灵感以及图形算法来自一个叫w_jsGraphics.js的类库。
用一个点来绘制出世界。甚以此纪念那段充满激情的岁月。
?
/** *JS 绘图类 Graphics- 0.02 *@author <a href="mailto: redrainyi@gmail.com">yyl</a> *@param canvas 画布(画布可以是 DIV(IE) 或 Layer(Netscape) *参考资料《w_jsGraphics.js绘图类》《DHTML手册》《BISOFT JS》《Computer Graphics》 *CopyLeft 2007 在引用或转载时请保持文件代码的完整性 */function Graphics(canvas){/*获得画板以后的绘图都是在画板上实现*/this.canvas = typeof(canvas)=="string"?document.getElementById(canvas):canvas;/*默认颜色 #000000黑色*/this.color = '#000000';/*设置线默认象素为 1px*/this.setStroke(1);/*文本默认字体*/this.setFont('verdana,geneva,helvetica,sans-serif', 20, "PLAIN");/*创建一个Div元素作为根结点 所有绘图的根结点*/this.documentRoot = document.createElement("div");}Graphics.prototype = {canvas : window,color : '#000000',stroke : 1,documentRoot : null,/*设置颜色 格式"#RRGGBB" 颜色会保留到下一次再重新设置为止*/setColor : function(c){this.color = c;},/*绘制点DIV*/drawDiv : function(x, y, w, h){var elem = document.createElement("div");/*创建一个Div元素*/elem.style.position = 'absolute';elem.style.overflow = 'hidden';elem.style.left = x;elem.style.top = y;elem.style.width = w;elem.style.height = h ;elem.style.backgroundColor = this.color;this.documentRoot.appendChild(elem);},/*绘制组件 (绘图)*/paint : function(){this.canvas.appendChild(this.documentRoot);/*将根结点添加到画布上*/},/*清空画板*/clear : function(){if (this.canvas) this.canvas.innerHTML = '';},/*设置画笔 参数代表点(象素)大小 默认是 1px (设置为-1时候代表 虚点线)*/setStroke : function(x){this.stroke = x;if (!(x+1))/*javaScript中 0为假 */{/*设置画法为虚点*/this.drawLine = this.drawLineDott;this.drawOval = this.drawOvalDott;this.drawRect = this.drawRectangleDott;}else if (x > 1){/*实线*/this.drawLine = this.drawLine2D;this.drawOval = this.drawOval2D;this.drawRect = this.drawRectangle;}else{/*/象素大小(厚度)为1px的线*/this.drawLine = this.drawLine1D;this.drawOval = this.drawOval1D;this.drawRect = this.drawRectangle;}},/*画虚线*/drawLineDott : function(x1, y1, x2, y2){if (x1 > x2){var _x2 = x2;var _y2 = y2;x2 = x1;y2 = y1;x1 = _x2;y1 = _y2;}var dx = x2-x1, dy = Math.abs(y2-y1),x = x1, y = y1,yIncr = (y1 > y2)? -1 : 1,drw = true;if (dx >= dy){var pr = dy<<1,pru = pr - (dx<<1),p = pr-dx;while ((dx--) > 0){if (drw) this.drawDiv(x, y, 1, 1);drw = !drw;if (p > 0){y += yIncr;p += pru;}else p += pr;++x;}if (drw) this.drawDiv(x, y, 1, 1);}else{var pr = dx<<1,pru = pr - (dy<<1),p = pr-dy;while ((dy--) > 0){if (drw) this.drawDiv(x, y, 1, 1);drw = !drw;y += yIncr;if (p > 0){++x;p += pru;}else p += pr;}if (drw) this.drawDiv(x, y, 1, 1);}},/*画线(经过优化的绘线方法)*/drawLine2D : function(x1, y1, x2, y2){if (x1 > x2){var _x2 = x2;var _y2 = y2;x2 = x1;y2 = y1;x1 = _x2;y1 = _y2;}var dx = x2-x1, dy = Math.abs(y2-y1),x = x1, y = y1,yIncr = (y1 > y2)? -1 : 1;var s = this.stroke;if (dx >= dy){if (dx > 0 && s-3 > 0){var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;}else var _s = s;var ad = Math.ceil(s/2);var pr = dy<<1,pru = pr - (dx<<1),p = pr-dx,ox = x;while ((dx--) > 0){++x;if (p > 0){this.drawDiv(ox, y, x-ox+ad, _s);y += yIncr;p += pru;ox = x;}else p += pr;}this.drawDiv(ox, y, x2-ox+ad+1, _s);}else{if (s-3 > 0){var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;}else var _s = s;var ad = Math.round(s/2);var pr = dx<<1,pru = pr - (dy<<1),p = pr-dy,oy = y;if (y2 <= y1){++ad;while ((dy--) > 0){if (p > 0){this.drawDiv(x++, y, _s, oy-y+ad);y += yIncr;p += pru;oy = y;}else{y += yIncr;p += pr;}}this.drawDiv(x2, y2, _s, oy-y2+ad);}else{while ((dy--) > 0){y += yIncr;if (p > 0){this.drawDiv(x++, oy, _s, y-oy+ad);p += pru;oy = y;}else p += pr;}this.drawDiv(x2, oy, _s, y2-oy+ad+1);}}},/*画线(象素大小为1的线 参考Bresenham算法)*/drawLine1D : function(x1, y1, x2, y2){if (x1 > x2){var _x2 = x2;var _y2 = y2;x2 = x1;y2 = y1;x1 = _x2;y1 = _y2;}var dx = x2-x1, dy = Math.abs(y2-y1),x = x1, y = y1,yIncr = (y1 > y2)? -1 : 1;if (dx >= dy){var pr = dy<<1,pru = pr - (dx<<1),p = pr-dx,ox = x;while ((dx--) > 0){++x;if (p > 0){this.drawDiv(ox, y, x-ox, 1);y += yIncr;p += pru;ox = x;}else p += pr;}this.drawDiv(ox, y, x2-ox+1, 1);}else{var pr = dx<<1,pru = pr - (dy<<1),p = pr-dy,oy = y;if (y2 <= y1){while ((dy--) > 0){if (p > 0){this.drawDiv(x++, y, 1, oy-y+1);y += yIncr;p += pru;oy = y;}else{y += yIncr;p += pr;}}this.drawDiv(x2, y2, 1, oy-y2+1);}else{while ((dy--) > 0){y += yIncr;if (p > 0){this.drawDiv(x++, oy, 1, y-oy);p += pru;oy = y;}else p += pr;}this.drawDiv(x2, oy, 1, y2-oy+1);}}},/*圆弧 八个对称点的算法*/drawCirclePoints : function(cx, cy, xl, xr, yt, yb, w, h){this.drawDiv(xr+cx, yt+cy, w, h);this.drawDiv(xr+cx, yb+cy, w, h);this.drawDiv(xl+cx, yb+cy, w, h);this.drawDiv(xl+cx, yt+cy, w, h);},/*圆形(椭圆形 卵形)*/drawOval2D : function(left, top, width, height){var s = this.stroke;width += s-1;height += s-1;var a = width>>1, b = height>>1,wod = width&1, hod = (height&1)+1,cx = left+a, cy = top+b,x = 0, y = b,aa = (a*a)<<1, bb = (b*b)<<1,st = (aa>>1)*(1-(b<<1)) + bb,tt = (bb>>1) - aa*((b<<1)-1);if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0)){var ox = 0, oy = b,w, h,pxl, pxr, pxt, pxb, pxw;while (y > 0){if (st < 0){st += bb*((x<<1)+3);tt += (bb<<1)*(++x);}else if (tt < 0){st += bb*((x<<1)+3) - (aa<<1)*(y-1);tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);w = x-ox;h = oy-y;if (w-1){pxw = w+1+(s&1);h = s;}else if (h-1){pxw = s;h += 1+(s&1);}else pxw = h = s;this.drawCirclePoints(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);ox = x;oy = y;}else{tt -= aa*((y<<1)-3);st -= (aa<<1)*(--y);}}this.drawDiv(cx-a, cy-oy, s, (oy<<1)+hod);this.drawDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);}else{var _a = (width-((s-1)<<1))>>1,_b = (height-((s-1)<<1))>>1,_x = 0, _y = _b,_aa = (_a*_a)<<1, _bb = (_b*_b)<<1,_st = (_aa>>1)*(1-(_b<<1)) + _bb,_tt = (_bb>>1) - _aa*((_b<<1)-1),pxl = new Array(),pxt = new Array(),_pxb = new Array();pxl[0] = 0;pxt[0] = b;_pxb[0] = _b-1;while (y > 0){if (st < 0){st += bb*((x<<1)+3);tt += (bb<<1)*(++x);pxl[pxl.length] = x;pxt[pxt.length] = y;}else if (tt < 0){st += bb*((x<<1)+3) - (aa<<1)*(y-1);tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);pxl[pxl.length] = x;pxt[pxt.length] = y;}else{tt -= aa*((y<<1)-3);st -= (aa<<1)*(--y);}if (_y > 0){if (_st < 0){_st += _bb*((_x<<1)+3);_tt += (_bb<<1)*(++_x);_pxb[_pxb.length] = _y-1;}else if (_tt < 0){_st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);_tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);_pxb[_pxb.length] = _y-1;}else{_tt -= _aa*((_y<<1)-3);_st -= (_aa<<1)*(--_y);_pxb[_pxb.length-1]--;}}}var ox = 0, oy = b,_oy = _pxb[0],l = pxl.length,w, h;for (var i = 0; i < l; i++){if (typeof _pxb[i] != "undefined"){if (_pxb[i] < _oy || pxt[i] < oy){x = pxl[i];this.drawCirclePoints(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);ox = x;oy = pxt[i];_oy = _pxb[i];}}else{x = pxl[i];this.drawDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);this.drawDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);ox = x;oy = pxt[i];}}this.drawDiv(cx-a, cy-oy, 1, (oy<<1)+hod);this.drawDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);}},/*线象素为1 的圆形*/drawOval1D : function(x1, y1, w1, h1){var a = w1>>1, b = h1>>1,wod = w1&1, hod = (h1&1)+1,cx = x1+a, cy = y1+b,x = 0, y = b,ox = 0, oy = b,aa = (a*a)<<1, bb = (b*b)<<1,st = (aa>>1)*(1-(b<<1)) + bb,tt = (bb>>1) - aa*((b<<1)-1),w, h;while (y > 0){if (st < 0){st += bb*((x<<1)+3);tt += (bb<<1)*(++x);}else if (tt < 0){st += bb*((x<<1)+3) - (aa<<1)*(y-1);tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);w = x-ox;h = oy-y;if (w&2 && h&2){this.drawCirclePoints(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);this.drawCirclePoints(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);}else this.drawCirclePoints(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);ox = x;oy = y;}else{tt -= aa*((y<<1)-3);st -= (aa<<1)*(--y);}}this.drawDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);this.drawDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);},/*虚点圆形*/drawOvalDott : function(x1, y1, w1, h1){var a = w1>>1, b = h1>>1,wod = w1&1, hod = h1&1,cx = x1+a, cy = y1+b,x = 0, y = b,aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,st = (aa2>>1)*(1-(b<<1)) + bb,tt = (bb>>1) - aa2*((b<<1)-1),drw = true;while (y > 0){if (st < 0){st += bb*((x<<1)+3);tt += (bb<<1)*(++x);}else if (tt < 0){st += bb*((x<<1)+3) - aa4*(y-1);tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);}else{tt -= aa2*((y<<1)-3);st -= aa4*(--y);}if (drw) this.drawCirclePoints(cx, cy, -x, x+wod, -y, y+hod, 1, 1);drw = !drw;}},/*绘制矩形(边为虚线的矩形)*/drawRectangleDott : function(x, y, w, h){this.drawLine(x, y, x+w, y);this.drawLine(x+w, y, x+w, y+h);this.drawLine(x, y+h, x+w, y+h);this.drawLine(x, y, x, y+h);},/*绘制矩形(边为实线的矩形)*/drawRectangle : function(x, y, w, h){var s = this.stroke;this.drawDiv(x, y, w, s);this.drawDiv(x+w, y, s, h);this.drawDiv(x, y+h, w+s, s);this.drawDiv(x, y+s, s, h-s);},/*绘制折线 参数是每个点xy轴坐标数祖集合*/drawPolyLine : function(xPoints, yPoints){for (var i=0 ; i<xPoints.length-1 ; i++ ){this.drawLine(xPoints[i], yPoints[i], xPoints[i+1], yPoints[i+1]);};},/*填充图形部分*//*填充矩形*/fillRect : function(x, y, w, h){this.drawDiv(x, y, w, h);},/*多边形 与折线类似不同的地方是多边形是闭合的*/drawPolygon : function(xPoints, yPoints){this.drawPolyline(xPoints, yPoints);this.drawLine(xPoints[x.length-1], yPoints[x.length-1], x[0], y[0]);},/*填充的圆形(椭圆形)*/fillOval : function(left, top, w, h){var a = (w -= 1)>>1, b = (h -= 1)>>1,wod = (w&1)+1, hod = (h&1)+1,cx = left+a, cy = top+b,x = 0, y = b,ox = 0, oy = b,aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,st = (aa2>>1)*(1-(b<<1)) + bb,tt = (bb>>1) - aa2*((b<<1)-1),pxl, dw, dh;if (w+1) while (y > 0){if (st < 0){st += bb*((x<<1)+3);tt += (bb<<1)*(++x);}else if (tt < 0){st += bb*((x<<1)+3) - aa4*(y-1);pxl = cx-x;dw = (x<<1)+wod;tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);dh = oy-y;this.drawDiv(pxl, cy-oy, dw, dh);this.drawDiv(pxl, cy+y+hod, dw, dh);ox = x;oy = y;}else{tt -= aa2*((y<<1)-3);st -= aa4*(--y);}}this.drawDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);},/** *填充的多边形 参数 x坐标数组 y坐标数组 *数组示例: *var Xpoints = new Array(10,80,80,50); *var YPoints = new Array(50,10,90,80); *jg.drawPolyline(Xpoints,Ypoints); */fillPolygon : function(array_x, array_y){var i;var y;var miny, maxy;var x1, y1;var x2, y2;var ind1, ind2;var ints;var n = array_x.length;/*数组长度 正常输入的情况 array_x.length == array_y.length;*/if (!n) return;/*如果输入数组为空 直接返回*//*得到最大于最小的y坐标*/miny = array_y[0];maxy = array_y[0];for (i = 1; i < n; i++){if (array_y[i] < miny)miny = array_y[i];if (array_y[i] > maxy)maxy = array_y[i];}/*最小Y坐标 -> 最大Y坐标*/for (y = miny; y <= maxy; y++){var polyInts = new Array();ints = 0;/*参数数组 -> */for (i = 0; i < n; i++){if (!i)// if( i != 0){ind1 = n-1;ind2 = 0;}else{ind1 = i-1;ind2 = i;}y1 = array_y[ind1];y2 = array_y[ind2];if (y1 < y2){x1 = array_x[ind1];x2 = array_x[ind2];}else if (y1 > y2){y2 = array_y[ind1];y1 = array_y[ind2];x2 = array_x[ind1];x1 = array_x[ind2];}else continue;if ((y >= y1) && (y < y2))polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);else if ((y == maxy) && (y > y1) && (y <= y2))polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);}/*sort函数:默认根据ASCII升序排列,这里使用用函数(integer_compare)来确定元素顺序*/polyInts.sort(new Function('x,y', 'return (x < y) ? -1 : ((x > y)*1);'));for (i = 0; i < ints; i+=2)this.drawDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);}},/*文本 参数为x y坐标 文本字符串*/drawString : function(txt, x, y){var elem = document.createElement("div");elem.style.position = 'absolute';elem.style.overflow = 'hidden';elem.style.left = x ;elem.style.top = y ; /*elem.style.backgroundColor = this.color;*/elem.style.fontFamily = this.fFamily;elem.style.fontSize = this.fSize;elem.style.color = this.color;/*字体属性*/if(this.fStyle=="PLAIN"){elem.style.fontweight = 'normal';/*默认字体*/}else if(this.fStyle=="ITALIC"){elem.style.fontweight = 'bold';/*斜体字*/}else if(this.fStyle=="BOLD"){elem.style.fontStyle = 'italic';/*斜体字*/}else if(this.fStyle=="ITALIC_BOLD"){elem.style.fontweight = 'bold';/*粗体字*/elem.style.fontStyle = 'italic';/*斜体字*/}else if((this.fStyle=="BOLD_ITALIC")){elem.style.fontStyle = 'italic';/*斜体字*/elem.style.fontweight = 'bold';/*粗体字*/}else{elem.style.fontweight = 'normal';/*默认字体PLAIN*/}elem.appendChild(document.createTextNode(txt));this.documentRoot.appendChild(elem);},/**设置字体 * 参数:(字形 尺寸 样式) * 尺寸:(单位象素) * 样式:(PLAIN 默认,BOLD 粗体,ITALIC 斜体,ITALIC_BOLD 斜粗体,BOLD_ITALIC 粗斜体) */setFont : function(fFamily, fSize, fStyle){this.fFamily = fFamily;this.fSize = fSize;this.fStyle = fStyle;},/*添加图片 图片地址 位置宽高*/drawImage : function(imgSrc, x, y, w, h){var elem = document.createElement("div");elem.style.position = 'absolute';elem.style.overflow = 'hidden';elem.style.left = x ;elem.style.top = y ; elem.style.width = w ;elem.style.height= h ; var elemImg = document.createElement("img");elemImg.src = imgSrc;elemImg.style.left = x ;elemImg.style.top = y ; elemImg.style.width = w ;elemImg.style.height= h ;elem.appendChild(elemImg);this.documentRoot.appendChild(elem);}};
?