Saturday, January 8, 2011

How To Draw a Circle in HTML <5 (without Canvas/SVG)

The following tiny script allows to draw circles in "regular" pre-HTML 5 document, it is so fast that it really allows for animations in real time.

Example:

   drawCircle(500, 500, 150, "red", 50, 1);

This will draw a  red circle, 50% transparent, with 150 px radius at the point (500,500). The circle will be drawn using 1px-fine pen (granularity).
The wider is the "pen" the faster is the routine. I usually increase granularity to 4px while dragging/sizing for speed and then re-render with 1px granularity upon drag grip release.


Here is the self-sufficient(does not rely on any libs) procedural source code:


//classic one
function isIE()
{
 return (navigator.appName.indexOf("Microsoft")!=-1);
}

function drawCircle(cx, cy, r, clr, op, gran)
{
 var x = 0;
 var div; 
 
 var dc = document.createElement("DIV");//aka "Device Context" wich is a DIV in doc tree
 dc.style.position="absolute";
 dc.innerHTML = "&nbsp;";
 dc.style.left = cx - r; 
 dc.style.top =  cy - r; 
 
 cx = r; cy = r;
 
 if (gran<1) gran = 1;
 
 if ((r/gran)> 280) gran = Math.round(r / 280);
  
 for(var y=0; y<=r; y+=gran)
 {
  x = Math.sqrt((r*r) - (y*y));
  
  div = document.createElement("DIV");
    
  div.style.position="absolute";
  div.style.background = clr;
  div.style.left = cx - x;
  div.style.top = cy+y;
  div.style.width= x*2;
  div.style.height=gran;
  div.style.fontSize=1;
  div.innerHTML = "&nbsp;";
  setObjectOpacity(div, op);
  dc.appendChild(div);
  
  div = document.createElement("DIV");
  div.style.position="absolute";
  div.style.background = clr;
  div.style.left = cx - x;
  div.style.top = cy-y-gran;
  div.style.width= x*2;
  div.style.height=gran;
  div.style.fontSize=1;
  div.innerHTML = "&nbsp;";
  setObjectOpacity(div, op);
  dc.appendChild(div);
  
 }
 
 return dc;
}//drawCircle

//semi-transparent through CSS/filter
function setObjectOpacity(obj, opacity) 
{
  //IE
  if (isIE())
   obj.style.filter = "alpha(opacity:"+opacity+")";
  else
  {
    opacity = (opacity == 100)?99.999:opacity;//99.9 for Firefox flicker bug
  
    // Konqueror, Safari
    obj.style.KHTMLOpacity = opacity / 100;
    // Old Mozilla and Firefox
    obj.style.MozOpacity = opacity / 100;
    // CSS3,  Safari , new Firefox (Gecko)
    obj.style.opacity = opacity / 100;
  }//else
}//setObjectOpacity


As you can see, this approach uses DIVs as a vehicle for graphics delivery. Also, one may ask why I did not use squares to reduce
 the number of DIVs - the answer is - flicker - squares would have overlapped and would have worked slower than interlaced DIVs.

Use as you please!