// 2D Graphics Package // Drawing routines for DynLayer // Copyright (C) 2000-2001 Dan Steinman, Guoyi Chao, Rob Breeds // Guoyi Chao: drawing routines for line, circle, ellipse // Dan Steinman: DynAPI2 support, object wrappers, VML support, improved routines for line, rect, and fills() // Rob Breeds: improve performance on ellipse and circle algorithms, and added line thicknesses support // Distributed under the terms of the GNU Library General Public License function Graphics(dlyr) { this._dlyr = dlyr; this._s = "yellow"; this._w = 1; this._f = "white"; }; Graphics.prototype.setStrokeColor = function(v) {this._s = v}; Graphics.prototype.setStrokeWeight = function(v) {this._w = v}; Graphics.prototype.setFillColor = function(v) {this._f = v}; Graphics.prototype.drawPixel = function(x,y) { drawPixel(x,y,this._s,this._w,this); }; Graphics.prototype.drawLine = function(x1,y1,x2,y2) { var shape; if (Graphics.useVML) { shape = new VML_Line(x1,y1,x2,y2,this._w,this._s); this._dlyr.elm.appendChild(shape.elm); } else { shape = new Line(x1,y1,x2,y2,this._w,this._s); this._dlyr.addChild(shape); } return shape; }; Graphics.prototype.drawCircle = function(x,y,radius) { var shape; if (Graphics.useVML) { // bug in IE, always fills anyway shape = new VML_Oval(x,y,2*radius,2*radius,this._w,this._s, dynapi.ua.ie5?this._dlyr.bgColor:false); this._dlyr.elm.appendChild(shape.elm); } else { shape = new Circle(x,y,radius,this._w,this._s); this._dlyr.addChild(shape); } return shape; }; Graphics.prototype.fillCircle = function(x,y,r) { fillCircle(x+r,y+r,r,this._f,this._dlyr); }; Graphics.prototype.drawEllipse = function(x,y,w,h) { drawEllipse(x+w/2,y+h/2,w,h,this._s,false,this._w,this._dlyr); }; Graphics.prototype.drawOval = Graphics.prototype.drawEllipse; Graphics.prototype.fillEllipse = function(x,y,w,h) { drawEllipse(x+w/2,y+h/2,w,h,this._f,true,this._w,this._dlyr); }; Graphics.prototype.fillOval = Graphics.prototype.fillEllipse; Graphics.prototype.drawRect = function(x,y,w,h) { drawRect(x,y,w,h,this._s,this._w,this._dlyr); }; Graphics.prototype.fillRect = function(x,y,w,h) { fillRect(x,y,w,h,this._f,this._dlyr); }; Graphics.prototype.clear = function() { this.deleteAllChildren(); this.setHTML(''); }; Graphics.useVML = false; if (dynapi.ua.ie && dynapi.ua.v>=5) { // include active-x component for IE5+ Graphics.useVML = true; var str = ''+ ''+ ''; if (dynapi.loaded) { dynapi.frame.document.body.appendChild('beforeEnd',str); } else { document.write(str); } }; // Drawing Routines function Pixel(x,y,color,t) { // not really needed this.DynLayer = DynLayer; this.DynLayer(); this.setLocation(x,y); this.setSize(t||1,t||1); this.setBgColor(color||"black"); }; Pixel.prototype = new DynLayer(); function drawPixel(x,y,color,t,lyr) { lyr.addChild( new DynLayer('',Math.round(x),Math.round(y),t,t,color) ); }; function Shape() { this.DynLayer = DynLayer; this.DynLayer(); this.setStrokeColor("black"); this.setStrokeWeight(1); }; Shape.prototype = new DynLayer(); Shape.prototype.setStrokeColor = function(v) {this._s = v}; Shape.prototype.setStrokeWeight = function(v) {this._w = v}; function Line(x1,y1,x2,y2,w,s) { this.Shape = Shape; this.Shape(); this.setStrokeWeight(w); this.setStrokeColor(s); var dx = Math.min(x1,x2); var dy = Math.min(y1,y2); var width = Math.abs(x2-x1); var height = Math.abs(y2-y1); this.setLocation(dx, dy); if(x1==x2||y1==y2) { // straight line this.setBgColor(s); if(x1==x2) this.setSize(w,height); // vertical else this.setSize(width,w); //horizontal } else { // diagonal this.setSize(width,height); var nx1 = x1-dx; var ny1 = y1-dy; var nx2 = x2-dx; var ny2 = y2-dy; drawLine(nx1,ny1,nx2,ny2,s,w,this); } }; Line.prototype = new Shape(); function VMLElement() { this.elm = null; }; VMLElement.prototype.createShape = function(type) { this.elm = document.createElement('v:'+type); }; VMLElement.prototype.setLocation = function() {}; function VML_Line(x1,y1,x2,y2,w,s) { this.VMLElement = VMLElement; this.VMLElement(); this.createShape("line"); this.elm.from = x1+'px ,'+y1+'px'; this.elm.to = x2+'px ,'+y2+'px'; this.elm.strokeColor = s; this.elm.innerHTML = ''; //this.elm.innerHTML = ''; //""; }; VML_Line.prototype = new VMLElement(); function VML_Oval(x,y,width,height,w,s,fc) { this.VMLElement = VMLElement; this.VMLElement(); this.elm = document.createElement('v:oval'); this.elm.style.position = "absolute"; this.elm.style.left = x+"px"; this.elm.style.top = y+"px"; this.elm.style.width = width+"px"; this.elm.style.height = height+"px"; this.elm.strokeColor = s; if (fc) { this.elm.fillColor = fc; this.elm.fill = true; } else this.elm.fill = false; this.elm.innerHTML = ''; }; VML_Oval.prototype = new VMLElement(); function drawLine(x1,y1,x2,y2,color,t,lyr) { var flag = (Math.abs(y2-y1) > Math.abs(x2-x1)); var dx,dy,x,y,e,xstep,ystep; if (flag) dx=Math.abs(y2-y1),dy=Math.abs(x2-x1),x=y1,y=x1; else dx=Math.abs(x2-x1),dy=Math.abs(y2-y1),x=x1,y=y1; xstep=x1>x2?-1:1; ystep=y1>y2?-1:1; if(x1==x2||y1==y2) { if(x1==x2) { var ny1 = Math.min(y1,y2); var ny2 = Math.max(y1,y2); lyr.addChild( new DynLayer('',x1,ny1,t,(ny2-ny1)*t,color) ); return; } else { var nx1 = Math.min(x1,x2); var nx2 = Math.max(x1,x2); lyr.addChild( new DynLayer('',nx1,y1,(nx2-nx1)*t,t,color) ); return; } } // Bresenham Method Begin var e=-dx; for(var count=0;count<=dx;count++) { if (flag) drawPixel(y,x,color,t,lyr); else drawPixel(x,y,color,t,lyr); if (flag) x+=ystep; else x+=xstep; e+=dy<<1; if(e>=0) { if(flag) y+=xstep; else y+=ystep; e-=dx<<1; } } return; }; function Circle(x,y,radius,w,s) { this.Shape = Shape; this.Shape(); this.setStrokeWeight(w); this.setStrokeColor(s); this.setLocation(x,y); this.setSize(2*radius, 2*radius); drawCircle(0+radius,0+radius,radius-1,this._s,this._w,this); }; Circle.prototype = new Shape(); function drawCircle(centerX,centerY,radius,color,t,lyr) { var x = centerX; var y = centerY; var cx = 0; var cy = radius; var df = 1 - radius; var d_e = 3; var d_se = -(radius<<1) + 5; do { drawPixel(x+cx, y+cy, color,t,lyr); if (cx) drawPixel(x-cx, y+cy, color,t,lyr); if (cy) drawPixel(x+cx, y-cy, color,t,lyr); if ((cx) && (cy)) drawPixel(x-cx, y-cy, color,t,lyr) ; if (cx != cy) { drawPixel(x+cy, y+cx, color,t,lyr); if (cx) drawPixel(x+cy, y-cx, color,t,lyr); if (cy) drawPixel(x-cy, y+cx, color,t,lyr); if (cx && cy) drawPixel(x-cy, y-cx, color,t,lyr); } if (df < 0) { df += d_e; d_e += 2; d_se += 2; } else { df += d_se; d_e += 2; d_se += 4; cy--; } cx++; } while (cx <= cy); }; function fillCircle(x,y,radius,color,lyr) { var cx = 0; var cy = radius; var df = 1 - radius; var d_e = 3; var d_se = -(radius<<1) + 5; do { fillRect(x-cy, y-cx, cy<<1, cx<<1, color,lyr); if (df < 0) { df += d_e; d_e += 2; d_se += 2; } else { if (cx != cy) fillRect(x-cx, y-cy, cx<<1, cy<<1, color,lyr); df += d_se; d_e += 2; d_se += 4; cy--; } cx++; } while (cx <= cy); } function drawEllipse(cx,cy,rx,ry,color,filled,t,lyr) { var x,y,a2,b2, S, T; a2 = rx*rx; b2 = ry*ry; x = 0; y = ry; S = a2*(1-2*ry) + 2*b2; T = b2 - 2*a2*(2*ry-1); symmPaint(cx,cy,x,y,color,filled,t,lyr); do { if (S<0) { S += 2*b2*(2*x+3); T += 4*b2*(x+1); x++; } else if (T<0) { S += 2*b2*(2*x+3) - 4*a2*(y-1); T += 4*b2*(x+1) - 2*a2*(2*y-3); x++; y--; } else { S -= 4*a2*(y-1); T -= 2*a2*(2*y-3); y--; } symmPaint(cx,cy,x,y,color,filled,t,lyr); } while (y>0); } //Bresenham's algorithm for ellipses function symmPaint(cx,cy, x, y, color, filled, t, lyr){ if (filled) { fillRect ( cx-x, cy-y, x<<1, y<<1, color, lyr ); } else { drawPixel ( cx-x, cy-y, color, t,lyr ); drawPixel ( cx+x, cy-y, color, t,lyr ); drawPixel ( cx-x, cy+y, color, t,lyr ); drawPixel ( cx+x, cy+y, color, t,lyr ); } } function drawRect(x,y,w,h,color,t,lyr) { lyr.addChild( new DynLayer('',x,y,w,t,color) ); lyr.addChild( new DynLayer('',x,y,t,h,color) ); lyr.addChild( new DynLayer('',x+w-t,y,t,h,color) ); lyr.addChild( new DynLayer('',x,y+h-t,w,t,color) ); } function fillRect(x,y,w,h,color,lyr) { lyr.addChild( new DynLayer('',x,y,w,h,color) ); }