Subversion Repositories wimsdev

Rev

Blame | Last modification | View Log | RSS feed

  1. // 2D Graphics Package
  2. // Drawing routines for DynLayer
  3. // Copyright (C) 2000-2001 Dan Steinman, Guoyi Chao, Rob Breeds
  4.  
  5. // Guoyi Chao: drawing routines for line, circle, ellipse
  6. // Dan Steinman: DynAPI2 support, object wrappers, VML support, improved routines for line, rect, and fills()
  7. // Rob Breeds: improve performance on ellipse and circle algorithms, and added line thicknesses support
  8.  
  9. // Distributed under the terms of the GNU Library General Public License
  10.  
  11. function Graphics(dlyr) {
  12.         this._dlyr = dlyr;
  13.         this._s = "yellow";
  14.         this._w = 1;
  15.         this._f = "white";
  16. }
  17. Graphics.prototype.setStrokeColor = function(v) {this._s = v};
  18. Graphics.prototype.setStrokeWeight = function(v) {this._w = v};
  19. Graphics.prototype.setFillColor = function(v) {this._f = v};
  20. Graphics.prototype.drawPixel = function(x,y) {
  21.         drawPixel(x,y,this._s,this._w,this);
  22. };
  23. Graphics.prototype.drawLine = function(x1,y1,x2,y2) {
  24.         var shape;
  25.         if (Graphics.useVML) {
  26.                 shape = new VML_Line(x1,y1,x2,y2,this._w,this._s);
  27.                 this._dlyr.elm.appendChild(shape.elm);
  28.         }
  29.         else {
  30.                 shape = new Line(x1,y1,x2,y2,this._w,this._s);
  31.                 this._dlyr.addChild(shape);
  32.         }
  33.         return shape;
  34. };
  35. Graphics.prototype.drawCircle = function(x,y,radius) {
  36.         var shape;
  37.         if (Graphics.useVML) {
  38.                 // bug in IE, always fills anyway
  39.                 shape = new VML_Oval(x,y,2*radius,2*radius,this._w,this._s, dynapi.ua.ie5?this._dlyr.bgColor:false);
  40.                 this._dlyr.elm.appendChild(shape.elm);
  41.         }
  42.         else {
  43.                 shape = new Circle(x,y,radius,this._w,this._s);
  44.                 this._dlyr.addChild(shape);
  45.         }
  46.         return shape;
  47. };
  48. Graphics.prototype.fillCircle = function(x,y,r) {
  49.         fillCircle(x+r,y+r,r,this.color,this._dlyr);
  50. };
  51. Graphics.prototype.drawOval = function(x,y,w,h) {
  52.         drawEllipse(x+w/2,y+h/2,w,h,this.color,false,this.thickness,this._dlyr);
  53. };
  54. Graphics.prototype.fillEllipse = function(x,y,w,h) {
  55.         drawEllipse(x+w/2,y+h/2,w,h,this.color,true,this.thickness,this._dlyr);
  56. };
  57. Graphics.prototype.drawRect = function(x,y,w,h) {
  58.         drawRect(x,y,w,h,this.color,this.thickness,this._dlyr);
  59. };
  60. Graphics.prototype.fillRect = function(x,y,w,h) {
  61.         fillRect(x,y,w,h,this.color,this._dlyr);
  62. };
  63. Graphics.prototype.clear = function() {
  64.         this.deleteAllChildren();
  65.         this.setHTML('');
  66. };
  67.  
  68. Graphics.useVML = false;
  69. if (dynapi.ua.ie && dynapi.ua.v>=5) {  // include active-x component for IE5+
  70.         Graphics.useVML = true;
  71.         var str = '<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>'+
  72.                 '<object id="VMLRender" codebase="vgx.dll" classid="CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E"></object>'+
  73.                 '<style>'+
  74.                 '<!--'+
  75.                 'v\\:* { behavior: url(#VMLRender); }'+
  76.                 '-->'+
  77.                 '</style>';
  78.        
  79.         if (dynapi.loaded) {
  80.                 dynapi.frame.document.body.appendChild('beforeEnd',str);
  81.         }
  82.         else {
  83.                 document.write(str);
  84.         }
  85. }
  86.  
  87. // Drawing Routines
  88.  
  89. function Pixel(x,y,color,t) {   // not really needed
  90.         this.DynLayer = DynLayer;
  91.         this.DynLayer();
  92.         this.setLocation(x,y);
  93.         this.setSize(t||1,t||1);
  94.         this.setBgColor(color||"black");
  95. }
  96. Pixel.prototype = new DynLayer();
  97.  
  98. function drawPixel(x,y,color,t,lyr) {
  99.         lyr.addChild( new DynLayer('',Math.round(x),Math.round(y),t,t,color) )
  100. }
  101.  
  102. function Shape() {
  103.         this.DynLayer = DynLayer;
  104.         this.DynLayer();
  105.        
  106.         this.setStrokeColor("black");
  107.         this.setStrokeWeight(1);
  108. }
  109. Shape.prototype = new DynLayer();
  110. Shape.prototype.setStrokeColor = function(v) {this._s = v};
  111. Shape.prototype.setStrokeWeight = function(v) {this._w = v};
  112.  
  113. function Line(x1,y1,x2,y2,w,s) {
  114.         this.Shape = Shape;
  115.         this.Shape();
  116.         this.setStrokeWeight(w);
  117.         this.setStrokeColor(s);
  118.        
  119.         var dx = Math.min(x1,x2);
  120.         var dy = Math.min(y1,y2);
  121.         var width = Math.abs(x2-x1);
  122.         var height = Math.abs(y2-y1);
  123.         this.setLocation(dx, dy);
  124.  
  125.         if(x1==x2||y1==y2) {  // straight line
  126.                 this.setBgColor(s);
  127.                 if(x1==x2) this.setSize(w,height); // vertical
  128.                 else this.setSize(width,w);  //horizontal
  129.         }
  130.         else {  // diagonal
  131.                 this.setSize(width,height);
  132.                 var nx1 = x1-dx;
  133.                 var ny1 = y1-dy;
  134.                 var nx2 = x2-dx;
  135.                 var ny2 = y2-dy;
  136.                 drawLine(nx1,ny1,nx2,ny2,s,w,this);
  137.         }
  138. }
  139. Line.prototype = new Shape();
  140.  
  141. function VMLElement() {
  142.         this.elm = null
  143. };
  144. VMLElement.prototype.createShape = function(type) {
  145.         this.elm = document.createElement('v:'+type);
  146. }
  147. VMLElement.prototype.setLocation = function() {};
  148.  
  149. function VML_Line(x1,y1,x2,y2,w,s) {
  150.         this.VMLElement = VMLElement;
  151.         this.VMLElement();
  152.        
  153.         this.createShape("line");
  154.         this.elm.from = x1+'px ,'+y1+'px';
  155.         this.elm.to = x2+'px ,'+y2+'px';
  156.         this.elm.strokeColor = s;
  157.         this.elm.innerHTML = '<v:stroke weight="'+w+'px">';    
  158.        
  159.         //this.elm.innerHTML = '<v:stroke weight="'+this.thickness+'px" color="'+this.color+'">';
  160.         //"<v:line id='line" + nnode + "' from=" + x1 + "," + y1 +"' to='" + x2 + "," + y2 +"'><v:stroke weight='2px' color='black'/></v:line>";
  161. };
  162. VML_Line.prototype = new VMLElement();
  163.  
  164. function VML_Oval(x,y,width,height,w,s,fc) {
  165.         this.VMLElement = VMLElement;
  166.         this.VMLElement();
  167.        
  168.         this.elm = document.createElement('v:oval');
  169.         this.elm.style.position = "absolute";
  170.         this.elm.style.left = x+"px";
  171.         this.elm.style.top = y+"px";
  172.         this.elm.style.width = width+"px";
  173.         this.elm.style.height = height+"px";
  174.  
  175.         this.elm.strokeColor = s;
  176.        
  177.         if (fc) {
  178.                 this.elm.fillColor = fc;
  179.                 this.elm.fill = true;
  180.         }
  181.         else this.elm.fill = false;
  182.        
  183.         this.elm.innerHTML = '<v:stroke weight="'+w+'px">';
  184. };
  185. VML_Oval.prototype = new VMLElement();
  186.  
  187. function drawLine(x1,y1,x2,y2,color,t,lyr) {
  188.         var flag = (Math.abs(y2-y1) > Math.abs(x2-x1))
  189.         var dx,dy,x,y,e,xstep,ystep
  190.         if (flag) dx=Math.abs(y2-y1),dy=Math.abs(x2-x1),x=y1,y=x1
  191.         else dx=Math.abs(x2-x1),dy=Math.abs(y2-y1),x=x1,y=y1
  192.         xstep=x1>x2?-1:1
  193.         ystep=y1>y2?-1:1
  194.         if(x1==x2||y1==y2) {
  195.                 if(x1==x2) {
  196.                         var ny1 = Math.min(y1,y2)
  197.                         var ny2 = Math.max(y1,y2)
  198.                         lyr.addChild( new DynLayer('',x1,ny1,t,(ny2-ny1)*t,color) )
  199.                         return
  200.                 }
  201.                 else {
  202.                         var nx1 = Math.min(x1,x2)
  203.                         var nx2 = Math.max(x1,x2)
  204.                         lyr.addChild( new DynLayer('',nx1,y1,(nx2-nx1)*t,t,color) )
  205.                         return
  206.                 }
  207.         }
  208.         // Bresenham Method Begin
  209.         var e=-dx
  210.         for(var count=0;count<=dx;count++) {
  211.                 if (flag) drawPixel(y,x,color,t,lyr)
  212.                 else drawPixel(x,y,color,t,lyr)
  213.                 if (flag) x+=ystep
  214.                 else x+=xstep
  215.                 e+=dy<<1
  216.                 if(e>=0) {
  217.                         if(flag) y+=xstep
  218.                         else y+=ystep
  219.                         e-=dx<<1
  220.                 }
  221.         }
  222.         return
  223. }
  224.  
  225. function Circle(x,y,radius,w,s) {
  226.         this.Shape = Shape;
  227.         this.Shape();
  228.         this.setStrokeWeight(w);
  229.         this.setStrokeColor(s);
  230.        
  231.         this.setLocation(x,y);
  232.         this.setSize(2*radius, 2*radius);
  233.        
  234.         drawCircle(0+radius,0+radius,radius-1,this._s,this._w,this);
  235. }
  236. Circle.prototype = new Shape();
  237.  
  238. function drawCircle(centerX,centerY,radius,color,t,lyr) {
  239.         var x = centerX;
  240.         var y = centerY;
  241.         var cx = 0
  242.         var cy = radius
  243.         var df = 1 - radius
  244.         var d_e = 3
  245.         var d_se = -(radius<<1) + 5
  246.         do {
  247.                 drawPixel(x+cx, y+cy, color,t,lyr)
  248.                 if (cx) drawPixel(x-cx, y+cy, color,t,lyr)
  249.       if (cy)   drawPixel(x+cx, y-cy, color,t,lyr)
  250.       if ((cx) && (cy)) drawPixel(x-cx, y-cy, color,t,lyr)
  251.       if (cx != cy) {
  252.                         drawPixel(x+cy, y+cx, color,t,lyr)
  253.                         if (cx) drawPixel(x+cy, y-cx, color,t,lyr)
  254.                         if (cy) drawPixel(x-cy, y+cx, color,t,lyr)
  255.                         if (cx && cy) drawPixel(x-cy, y-cx, color,t,lyr)
  256.       }
  257.       if (df < 0)  {
  258.                         df += d_e
  259.                         d_e += 2
  260.                         d_se += 2
  261.       }
  262.       else {
  263.                         df += d_se
  264.                         d_e += 2
  265.                         d_se += 4
  266.                         cy--
  267.                 }
  268.                 cx++
  269.    } while (cx <= cy)
  270. }
  271.  
  272. function fillCircle(x,y,radius,color,lyr) {
  273.         var cx = 0
  274.         var cy = radius
  275.         var df = 1 - radius
  276.         var d_e = 3
  277.         var d_se = -(radius<<1) + 5
  278.         do {
  279.                 fillRect(x-cy, y-cx, cy<<1, cx<<1, color,lyr)
  280.             if (df < 0)  {
  281.                         df += d_e
  282.                         d_e += 2
  283.                         d_se += 2
  284.                 }
  285.                 else {
  286.                         if (cx != cy) fillRect(x-cx, y-cy, cx<<1, cy<<1, color,lyr)
  287.                         df += d_se
  288.                         d_e += 2
  289.                         d_se += 4
  290.                         cy--
  291.                 }
  292.                 cx++
  293.         } while (cx <= cy)
  294. }
  295.  
  296. function drawEllipse(cx,cy,rx,ry,color,filled,t,lyr) {
  297.         var x,y,a2,b2, S, T
  298.         a2 = rx*rx
  299.         b2 = ry*ry
  300.         x = 0
  301.         y = ry
  302.         S = a2*(1-2*ry) + 2*b2
  303.         T = b2 - 2*a2*(2*ry-1)
  304.         symmPaint(cx,cy,x,y,color,filled,t,lyr)
  305.         do {
  306.                 if (S<0) {
  307.                         S += 2*b2*(2*x+3)
  308.                         T += 4*b2*(x+1)
  309.                         x++
  310.                 } else if (T<0) {
  311.                         S += 2*b2*(2*x+3) - 4*a2*(y-1)
  312.                         T += 4*b2*(x+1) - 2*a2*(2*y-3)
  313.                         x++
  314.                         y--
  315.                 } else {
  316.                         S -= 4*a2*(y-1)
  317.                         T -= 2*a2*(2*y-3)
  318.                         y--
  319.                 }
  320.                 symmPaint(cx,cy,x,y,color,filled,t,lyr)
  321.         } while (y>0)
  322. }
  323.  
  324. //Bresenham's algorithm for ellipses
  325. function symmPaint(cx,cy, x, y, color, filled, t, lyr){
  326.         if (filled) {
  327.                 fillRect ( cx-x, cy-y, x<<1, y<<1, color, lyr )
  328.         } else {
  329.                 drawPixel ( cx-x, cy-y, color, t,lyr )
  330.                 drawPixel ( cx+x, cy-y, color, t,lyr )
  331.                 drawPixel ( cx-x, cy+y, color, t,lyr )
  332.                 drawPixel ( cx+x, cy+y, color, t,lyr )
  333.         }
  334. }
  335.  
  336. function drawRect(x,y,w,h,color,t,lyr) {
  337.         lyr.addChild( new DynLayer('',x,y,w,t,color) )
  338.         lyr.addChild( new DynLayer('',x,y,t,h,color) )
  339.         lyr.addChild( new DynLayer('',x+w-t,y,t,h,color) )
  340.         lyr.addChild( new DynLayer('',x,y+h-t,w,t,color) )
  341. }
  342.  
  343. function fillRect(x,y,w,h,color,lyr) {
  344.         lyr.addChild( new DynLayer('',x,y,w,h,color) )
  345. }
  346.