/**********************************************************************************
*
* Project Name: jsDraw2D (Graphics Library for JavaScript)
* Version: Beta 1.1.0 (17-August-2009) (Uncompressed)
* Project Homepage: http://jsdraw2d.jsfiction.com
* Author: Sameer Burle
* Copyright 2009: jsFiction.com (http://www.jsfiction.com)
* Licensed Under: LGPL
*
* This program (library) is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
************************************************************************************/
//jsColor class holds the color information and provides some color related basic functions.
function jsColor()
{
//Member variables
var hex="#000000";
switch(arguments.length)
{
//Hexadecimal Color
case 1:
setHex(arguments[0]);
break;
//RGB Color
case 3:
var red=arguments[0];
var green=arguments[1];
var blue=arguments[2];
hex=rgbToHex(red,green,blue);
if(hex==false)
hex="#000000";
break;
}
//Public Methods
//Set color by specifying the hexa-decimal value.
this.setHex=setHex;
function setHex(hexColor)
{
if(hexColor.charAt(0)=="#")
{
hex=hexColor;
}
else
{
if(isNaN(hexColor))
{
setNamedColor(hexColor.toLowerCase());
}
else
{
hex="#" + hexColor;
}
}
var rgbArray=hexToRgb(hex);
if(!rgbArray)
{
hex="#000000"
}
}
//Get the hexa-decimal value of the object
this.getHex=getHex;
function getHex()
{
return hex;
}
//Set color by specifying the RGB values.
this.setRGB=setRGB;
function setRGB(redValue,greenValue,blueValue)
{
hex=rgbToHex(redValue,greenValue,blueValue);
if(hex==false)
hex="#000000";
}
//Get the RGB values of the object
this.getRGB=getRGB;
function getRGB()
{
return hexToRgb(hex);
}
//Returns new jsColor object with darker color shade
this.getDarkerShade=getDarkerShade;
function getDarkerShade(value)
{
var redValue,greenValue,blueValue;
var resArray=getRGB();
if(!isNaN(value))
{
redValue=parseInt(resArray[0]-value);
greenValue=parseInt(resArray[1]-value);
blueValue=parseInt(resArray[2]-value);
}
if(redValue<0)
redValue=0;
if(greenValue<0)
greenValue=0;
if(blueValue<0)
blueValue=0;
return new jsColor(redValue,greenValue,blueValue);
}
//Returns new jsColor object with lighter color shade
this.getLighterShade=getLighterShade;
function getLighterShade(value)
{
var redValue,greenValue,blueValue;
var resArray=getRGB();
if(!isNaN(value))
{
redValue=parseInt(resArray[0]+value);
greenValue=parseInt(resArray[1]+value);
blueValue=parseInt(resArray[2]+value);
}
if(redValue>255)
redValue=255;
if(greenValue>255)
greenValue=255;
if(blueValue>255)
blueValue=255;
return new jsColor(redValue,greenValue,blueValue);
}
//Static-Shared Utility Methods
//Convert RGB color to Hex color
this.rgbToHex=rgbToHex;
function rgbToHex(redValue, greenValue, blueValue)
{
//Check argument values
if(redValue<0 || redValue>255 || greenValue<0 || greenValue>255 || blueValue<0 || blueValue>255)
{
return false;
}
var colorDec = Math.round(blueValue) + 256 * Math.round(greenValue) + 65536 * Math.round(redValue);
return "#" + zeroPad(colorDec.toString(16),6);
}
//Convert Hex color to RGB color
this.hexToRgb=hexToRgb;
function hexToRgb(hexValue)
{
var redValue,greenValue,blueValue;
if(hexValue.charAt(0)=="#")
{
hexValue=hexValue.substring(1,7);
}
redValue=parseInt(hexValue.substring(0,2),16);
greenValue=parseInt(hexValue.substring(2,4),16);
blueValue=parseInt(hexValue.substring(4,6),16);
//Check argument values
if(redValue<0 || redValue>255 || greenValue<0 || greenValue>255 || blueValue<0 || blueValue>255)
{
return false;
}
return new Array(redValue,greenValue,blueValue);
}
//Private Methods
//Set the color using specified name of the color out of 16 web colors.
function setNamedColor(colorName)
{
switch(colorName)
{
case "aqua":
hex="#00FFFF";
break;
case "black":
hex="#000000";
break;
case "blue":
hex="#0000FF";
break;
case "fuchsia":
hex="#FF00FF";
break;
case "green":
hex="#008000";
break;
case "gray":
hex="#808080";
break;
case "lime":
hex="#00FF00";
break;
case "maroon":
hex="#800000";
break;
case "navy":
hex="#000080";
break;
case "olive":
hex="#808000";
break;
case "purple":
hex="#800080";
break;
case "red":
hex="#FF0000";
break;
case "silver":
hex="#C0C0C0";
break;
case "teal":
hex="#008080";
break;
case "white":
hex="#FFFFFF";
break;
case "yellow":
hex="#FFFF00";
break;
}
}
//Add zero padding to the left. Used for building hexa-decimal string.
function zeroPad(val,count)
{
var valZeropad = val + "";
while(valZeropad.length < count)
{
valZeropad = "0" + valZeropad;
}
return valZeropad;
}
}
//jsFont class holds the font information which can be used by other objects in object oriented way.
function jsFont(family,weight,size,style,variant)
{
//Properties: family, weight, size, style and varient with default value null
this.family=null;
this.weight=null;
this.size=null;
this.style=null;
this.variant=null;
if(family && family!="")
this.family=family;
if(weight && weight!="")
this.weight=weight;
if(size && size!="")
this.size=size;
if(style && style!="")
this.style=style;
if(variant && variant!="")
this.variant=variant;
}
//jsPen class holds the drawing pen/stroke information. Mainly it holds the color and width values to be used for 2D drawing.
//All draw methods take jsPen object as a parameter. Acts like a pen for drawing.
function jsPen(color,width)
{
this.color=new jsColor(); //color proprty of jsColor type
this.width="1px"; //width property with 1px default value
if(arguments.length>0)
{
this.color=color;
}
if(arguments.length>=2)
{
this.width=width;
}
if(!isNaN(width))
{
this.width=width+"px";
}
}
//jsPoint class holds the 2D drawing point information. It holds values of x and y coordinates of the point.
function jsPoint(x,y)
{
this.x=0;
this.y=0;
if(arguments.length==2)
{
this.x=x;
this.y=y;
}
}
function jsGraphics(canvasDivElement)
{
//Private member variables
var origin=new jsPoint(0,0);
var scale=1;
var coordinateSystem="default"; //Possible values "default" or "cartecian"
var canvasDiv;
if(canvasDivElement)
canvasDiv=canvasDivElement;
else
canvasDiv=document.body; //Document will be used directly for drawing
var gridDiv=null;
//Public Methods
this.drawLine=drawLine;
this.drawRectangle=drawRectangle;
this.fillRectangle=fillRectangle;
this.drawCircle=drawCircle;
this.drawEllipse=drawEllipse;
this.fillCircle=fillCircle;
this.fillEllipse=fillEllipse;
this.fillArc=fillArc;
this.drawArc=drawArc;
this.drawPolyline=drawPolyline;
this.drawPolygon=drawPolygon;
this.fillPolygon=fillPolygon;
this.drawBezier=drawBezier;
this.drawPolyBezier=drawPolyBezier;
this.drawCurve=drawCurve;
this.drawClosedCurve=drawClosedCurve;
this.fillClosedCurve=fillClosedCurve;
this.drawText=drawText;
this.drawImage=drawImage;
this.clear=clear;
this.showGrid=showGrid;
this.hideGrid=hideGrid;
this.setOrigin=setOrigin;
this.getOrigin=getOrigin;
this.setScale=setScale;
this.getScale=getScale;
this.setCoordinateSystem=setCoordinateSystem;
this.getCoordinateSystem=getCoordinateSystem;
this.logicalToPhysicalPoint=logicalToPhysicalPoint;
//Initialization
//Grid initialization
gridDiv=document.createElement("div");
gridDiv.style.left="0px";
gridDiv.style.top="0px";
if(canvasDiv.clientWidth>0 && canvasDiv.clientHeight>0)
{
gridDiv.style.width=(parseInt(canvasDiv.clientWidth)-1) + "px";
gridDiv.style.height=(parseInt(canvasDiv.clientHeight)-1) + "px";
}
else
{
gridDiv.style.width="0px";
gridDiv.style.height="0px";
}
gridDiv.style.zIndex=0;
gridDiv.style.position="absolute";
gridDiv.style.display="none";
canvasDiv.appendChild(gridDiv);
//Origin
function setOrigin(point)
{
origin=point;
}
function getOrigin()
{
return origin;
}
//Scale
function setScale(value)
{
scale=value;
}
function getScale()
{
return scale;
}
//Coordinate System
function setCoordinateSystem(name)
{
name=name.toLowerCase()
if(name.toLowerCase() != "default" && name.toLowerCase() != "cartecian")
{
coordinateSystem="default";
}
else
{
coordinateSystem=name;
}
}
function getCoordinateSystem()
{
return coordinateSystem=name;
}
//Conversion of logical point to physical point based on coordinate system, origin and scale.
function logicalToPhysicalPoint(point)
{
if(coordinateSystem=="cartecian")
{
return new jsPoint(point.x*scale+origin.x,origin.y-point.y*scale)
}
else
{
return new jsPoint(point.x*scale+origin.x,point.y*scale+origin.y)
}
}
//Display background grid
function showGrid(range,showRange,color)
{
if(showRange==null)
showRange=true; //range is grid interval. The values will be shown if showRange is true.
var x0,x1,y0,y1;
var isLeft=false; //range display on left side of y-axis if true otherwise right side.
var isUp=false; //range display above the x-axis if true otherwise below.
gridDiv.innerHTML="";
if(!color)
color=new jsColor(200,200,200);
if(!range)
range=Math.round(parseInt(gridDiv.style.width)/10); //If range not specified, use grid with devided by 10 as range.
else
range=range*scale;
var hexColor=color.getHex();
//If grid height or width is not available, the grid will not be displayed.
if(parseInt(gridDiv.style.width)<=0 || parseInt(gridDiv.style.height)<=0)
return;
else
gridDiv.style.display="";
x0=parseInt(gridDiv.style.left)
x1=parseInt(gridDiv.style.left)+parseInt(gridDiv.style.width);
y0=parseInt(gridDiv.style.top);
y1=parseInt(gridDiv.style.top)+parseInt(gridDiv.style.height);
//On which side of the axis the range to be displayed is decided based on position of the origin in the canvas.
//Range is displyed on opposite side of the largest section(out of 4 section divided by the 2 axis)
if(origin.x-parseInt(gridDiv.style.left)<=parseInt(gridDiv.style.left)+gridDiv.offsetWidth-origin.x)
isLeft=true
if(origin.y-parseInt(gridDiv.style.top)<=parseInt(gridDiv.style.top)+gridDiv.offsetHeight-origin.y)
isUp=true
var iHtml=new Array(); //Holds inner html
var rangeFont=new jsFont("arial",null,"9px");
var rangeColor=color.getDarkerShade(150);
var hexRangeColor=rangeColor.getHex();
//Draw the border grids
iHtml[iHtml.length]="
";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
var gridHeight=gridDiv.offsetHeight;
var gridWidth=gridDiv.offsetWidth;
var lastRangeDiv; //previous range div
var currentRangeDiv //current range div
//Draw vertical grid lines
for(var x=(origin.x-x0)%range;x=x0)
{
if(x>=x0 && x<=x1)
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
if(showRange && x>=x0 && x y1)
currentRangeDiv.style.top=y1-currentRangeDiv.offsetHeight-1;
}
else
{
if(parseInt(currentRangeDiv.style.top)-currentRangeDiv.offsetHeight-1>y0)
currentRangeDiv.style.top=parseInt(currentRangeDiv.style.top)-currentRangeDiv.offsetHeight-1;
if(parseInt(currentRangeDiv.style.top)<=y0)
currentRangeDiv.style.top=y0 + 1;
}
currentRangeDiv.style.visibility="visible";
lastRangeDiv = currentRangeDiv;
}
currentRangeDiv=null;
}
}
lastRangeDiv = null;
//Draw horizontal grid lines
for(var y=(origin.y-y0)%range;y<=y1;y+=range)
{
if(y==origin.y)
{
if(y>=y0 && y<=y1)
iHtml[iHtml.length]="";
}
else
iHtml[iHtml.length]="";
if(showRange && y!=origin.y && y>=y0 && y x0)
currentRangeDiv.style.left=parseInt(currentRangeDiv.style.left)-currentRangeDiv.offsetWidth-2;
else
currentRangeDiv.style.left=parseInt(currentRangeDiv.style.left)+1;
if(parseInt(currentRangeDiv.style.left)<=x0)
currentRangeDiv.style.left=x0 + 1;
}
currentRangeDiv.style.visibility="visible";
//Hide the overlapping range.
if(isUp && parseInt(currentRangeDiv.style.top)+currentRangeDiv.offsetHeight>origin.y-currentRangeDiv.offsetHeight && parseInt(currentRangeDiv.style.top)origin.y && parseInt(currentRangeDiv.style.top)origin.y)
currentRangeDiv.style.visibility="hidden";
if(origin.y>y1 && parseInt(currentRangeDiv.style.top)+currentRangeDiv.offsetHeight>y1-currentRangeDiv.offsetHeight)
currentRangeDiv.style.visibility="hidden";
if(!isUp && parseInt(currentRangeDiv.style.top)origin.y)
currentRangeDiv.style.visibility="hidden";
if(!isUp && parseInt(currentRangeDiv.style.top)origin.y && parseInt(currentRangeDiv.style.top)";
else if(x0>x1)
lineDiv.innerHTML="";
return lineDiv;
}
//For Vertical line
if(x0==x1)
{
if(y0<=y1)
lineDiv.innerHTML="";
else if(y0>y1)
lineDiv.innerHTML="";
return lineDiv;
}
var iHtml=new Array();
var yArray=new Array();
///Pixel Height Width Start
var dx=Math.abs(x1-x0);
var dy=Math.abs(y1-y0);
var pixHeight,pixWidth;
var penWidth=parseInt(pen.width);
pixHeight=Math.round(Math.sqrt((penWidth*penWidth)/((dy*dy)/(dx*dx)+1)));
pixWidth=Math.round(Math.sqrt(penWidth*penWidth-pixHeight*pixHeight));
if(pixWidth==0)
{
pixWidth=1;
}
if(pixHeight==0)
{
pixHeight=1;
}
///Pixel Height Width End
var steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep)
{
// swap
var tmp=x0;
x0=y0;
y0=tmp;
tmp=x1;
x1=y1;
y1=tmp;
}
if (x0 > x1)
{
// swap
var tmp=x0;
x0=x1;
x1=tmp;
tmp=y0;
y0=y1;
y1=tmp;
}
var deltax = x1 - x0;
var deltay = Math.abs(y1 - y0);
var error = deltax/2;
var ystep;
var y = y0;
if (y0";
divHeight=0;
xp=y;
yp=x;
}
}
if(x==x1)
{
if(divHeight!=0)
{
divHeight=divHeight+pixHeight;
iHtml[iHtml.length]="";
}
else
{
divHeight=pixHeight;
iHtml[iHtml.length]="";
}
}
}
else
{
if(x==x0)
{
xp=x;
yp=y;
}
else
{
if(y==yp)
{
divWidth=divWidth + 1;
}
else
{
divWidth=divWidth+pixWidth;
iHtml[iHtml.length]="";
divWidth=0;
xp=x;
yp=y;
}
}
if(x==x1)
{
if(divWidth!=0)
{
divWidth=divWidth+pixWidth;
iHtml[iHtml.length]="";
}
else
{
divWidth=pixWidth;
iHtml[iHtml.length]="";
}
}
}
error = error - deltay;
if (error < 0)
{
y = y + ystep;
error = error + deltax;
}
}
lineDiv.innerHTML=iHtml.join("");
return lineDiv;
}
//Private function returns array of x coordinates for y values
//for a line (algorithm same as drawLine method).
//Used by drawArc, fillArc and fillPolygon methods.
function getLinePixels(point0,point1)
{
function xData()
{
this.xMax=0;
this.xMin=0;
this.isVertex=false;
}
var x0, x1, y0, y1;
x0=point0.x;
x1=point1.x;
y0=point0.y;
y1=point1.y;
var xDataArray=new Array();
var steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep)
{
// swap
var tmp=x0;
x0=y0;
y0=tmp;
tmp=x1;
x1=y1;
y1=tmp;
}
if (x0 > x1)
{
// swap
var tmp=x0;
x0=x1;
x1=tmp;
tmp=y0;
y0=y1;
y1=tmp;
}
var deltax = x1 - x0;
var deltay = Math.abs(y1 - y0);
var error = deltax/2;
var ystep;
var y = y0;
if (y0=height || penWidth>=width)
return this.fillRectangle(pen.color,point,width,height);
phPoint=logicalToPhysicalPoint(point);
//Draw 4 sides of the rectangle.
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
rectDiv.innerHTML=iHtml.join("");
return rectDiv;
}
//Draw color filled rectangle at specified point with specified color, width and height
function fillRectangle(color,point,width,height)
{
//Check arguments for null values
if(!color || !point || !width || !height)
return false;
width=Math.round(width*scale);
height=Math.round(height*scale);
var rectDiv=canvasDiv.appendChild(document.createElement("div"));
phPoint=logicalToPhysicalPoint(point);
var hexColor=color.getHex();
//Draw a single div element
rectDiv.innerHTML="";
return rectDiv;
}
//This is a private function to draw an ellipse with width 1px.
//It is used by drawEllipse method.
//Mid point algorithm is used for the drawing
function drawEllipseSingle(pen,center,width,height)
{
//Check arguments for null values
if(!pen || !center || !width || !height)
return false;
var ellipseDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
var penWidth=parseInt(pen.width);
var hexColor=pen.color.getHex();
var a=Math.round(width/2);
var b=Math.round(height/2);
var xc=center.x;
var yc=center.y;
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
var yp=y;
var xp=x;
var divWidth;
var divHeight;
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(x==1 && y!=yp)
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
if(y!=yp)
{
divWidth=x-xp;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
yp=y;
xp=x;
}
if(b2*x >= a2*y)
{
divWidth=x-xp+1;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
}
yp=y;
xp=x;
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
if(x!=xp)
{
divHeight=yp-y;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
}
if(y==0)
{
divHeight=yp-y+1;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
}
}
ellipseDiv.innerHTML=iHtml.join("");
return ellipseDiv;
}
//Draw ellipse with specified center, width and height.
//Mid point algorithm is used for basic drawing.
function drawEllipse(pen,center,width,height)
{
//Check arguments for null values
if(!pen || !center || !width || !height)
return false;
width*=scale;
height*=scale;
var ellipseDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
phCenter=logicalToPhysicalPoint(center);
var penWidth=parseInt(pen.width);
if(penWidth<=1)
{
return drawEllipseSingle(pen,phCenter,width,height);
}
var hexColor=pen.color.getHex();
var a=Math.round(width/2);
var b=Math.round(height/2);
var xc=phCenter.x;
var yc=phCenter.y;
//For inner ellipse
var ai=a-penWidth + 1;
var bi=b-penWidth + 1;
//For drawing ellipse having width more than 1px, inner ellipse is required to be considered
var res=getInnerEllipse(phCenter,ai*2,bi*2)
var xArray=res[0];
var xArrayI=res[1];
var yi=bi;
var ai2=ai*ai;
var bi2=bi*bi;
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
var xp,yp;
xp=1;
yp=y;
var ypi=yi;
var xT;
var divWidth;
var divHeight=1;
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(y+1";
iHtml[iHtml.length]="";
xT=xT+2*(x-1)+1-divWidth;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
yp=y;
xp=x;
}
//Last step in loop
if(b2*x >= a2*y)
{
xT=xc-x;
divWidth=x+1-xArray[yp];
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xT=xT+2*x+1-divWidth;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
}
else
{
if(x==1 && y!=yp) //Topmost and bottom most points, to be tested
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
if(y!=yp)
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
yp=y;
}
//Last step in loop
if(y==bi || y==0)
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
}
}
xp=x;
yp=y;
divHeight=1;
var xpi=xArray[y];
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
if(y+1";
iHtml[iHtml.length]="";
xT=xT+2*xp+1-divWidth;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
xpi=xArray[y];
}
//Last step in loop
if(y==0)
{
divHeight=yp-y+1;
xT=xc-x;
divWidth=x+1-xArray[y];
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xT=xT+2*x+1-divWidth;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
xpi=xArray[y];
}
}
else
{
if(x!=xp)
{
divHeight=yp-y;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
xpi=xArray[y];
}
//Last step in loop
if(y==bi || y==0)
{
divHeight=yp-y+1;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
xpi=xArray[y];
}
}
}
ellipseDiv.innerHTML=iHtml.join("");
return ellipseDiv;
}
//For ellipse having width more than 1 px, get the coordinates for inner ellipse.
function getInnerEllipse(center,w,h)
{
var a=Math.round(w/2);
var b=Math.round(h/2);
var xc=center.x;
var yc=center.y;
xArray=new Array();
xArrayI=new Array();
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
xArray[y]=x;
xArrayI[y]=x;
var divWidth;
var divHeight;
//Upper and Lower portions of the ellipse
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(!xArray[y])
xArray[y]=x;
xArrayI[y]=x;
}
//Left and Right portions of the ellipse
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
xArray[y]=x;
xArrayI[y]=x;
}
return new Array(xArray,xArrayI);
}
//Draw circle with specified center and radius.
//Uses drawEllipse method only.
function drawCircle(pen,center,radius)
{
//Check arguments for null values
if(!pen || !center || !radius)
return false;
return drawEllipse(pen,center,2*radius,2*radius);
}
//Draw circle filled with the specified color alongwith specified center and radius.
//Uses drawEllipse method only.
function fillCircle(color,center,radius)
{
//Check arguments for null values
if(!color || !center || !radius)
return false;
return fillEllipse(color,center,2*radius,2*radius);
}
//Draw ellipse filled with specified color and other parameters, center, width and height.
//Mid point algorithm is used for basic ellipse drawing.
function fillEllipse(color,center,width,height)
{
//Check arguments for null values
if(!color || !center || !width || !height)
return false;
width*=scale;
height*=scale;
var ellipseDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
phCenter=logicalToPhysicalPoint(center);
var a=Math.round(width/2);
var b=Math.round(height/2);
var xc=phCenter.x;
var yc=phCenter.y;
var hexColor=color.getHex();
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
var xp,yp;
xp=1;
yp=y;
//Upper and Lower portion of the ellipse
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(x==1 && y!=yp) //Topmost and bottom most points, to be tested
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
if(y!=yp)
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
yp=y;
xp=x;
}
//Last step in loop
if(b2*x >= a2*y)
{
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
}
xp=x;
yp=y;
var divHeight=1;
//Left and Right portion of the ellipse
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
if(x!=xp)
{
divHeight=yp-y;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
xp=x;
yp=y;
}
//Last step in loop
if(y==0)
{
divHeight=yp-y+1;
iHtml[iHtml.length]="";
iHtml[iHtml.length]="";
}
}
ellipseDiv.innerHTML=iHtml.join("");
return ellipseDiv;
}
//Draw arc filled with specified color, center, width, height, start angle and swap angle.
function fillArc(color,center,width,height,startAngle,swapAngle)
{
//Check arguments for null values
if(!color || !center || !width || !height || startAngle==null || swapAngle==null)
return false;
width*=scale;
height*=scale;
if(swapAngle==0)
return;
var arcDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
phCenter=logicalToPhysicalPoint(center);
var saD; //arc start angle degrees.
if(startAngle>360)
saD=startAngle%360;
else
saD=startAngle;
var swD; //swap angle in degrees.
if(swapAngle>360)
swD=swapAngle%360;
else
swD=swapAngle;
var eaD; //arc end angle degrees.
eaD=parseFloat(saD)+parseFloat(swD);
if(eaD>360)
eaD=eaD%360;
//For cartecian coordinate system.
if(coordinateSystem=="cartecian")
{
saD=360-saD;
eaD=360-eaD;
var tempAD;
tempAD=saD;
saD=eaD;
eaD=tempAD;
}
var x1,y1,x2,y2;
var saR=saD*Math.PI/180;
var swR=swD*Math.PI/180;
var eaR=eaD*Math.PI/180;
//For start angle
if((saD<=45 && saD>=0) || (saD>=135 && saD<=225) || (saD>=315 && saD<=360))
{
y1=Math.round(phCenter.y+Math.sin(saR)*width/2);
if(saD>=90 && saD<=270)
x1=Math.round(phCenter.x-width/2);
else
x1=Math.round(phCenter.x+width/2);
}
else
{
x1=Math.round(phCenter.x+Math.cos(saR)*height/2);
if(saD>=0 && saD<=180)
y1=Math.round(phCenter.y+height/2);
else
y1=Math.round(phCenter.y-height/2);
}
//For end angle
if((eaD<=45 && eaD>=0) || (eaD>=135 && eaD<=225) || (eaD>=315 && eaD<=360))
{
y2=Math.round(phCenter.y+Math.sin(eaR)*width/2);
if(eaD>=90 && eaD<=270)
x2=Math.round(phCenter.x-width/2);
else
x2=Math.round(phCenter.x+width/2);
}
else
{
x2=Math.round(phCenter.x+Math.cos(eaR)*height/2);
if(eaD>=0 && eaD<=180)
y2=Math.round(phCenter.y+height/2);
else
y2=Math.round(phCenter.y-height/2);
}
//Get the pixel arrays for the lines croping the ellipse to form an arc.
xDataArraySa=getLinePixels(phCenter,new jsPoint(x1,y1));
xDataArrayEa=getLinePixels(phCenter,new jsPoint(x2,y2));
var hexColor=color.getHex();
var a=Math.round(width/2);
var b=Math.round(height/2);
var xc=phCenter.x;
var yc=phCenter.y;
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
var xp,yp;
var divX1,divX1pU,divX1pD,divX2,divX2pU,divX2pD,divY1,divY2,saX,eaX,saXp,eaXp,xpU,xpD,ypU,ypD;
var divWidthOrg,divWidth1,divWidth2,divWidth3,divWidth4,divWidth1p,divWidth2p,divWidth3p,divWidth4p,divHeight;
var draw1p,draw2p,draw3p,draw4p;
xp=1;
yp=y;
//Upper and lower portion of the ellipse constutuing the arc
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(x==1 && y!=yp) //Topmost and bottom most points, to be tested
{
divY1=yc+yp-1;
divY2=yc-yp;
divWidthOrg=1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
fillArcSegOut(true);
if(eaD<=saD)
fillArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
fillArcSegOut(false);
if(eaD<=saD)
fillArcSegOut(true);
}
else
{
fillArcSegOut(true);
fillArcSegOut(false);
}
}
else if(y!=yp)
{
divY1=yc+yp;
divY2=yc-yp;
divWidthOrg=2*(x-1)+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x+1;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
fillArcSegOut(true);
if(eaD<=saD)
fillArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
fillArcSegOut(false);
if(eaD<=saD)
fillArcSegOut(true);
}
else
{
fillArcSegOut(true);
fillArcSegOut(false);
}
yp=y;
xp=x;
}
//Last step in loop
if(b2*x >= a2*y)
{
divY1=yc+yp;
divY2=yc-yp;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
fillArcSegOut(true);
if(eaD<=saD)
fillArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
fillArcSegOut(false);
if(eaD<=saD)
fillArcSegOut(true);
}
else
{
fillArcSegOut(true);
fillArcSegOut(false);
}
}
}
xp=x;
yp=y;
divHeight=1;
//Similar code as in next while loop for first y before the loop. Only values are retrieved and no drawing.
divY1=yc+y;
divY2=yc-y;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
xDataArrayEa.pop();
fillArcSegIn(true,true);
if(eaD<=saD)
fillArcSegIn(false,true);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
xDataArrayEa.pop();
if(y!=0)
fillArcSegIn(false,true);
if(eaD<=saD)
fillArcSegIn(true,true);
}
else
{
if(saD>=180 && saD<360)
xDataArraySa.pop();
else
xDataArrayEa.pop();
fillArcSegIn(true,true);
if(y!=0)
{
divX1=xc-x;
fillArcSegIn(false,true);
}
}
//Left and Right portion of the ellipse ellipse constutuing the arc.
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
divY1=yc+y;
divY2=yc-y;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
fillArcSegIn(true);
if(eaD<=saD)
fillArcSegIn(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
if(y!=0)
fillArcSegIn(false);
if(eaD<=saD)
fillArcSegIn(true);
}
else
{
fillArcSegIn(true);
if(y!=0)
{
divX1=xc-x;
fillArcSegIn(false);
}
}
}
arcDiv.innerHTML=iHtml.join("");
return arcDiv;
//Internal function: Arc segment for left and right portion of the ellipse constutuing the arc.
function fillArcSegIn(isUpperHalf,valueOnly)
{
var divY;
var xDataArray1,xDataArray1;
var divWidthFirst=divWidthOrg;
var divWidthSecond=divWidthOrg;
var drawFirst=false;
var drawSecond=false;
if(isUpperHalf)
{
var draw1=false; //upper half (in all comments upper & lower are in context of cartecian system)
var draw3=false; //upper half second
divY=divY1;
xDataArray1=xDataArraySa;
xDataArray2=xDataArrayEa;
saDvar=saD;
eaDvar=eaD;
}
else
{
var draw2=false; //lower half
var draw4=false; //lower half second
divY=divY2;
xDataArray2=xDataArraySa;
xDataArray1=xDataArrayEa;
saDvar=360-eaD;
eaDvar=360-saD;
}
if(eaDvar>saDvar)
{
if(xDataArray2[divY] && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
eaX=xDataArray2[divY].xMin;
if(xDataArray1[divY] && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-eaX;
}
else
{
divWidthFirst=divX1+divWidthOrg-eaX;
}
divX1=eaX;
drawFirst=true;
}
else if(xDataArray1[divY] && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar>90 && saDvar<90)
{
drawFirst=true;
}
}
else //saDvar>=eaDvar
{
if(xDataArray1[divY] && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar<90 && saDvar<90)
{
drawFirst=true;
}
if(xDataArray2[divY] && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
divX2=xDataArray2[divY].xMin;
divWidthSecond=divWidthOrg-xDataArray2[divY].xMin+divX1;
drawSecond=true;
}
else if(eaDvar>90 && saDvar>90)
{
divX2=divX1;
divWidthSecond=divWidthOrg;
drawSecond=true;
}
}
if(isUpperHalf)
{
if(drawFirst)
draw1=true;
if(drawSecond)
draw3=true;
divWidth1=divWidthFirst;
divWidth3=divWidthSecond;
}
else
{
if(drawFirst)
draw2=true;
if(drawSecond)
draw4=true;
divWidth2=divWidthFirst;
divWidth4=divWidthSecond;
}
if(saD>=0 && saD<180 && eaD>=0 && eaD<180 && saD>eaD)
{
draw2=true;
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<360 && saD>eaD)
{
draw1=true;
}
if(!divX2)
divX2="";
if(!divX1)
divX1="";
if(!valueOnly)
{
if(isUpperHalf)
{
if(x!=xpU || divX1pU!=divX1 || divX2pU!=divX2 || divWidth1!=divWidth1p || divWidth3!=divWidth3p)
{
divHeight=ypU-y;
if(draw3p)
{
if(divX2pU!=null)
iHtml[iHtml.length]="";
}
if(draw1p)
{
if(divX1pU!=null)
iHtml[iHtml.length]="";
}
if(draw1p||draw3p)
{
divX1pU=divX1;
draw1p=draw1;
draw3p=draw3;
xpU=x;
ypU=y;
divWidth1p=divWidth1;
divWidth3p=divWidth3;
divX2pU=divX2;
}
}
}
else
{
if(x!=xpD || divX1pD!=divX1 || divX2pD!=divX2 || divWidth2!=divWidth2p || divWidth4!=divWidth4p)
{
divHeight=ypD-y;
if(draw4p)
{
if(divX2pD!=null)
iHtml[iHtml.length]="";
}
if(draw2p)
{
if(divX1pD!=null)
iHtml[iHtml.length]="";
}
if(draw2p||draw4p)
{
divX1pD=divX1;
draw2p=draw2;
draw4p=draw4;
xpD=x;
ypD=y;
divWidth2p=divWidth2;
divWidth4p=divWidth4;
divX2pD=divX2;
}
}
}
}
//To get only values; used for first y value before loop.
if(valueOnly)
{
if(isUpperHalf)
{
draw1p=draw1;
draw3p=draw3;
if(draw1p)
divX1pU=divX1;
if(draw3p)
divX2pU=divX2;
if(draw1p||draw3p)
{
ypU=y;
xpU=x;
}
else
{
ypU=0;
xpU=0;
}
divWidth1p=divWidth1;
divWidth3p=divWidth3;
}
else
{
draw2p=draw2;
draw4p=draw4;
if(draw2p)
divX1pD=divX1;
if(draw4p)
divX2pD=divX2;
if(draw2p||draw4p)
{
ypD=y;
xpD=x;
}
else
{
ypD=0;
xpD=0;
}
divWidth2p=divWidth2;
divWidth4p=divWidth4;
}
}
if(!isUpperHalf)
{
draw2p=draw2;
draw4p=draw4;
}
else
{
draw1p=draw1;
draw3p=draw3;
}
if(y==1 && !isUpperHalf)
{
divHeight=ypD-y+1;
if(draw4)
{
iHtml[iHtml.length]="";
}
if(draw2)
{
iHtml[iHtml.length]="";
}
}
if(y==0 && isUpperHalf)
{
divHeight=ypU-y+1;
if(draw3)
{
iHtml[iHtml.length]="";
}
if(draw1)
{
iHtml[iHtml.length]="";
}
}
}
//Internal function: Arc segment for upper and lower portion of the ellipse constutuing the arc.
function fillArcSegOut(isUpperHalf)
{
var divY;
var xDataArray1,xDataArray1;
var divWidthFirst=divWidthOrg;
var divWidthSecond=divWidthOrg;
var drawFirst=false;
var drawSecond=false;
if(isUpperHalf)
{
var draw1=false; //upper half
var draw3=false; //upper half second
divY=divY1;
xDataArray1=xDataArraySa;
xDataArray2=xDataArrayEa;
saDvar=saD;
eaDvar=eaD;
}
else
{
var draw2=false; //lower half
var draw4=false; //lower half second
divY=divY2;
xDataArray2=xDataArraySa;
xDataArray1=xDataArrayEa;
saDvar=360-eaD;
eaDvar=360-saD;
}
if(eaDvar>saDvar)
{
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
eaX=xDataArray2[divY].xMin;
if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-eaX;
}
else
{
divWidthFirst=divX1+divWidthOrg-eaX;
}
divX1=eaX;
drawFirst=true;
}
else if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar>90 && saDvar<90)
{
drawFirst=true;
}
}
else //saDvar>eaDvar
{
if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar<90 && saDvar<90)
{
drawFirst=true;
}
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
divX2=xDataArray2[divY].xMin;
divWidthSecond=divWidthOrg-xDataArray2[divY].xMin+divX1;
drawSecond=true;
}
else if(eaDvar>90 && saDvar>90)
{
divX2=divX1;
divWidthSecond=divWidthOrg;
drawSecond=true;
}
}
if(isUpperHalf)
{
if(drawFirst)
draw1=true;
if(drawSecond)
draw3=true;
divWidth1=divWidthFirst;
divWidth3=divWidthSecond;
}
else
{
if(drawFirst)
draw2=true;
if(drawSecond)
draw4=true;
divWidth2=divWidthFirst;
divWidth4=divWidthSecond;
}
if(saD>=0 && saD<180 && eaD>=0 && eaD<180 && saD>eaD)
{
draw2=true;
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<360 && saD>eaD)
{
draw1=true;
}
if(divX2==null)
divX2="X";
if(divX1==null)
divX1="X";
if(isUpperHalf)
{
divHeight=1;
if(draw3)
{
if(divX2!="X")
iHtml[iHtml.length]="";
}
if(draw1)
{
if(divX1!="X")
iHtml[iHtml.length]="";
}
}
else
{
divHeight=1;
if(draw4)
{
if(divX2!="X")
iHtml[iHtml.length]="";
}
if(draw2)
{
if(divX1!="X")
iHtml[iHtml.length]="";
}
}
}
}
//Draw arc with specified center, width, height, start angle and swap angle.
function drawArc(pen,center,width,height,startAngle,swapAngle)
{
//Check arguments for null values
if(!pen || !center || !width || !height || startAngle==null || swapAngle==null)
return false;
width*=scale;
height*=scale;
if(swapAngle==0)
return;
var arcDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
phCenter=logicalToPhysicalPoint(center);
var saD; //arc start angle degrees.
if(startAngle>360)
saD=startAngle%360;
else
saD=startAngle;
var swD; //swap angle in degrees.
if(swapAngle>360)
swD=swapAngle%360;
else
swD=swapAngle;
var eaD; //arc end angle degrees.
eaD=parseFloat(saD)+parseFloat(swD);
if(eaD>360)
eaD=eaD%360;
//For cartecian coordinate system.
if(coordinateSystem=="cartecian")
{
saD=360-saD;
eaD=360-eaD;
var tempAD;
tempAD=saD;
saD=eaD;
eaD=tempAD;
}
var x1,y1,x2,y2;
var saR=saD*Math.PI/180;
var swR=swD*Math.PI/180;
var eaR=eaD*Math.PI/180;
//For start angle
if((saD<=45 && saD>=0) || (saD>=135 && saD<=225) || (saD>=315 && saD<=360))
{
y1=Math.round(phCenter.y+Math.sin(saR)*width/2);
if(saD>=90 && saD<=270)
x1=Math.round(phCenter.x-width/2);
else
x1=Math.round(phCenter.x+width/2);
}
else
{
x1=Math.round(phCenter.x+Math.cos(saR)*height/2);
if(saD>=0 && saD<=180)
y1=Math.round(phCenter.y+height/2);
else
y1=Math.round(phCenter.y-height/2);
}
//For end angle
if((eaD<=45 && eaD>=0) || (eaD>=135 && eaD<=225) || (eaD>=315 && eaD<=360))
{
y2=Math.round(phCenter.y+Math.sin(eaR)*width/2);
if(eaD>=90 && eaD<=270)
x2=Math.round(phCenter.x-width/2);
else
x2=Math.round(phCenter.x+width/2);
}
else
{
x2=Math.round(phCenter.x+Math.cos(eaR)*height/2);
if(eaD>=0 && eaD<=180)
y2=Math.round(phCenter.y+height/2);
else
y2=Math.round(phCenter.y-height/2);
}
//Get the pixel arrays for the lines croping the ellipse to form an arc.
xDataArraySa=getLinePixels(phCenter,new jsPoint(x1,y1));
xDataArrayEa=getLinePixels(phCenter,new jsPoint(x2,y2));
var hexColor=pen.color.getHex();
var a=Math.round(width/2);
var b=Math.round(height/2);
var xc=phCenter.x;
var yc=phCenter.y;
var x=0;
var y=b;
var a2=a*a;
var b2=b*b;
var hexColor=pen.color.getHex();
//For Inner Ellipse
var ai=a-parseInt(pen.width)+1;
var bi=b-parseInt(pen.width)+1;
var res=getInnerEllipse(phCenter,ai*2,bi*2)
var xArray=res[0];
var xArrayI=res[1];
xArray.pop();
xArrayI.pop();
var xp,yp;
var divX1,divX1pU,divX1pD,divX2,divX2pU,divX2pD,divY1,divY2,saX,eaX,saXp,eaXp,xpU,xpD,ypU,ypD,divX1i,divX2i,divX1pUi,divX1pDi,divX2pUi,divX2pDi;
var divWidthOrg,divWidth1,divWidth2,divWidth3,divWidth4,divWidth1p,divWidth2p,divWidth3p,divWidth4p,divHeight,divWidth1i,divWidth2i,divWidth3i,divWidth4i,divWidth1pi,divWidth2pi,divWidth3pi,divWidth4pi;
var draw1p,draw2p,draw3p,draw4p;
xp=1;
yp=y;
//Upper and lower portion of the ellipse constutuing the arc
while(b2*x < a2*y)
{
x++;
if((b2*x*x + a2*(y-0.5)*(y-0.5) - a2*b2) >=0)
y--;
if(x==1 && y!=yp) //Topmost and bottom most points, to be tested
{
divY1=yc+yp-1;
divY2=yc-yp;
divWidthOrg=1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
drawArcSegOut(true);
if(eaD<=saD)
drawArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
drawArcSegOut(false);
if(eaD<=saD)
drawArcSegOut(true);
}
else
{
drawArcSegOut(true);
drawArcSegOut(false);
}
}
else if(y!=yp)
{
divY1=yc+yp;
divY2=yc-yp;
divWidthOrg=2*(x-1)+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x+1;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
drawArcSegOut(true);
if(eaD<=saD)
drawArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
drawArcSegOut(false);
if(eaD<=saD)
drawArcSegOut(true);
}
else
{
drawArcSegOut(true);
drawArcSegOut(false);
}
yp=y;
xp=x;
}
//Last step in loop
if(b2*x >= a2*y)
{
divY1=yc+yp;
divY2=yc-yp;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
drawArcSegOut(true);
if(eaD<=saD)
drawArcSegOut(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
drawArcSegOut(false);
if(eaD<=saD)
drawArcSegOut(true);
}
else
{
drawArcSegOut(true);
drawArcSegOut(false);
}
}
}
xp=x;
yp=y;
divHeight=1;
//Similar code as in next while loop for first y before the loop. Only values are retrieved and no drawing.
divY1=yc+y;
divY2=yc-y;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
xDataArrayEa.pop();
drawArcSegIn(true,true);
if(eaD<=saD)
drawArcSegIn(false,true);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
xDataArrayEa.pop();
if(y!=0)
drawArcSegIn(false,true);
if(eaD<=saD)
drawArcSegIn(true,true);
}
else
{
if(saD>=180 && saD<360)
xDataArraySa.pop();
else
xDataArrayEa.pop();
drawArcSegIn(true,true);
if(y!=0)
{
divX1=xc-x;
drawArcSegIn(false,true);
}
}
//Left and Right portion of the ellipse ellipse constutuing the arc.
while(y!=0)
{
y--;
if((b2*(x+0.5)*(x+0.5) + a2*y*y - a2*b2)<=0)
x++;
divY1=yc+y;
divY2=yc-y;
divWidthOrg=2*x+1;
divWidth1=divWidthOrg;
divWidth2=divWidthOrg;
divWidth3=divWidthOrg;
divWidth4=divWidthOrg;
divX1=xc-x;
if(saD>=0 && saD<180 && eaD>=0 && eaD<180)
{
drawArcSegIn(true);
if(eaD<=saD)
drawArcSegIn(false);
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<=360)
{
if(y!=0)
drawArcSegIn(false);
if(eaD<=saD)
drawArcSegIn(true);
}
else
{
drawArcSegIn(true);
if(y!=0)
{
divX1=xc-x;
drawArcSegIn(false);
}
}
}
arcDiv.innerHTML=iHtml.join("");
return arcDiv;
//Internal function: Arc segment for left and right portion of the ellipse constutuing the arc.
function drawArcSegIn(isUpperHalf,valueOnly)
{
var divY;
var xDataArray1,xDataArray1;
var divWidthFirst=divWidthOrg;
var divWidthSecond=divWidthOrg;
var drawFirst=false;
var drawSecond=false;
var xIn;
if(isUpperHalf)
{
var draw1=false; //upper half
var draw3=false; //upper half second
divY=divY1;
xDataArray1=xDataArraySa;
xDataArray2=xDataArrayEa;
saDvar=saD;
eaDvar=eaD;
}
else
{
var draw2=false; //lower half
var draw4=false; //lower half second
divY=divY2;
xDataArray2=xDataArraySa;
xDataArray1=xDataArrayEa;
saDvar=360-eaD;
eaDvar=360-saD;
}
if(eaDvar>saDvar)
{
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
eaX=xDataArray2[divY].xMin;
if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-eaX;
}
else
{
divWidthFirst=divX1+divWidthOrg-eaX;
}
divX1=eaX;
drawFirst=true;
}
else if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar>90 && saDvar<90)
{
drawFirst=true;
}
}
else //saDvar>eaDvar
{
if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar<90 && saDvar<90)
{
drawFirst=true;
}
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
divX2=xDataArray2[divY].xMin;
divWidthSecond=divWidthOrg-xDataArray2[divY].xMin+divX1;
drawSecond=true;
}
else if(eaDvar>90 && saDvar>90)
{
divX2=divX1;
divWidthSecond=divWidthOrg;
drawSecond=true;
}
}
if(isUpperHalf)
{
if(drawFirst)
draw1=true;
if(drawSecond)
draw3=true;
divWidth1=divWidthFirst;
divWidth3=divWidthSecond;
}
else
{
if(drawFirst)
draw2=true;
if(drawSecond)
draw4=true;
divWidth2=divWidthFirst;
divWidth4=divWidthSecond;
}
if(saD>=0 && saD<180 && eaD>=0 && eaD<180 && saD>eaD)
{
draw2=true;
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<360 && saD>eaD)
{
draw1=true;
}
//Start: Only for drawArc (not in fillArc)
if(draw1)
{
if(xArray[divY1-yc]!=null && divX1!=null)
{
if(xc+xArray[divY1-yc]<=divX1+divWidth1)
{
if(divWidth1>divX1+divWidth1-xc-xArray[divY1-yc])
{
divX1i=xc+xArray[divY1-yc];
divWidth1i=divX1+divWidth1-xc-xArray[divY1-yc];
}
}
else
divX1i=null;
if(divX1<=xc-xArray[divY1-yc]+1)
{
if(divWidth1>xc-xArray[divY1-yc]-divX1+1)
divWidth1=xc-xArray[divY1-yc]-divX1+1;
}
else if(divWidth1>=divX1+divWidth1-xc-xArray[divY1-yc]+1)
divX1=null;
}
}
if(draw3)
{
if(xArray[divY1-yc]!=null && divX2!=null)
{
if(xc+xArray[divY1-yc]<=divX2+divWidth3)
{
if(divWidth3>divX2+divWidth3-xc-xArray[divY1-yc])
{
divX2i=xc+xArray[divY1-yc];
divWidth3i=divX2+divWidth3-xc-xArray[divY1-yc];
}
}
else
divX2i=null;
if(divX2<=xc-xArray[divY1-yc]+1)
{
if(divWidth3>xc-xArray[divY1-yc]-divX2+1)
divWidth3=xc-xArray[divY1-yc]-divX2+1;
}
else if(divWidth3>=divX2+divWidth3-xc-xArray[divY1-yc]+1)
divX2=null;
}
}
//Lower Half
if(draw2)
{
if(xArray[divY1-yc]!=null && divX1!=null)
{
if(xc+xArray[divY1-yc]<=divX1+divWidth2)
{
if(divWidth2>divX1+divWidth2-xc-xArray[divY1-yc])
{
divX1i=xc+xArray[divY1-yc];
divWidth2i=divX1+divWidth2-xc-xArray[divY1-yc];
}
}
else
divX1i=null;
if(divX1<=xc-xArray[divY1-yc]+1)
{
if(divWidth2>xc-xArray[divY1-yc]-divX1+1)
divWidth2=xc-xArray[divY1-yc]-divX1+1;
}
else if(divWidth2>=divX1+divWidth2-xc-xArray[divY1-yc]+1)
divX1=null;
}
}
if(draw4)
{
if(xArray[divY1-yc]!=null && divX2!=null)
{
if(xc+xArray[divY1-yc]<=divX2+divWidth4)
{
if(divWidth4>divX2+divWidth4-xc-xArray[divY1-yc])
{
divX2i=xc+xArray[divY1-yc];
divWidth4i=divX2+divWidth4-xc-xArray[divY1-yc];
}
}
else
divX2i=null;
if(divX2<=xc-xArray[divY1-yc]+1)
{
if(divWidth4>xc-xArray[divY1-yc]-divX2+1)
divWidth4=xc-xArray[divY1-yc]-divX2+1;
}
else if(divWidth4>=divX2+divWidth4-xc-xArray[divY1-yc]+1)
divX2=null;
}
}
//End: Only for drawArc (not in fillArc)
if(divX2==null)
divX2="";
if(divX1==null)
divX1="";
if(!valueOnly)
{
if(isUpperHalf)
{
if(x!=xpU || divX1pU!=divX1 || divX1pUi!=divX1i || divX2pU!=divX2 || divX2pUi!=divX2i || divWidth1!=divWidth1p || divWidth3!=divWidth3p || divWidth1i!=divWidth1pi || divWidth3i!=divWidth3pi)
{
divHeight=ypU-y;
if(draw3p)
{
if(divX2pU!=null && divX2pU!="")
iHtml[iHtml.length]="";
if(divX2pUi!=null && divX2pUi!="")
iHtml[iHtml.length]="";
}
if(draw1p)
{
if(divX1pU!=null && divX1pU!="")
iHtml[iHtml.length]="";
if(divX1pUi!=null && divX1pUi!="")
iHtml[iHtml.length]="";
}
if(draw1p||draw3p)
{
divX1pU=divX1;
divX1pUi=divX1i;
draw1p=draw1;
draw3p=draw3;
xpU=x;
ypU=y;
divWidth1p=divWidth1;
divWidth3p=divWidth3;
divX2pU=divX2;
divX2pUi=divX2i;
divWidth1pi=divWidth1i;
divWidth3pi=divWidth3i;
}
}
}
else
{
if(x!=xpD || divX1pD!=divX1 ||divX1pDi!=divX1i || divX2pD!=divX2 || divWidth2!=divWidth2p || divWidth2i!=divWidth2pi || divWidth4!=divWidth4p || divWidth4i!=divWidth4pi)
{
divHeight=ypD-y;
if(draw4p)
{
if(divX2pD!=null && divX2pD!="")
iHtml[iHtml.length]="";
if(divX2pDi!=null && divX2pDi!="")
iHtml[iHtml.length]="";
}
if(draw2p)
{
if(divX1pD!=null && divX1pD!="")
iHtml[iHtml.length]="";
if(divX1pDi!=null && divX1pDi!="")
iHtml[iHtml.length]="";
}
if(draw2p||draw4p)
{
divX1pD=divX1;
divX1pDi=divX1i;
draw2p=draw2;
draw4p=draw4;
xpD=x;
ypD=y;
divWidth2p=divWidth2;
divWidth4p=divWidth4;
divX2pD=divX2;
divX2pDi=divX2i;
divWidth2pi=divWidth2i;
divWidth4pi=divWidth4i;
}
}
}
}
//To get only values; used for first y value before loop.
if(valueOnly)
{
if(isUpperHalf)
{
draw1p=draw1;
draw3p=draw3;
if(draw1p)
{
divX1pU=divX1;
divX1pUi=divX1i;
}
if(draw3p)
{
divX2pU=divX2;
divX2pUi=divX2i;
}
if(draw1p||draw3p)
{
ypU=y;
xpU=x;
}
else
{
ypU=0;
xpU=0;
}
divWidth1p=divWidth1;
divWidth3p=divWidth3;
divWidth1pi=divWidth1i;
divWidth3pi=divWidth3i;
}
else
{
draw2p=draw2;
draw4p=draw4;
if(draw2p)
{
divX1pD=divX1;
divX1pDi=divX1i;
}
if(draw4p)
{
divX2pD=divX2;
divX2pDi=divX2i;
}
if(draw2p||draw4p)
{
ypD=y;
xpD=x;
}
else
{
ypD=0;
xpD=0;
}
divWidth2p=divWidth2;
divWidth4p=divWidth4;
divWidth2pi=divWidth2i;
divWidth4pi=divWidth4i;
}
}
if(!isUpperHalf)
{
draw2p=draw2;
draw4p=draw4;
}
else
{
draw1p=draw1;
draw3p=draw3;
}
if(y==1 && !isUpperHalf)
{
divHeight=ypD-y+1;
if(draw4)
{
if(divX2!="")
iHtml[iHtml.length]="";
if(divX2i!=null)
iHtml[iHtml.length]="";
}
if(draw2)
{
if(divX1!="")
iHtml[iHtml.length]="";
if(divX1i!=null)
iHtml[iHtml.length]="";
}
}
if(y==0 && isUpperHalf)
{
divHeight=ypU-y+1;
if(draw3)
{
if(divX2!="")
iHtml[iHtml.length]="";
if(divX2i!=null)
iHtml[iHtml.length]="";
}
if(draw1)
{
if(divX1!="")
iHtml[iHtml.length]="";
if(divX1i!=null)
iHtml[iHtml.length]="";
}
}
}
//Internal function: Arc segment for upper and lower portion of the ellipse constutuing the arc.
function drawArcSegOut(isUpperHalf)
{
var divY;
var xDataArray1,xDataArray1;
var divWidthFirst=divWidthOrg;
var divWidthSecond=divWidthOrg;
var drawFirst=false;
var drawSecond=false;
if(isUpperHalf)
{
var draw1=false; //upper half
var draw3=false; //upper half second
divY=divY1;
xDataArray1=xDataArraySa;
xDataArray2=xDataArrayEa;
saDvar=saD;
eaDvar=eaD;
}
else
{
var draw2=false; //lower half
var draw4=false; //lower half second
divY=divY2;
xDataArray2=xDataArraySa;
xDataArray1=xDataArrayEa;
saDvar=360-eaD;
eaDvar=360-saD;
}
if(eaDvar>saDvar)
{
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
eaX=xDataArray2[divY].xMin;
if(xDataArray1[divY] && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-eaX;
}
else
{
divWidthFirst=divX1+divWidthOrg-eaX;
}
divX1=eaX;
drawFirst=true;
}
else if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar>90 && saDvar<90)
{
drawFirst=true;
}
}
else //saDvar>eaDvar
{
if(xDataArray1[divY]!=null && divX1+divWidthOrg>=xDataArray1[divY].xMax+1 && divX1<=xDataArray1[divY].xMax+1)
{
saX=xDataArray1[divY].xMax+1;
divWidthFirst=saX-divX1;
drawFirst=true;
}
else if(eaDvar<90 && saDvar<90)
{
drawFirst=true;
}
if(xDataArray2[divY]!=null && divX1+divWidthOrg>=xDataArray2[divY].xMin && divX1<=xDataArray2[divY].xMin)
{
divX2=xDataArray2[divY].xMin;
divWidthSecond=divWidthOrg-xDataArray2[divY].xMin+divX1;
drawSecond=true;
}
else if(eaDvar>90 && saDvar>90)
{
divX2=divX1;
divWidthSecond=divWidthOrg;
drawSecond=true;
}
}
if(isUpperHalf)
{
if(drawFirst)
draw1=true;
if(drawSecond)
draw3=true;
divWidth1=divWidthFirst;
divWidth3=divWidthSecond;
}
else
{
if(drawFirst)
draw2=true;
if(drawSecond)
draw4=true;
divWidth2=divWidthFirst;
divWidth4=divWidthSecond;
}
if(saD>=0 && saD<180 && eaD>=0 && eaD<180 && saD>eaD)
{
draw2=true;
}
else if(saD>=180 && saD<360 && eaD>=180 && eaD<360 && saD>eaD)
{
draw1=true;
}
//Start: Only for drawArc (not in fillArc)
if(draw1)
{
if(xArray[divY1-yc] && divX1!=null)
{
if(xc+xArray[divY1-yc]<=divX1+divWidth1)
{
if(divWidth1>divX1+divWidth1-xc-xArray[divY1-yc])
{
divX1i=xc+xArray[divY1-yc];
divWidth1i=divX1+divWidth1-xc-xArray[divY1-yc];
}
}
else
divX1i="X";
if(divX1xc-xArray[divY1-yc]-divX1+1)
divWidth1=xc-xArray[divY1-yc]-divX1+1;
}
else if(divWidth1>=divX1+divWidth1-xc-xArray[divY1-yc]+1)
divX1="X";
}
}
if(draw3)
{
if(xArray[divY1-yc] && divX2!=null)
{
if(xc+xArray[divY1-yc]<=divX2+divWidth3)
{
if(divWidth3>divX2+divWidth3-xc-xArray[divY1-yc])
{
divX2i=xc+xArray[divY1-yc];
divWidth3i=divX2+divWidth3-xc-xArray[divY1-yc];
}
}
else
divX2i="X";
if(divX2<=xc-xArray[divY1-yc]+1)
{
if(divWidth3>xc-xArray[divY1-yc]-divX2+1)
divWidth3=xc-xArray[divY1-yc]-divX2+1;
}
else if(divWidth3>=divX2+divWidth3-xc-xArray[divY1-yc]+1)
divX2="X";
}
}
//Lower Half
if(draw2)
{
if(xArray[divY1-yc] && divX1!=null)
{
if(xc+xArray[divY1-yc]<=divX1+divWidth2)
{
if(divWidth2>divX1+divWidth2-xc-xArrayI[divY1-yc])
{
divX1i=xc+xArray[divY1-yc];
divWidth2i=divX1+divWidth2-xc-xArray[divY1-yc];
}
}
else
divX1i="X";
if(divX1<=xc-xArray[divY1-yc]+1)
{
if(divWidth2>xc-xArray[divY1-yc]-divX1+1)
divWidth2=xc-xArray[divY1-yc]-divX1+1;
}
else if(divWidth2>=divX1+divWidth2-xc-xArray[divY1-yc]+1)
divX1="X";
}
}
if(draw4)
{
if(xArrayI[divY1-yc] && divX2!=null)
{
if(xc+xArray[divY1-yc]<=divX2+divWidth4)
{
if(divWidth4>divX2+divWidth4-xc-xArray[divY1-yc])
{
divX2i=xc+xArray[divY1-yc];
divWidth4i=divX2+divWidth4-xc-xArray[divY1-yc];
}
}
else
divX2i="X";
if(divX2<=xc-xArray[divY1-yc]+1)
{
if(divWidth4>xc-xArray[divY1-yc]-divX2+1)
divWidth4=xc-xArray[divY1-yc]-divX2+1;
}
else if(divWidth4>=divX2+divWidth4-xc-xArray[divY1-yc]+1)
divX2="X";
}
}
//End: Only for drawArc (not in fillArc)
if(divX2==null)
divX2="X";
if(divX1==null)
divX1="X";
if(divX2i==null)
divX2i="X";
if(divX1i==null)
divX1i="X";
if(isUpperHalf)
{
divHeight=1;
if(draw3)
{
if(divX2!="X")
iHtml[iHtml.length]="";
if(divX2i!="X")
iHtml[iHtml.length]="";
}
if(draw1)
{
if(divX1!="X")
iHtml[iHtml.length]="";
if(divX1i!="X")
iHtml[iHtml.length]="";
}
}
else
{
divHeight=1;
if(draw4)
{
if(divX2!="X")
iHtml[iHtml.length]="";
if(divX2i!="X")
iHtml[iHtml.length]="";
}
if(draw2)
{
if(divX1!="X")
iHtml[iHtml.length]="";
if(divX1i!="X")
iHtml[iHtml.length]="";
}
}
}
}
//Draw polyline connecting to the specified points.
function drawPolyline(pen,points)
{
//Check arguments for null values
if(!pen || !points)
return false;
var polylineDiv=canvasDiv.appendChild(document.createElement("div"));
for(var i=1;i";
}
else
{
iHtml[iHtml.length]="";
}
}
}
phPoints=newPoints;
for(i=1;iphPoints[i-1].y)
{
yMin=phPoints[i-1].y;
}
if(yMaxphPoints[i].y && phPoints[i].y>phPoints[i+1].y))
{
xDataArrays[i-1][phPoints[i].y]=null;
}
}
else
{
if((phPoints[i-1].yphPoints[i].y && phPoints[i].y>phPoints[0].y))
{
xDataArrays[i-1][phPoints[i].y]=null;
}
}
}
if(yMin>phPoints[i-1].y)
{
yMin=phPoints[i-1].y;
}
if(yMaxphPoints[0].y && phPoints[0].y>phPoints[1].y))
{
xDataArrays[i-1][phPoints[0].y]=null;
}
var y;
var divStyle="";
var j;
pointsCount=phPoints.length;
var xDataArray;
var xMin,xMax;
var curX,curY,curWidth;
for(y=yMin;y<=yMax;y++)
{
j=0;
var allXDataArray=new Array();
for(i=0;iphPoints[l].y && y>phPoints[n].y && xDataArray[y]))
{
allXDataArray[j]= xDataArray[y];
j++;
}
if(xDataArray[y])
{
allXDataArray[j]= xDataArray[y];
j++;
}
}
//Sorting based on xMin, uses sortXDataArray function
allXDataArray.sort(sortXDataArray);
curY=y;
for(i=0;iallXDataArray[i].xMax)
curWidth=allXDataArray[i+1].xMax-allXDataArray[i].xMin+1;
else
curWidth=allXDataArray[i].xMax-allXDataArray[i].xMin+1;
}
else
{
curX=allXDataArray[allXDataArray.length-1].xMin;
curWidth=allXDataArray[allXDataArray.length-1].xMax-allXDataArray[allXDataArray.length-1].xMin+1;
}
iHtml[iHtml.length]="";
}
}
polygonDiv.innerHTML=iHtml.join("");
return polygonDiv;
//Internal function: sorting based on xMin
function sortXDataArray(a,b)
{
return a.xMin - b.xMin;
}
}
//Draw cubic bezier curve with specified 4 points
function drawBezier(pen,points)
{
//Check arguments for null values
if(!pen || !points)
return false;
var phPoints=new Array();
var i;
for(i=0;i4)
{
phPoints=new Array(phPoints[0],phPoints[1],phPoints[2],phPoints[3]);
}
else if(phPoints.length<4)
{
return false;
}
var bezierDiv=canvasDiv.appendChild(document.createElement("div"));
var iHtml=new Array();
var xMin=phPoints[0].x;
var xMax=phPoints[0].x;
for(i=1;iphPoints[i-1].x)
{
xMin=phPoints[i-1].x;
}
if(xMax1 || y-yl>1 || xl-x>1 || yl-y>1)
{
t-=f;
f=f/k;
}
else
{
curvePoints[curvePoints.length]=new jsPoint(x,y);
xl=x;
yl=y;
}
}
else
{
t-=f;
f=f*k;
}
t+=f;
}
var isEliminated=new Array();
for(var i=0;i";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
y1=yp;
y2=yp;
xStart=false;
}
if(y!=yp && !xStart )
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
x1=xp;
x2=xp;
yStart=false;
}
if(xStart && !yStart)
{
if(y<=y1)
y1=y;
if(y>y2)
y2=y;
}
else
{
y1=y;
y2=y;
}
if(yStart && !xStart)
{
if(x<=x1)
x1=x;
if(x>x2)
x2=x;
}
else
{
x1=x;
x2=x;
}
if(i==curvePoints.length-1) //last step in the loop
{
if(!xStart)
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
if(!yStart)
{
if(y2==y1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
}
}
}
bezierDiv.innerHTML=iHtml.join("");
return bezierDiv;
}
//Draw general (poly) bezier curve with specified points
function drawPolyBezier(pen,points)
{
//Check arguments for null values
if(!pen || !points)
return false;
if(points.length<2)
{
return false;
}
var phPoints=new Array();
for(var i=0;i1 || y-yl>1 || xl-x>1 || yl-y>1)
{
t-=f;
f=f/k;
}
else
{
curvePoints[curvePoints.length]=new jsPoint(x,y);
xl=x;
yl=y;
}
}
else
{
t-=f;
f=f*k;
}
t+=f;
}
var isEliminated=new Array();
for(var i=0;i";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
y1=yp;
y2=yp;
xStart=false;
}
if(y!=yp && !xStart )
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
x1=xp;
x2=xp;
yStart=false;
}
if(xStart && !yStart)
{
if(y<=y1)
y1=y;
if(y>y2)
y2=y;
}
else
{
y1=y;
y2=y;
}
if(yStart && !xStart)
{
if(x<=x1)
x1=x;
if(x>x2)
x2=x;
}
else
{
x1=x;
x2=x;
}
if(i==curvePoints.length-1) //last step in the loop
{
if(!xStart)
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
if(!yStart)
{
if(y2==y1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
}
}
}
bezierDiv.innerHTML=iHtml.join("");
return bezierDiv;
//Internal factorial function
function fact(n)
{
var res = 1;
for(var i=1;i<= n;i++)
{
res =res * i;
}
return res;
}
}
//Draw closed curve passing through the give points with specified tension
//This method just calls drawCurve method with parameter isClosed=true
function drawClosedCurve(pen,points,tension)
{
return this.drawCurve(pen,points,tension,true);
}
//Draw curve passing through the give points with specified tension
function drawCurve(pen,points,tension,isClosed)
{
if(!pen || !points)
return false;
if(!tension)
{
tension=0;
}
if(!isClosed)
{
isClosed=false;
}
var phPoints=new Array();
for(var i=0;i1 || y-yl>1 || xl-x>1 || yl-y>1)
{
t-=f;
f=f/k;
}
else
{
curvePoints[curvePoints.length]=new jsPoint(x,y);
xl=x;
yl=y;
if(t+f>1)
t=1-f;
}
}
else
{
f=f*k;
}
t+=f;
}
}
//Private function used by drawCurve method to draw actual curve
//using and processing points data in curvePoints array
function drawAllCurvePoints(pen,curvePoints,iHtml)
{
var xp=curvePoints[0].x;
var yp=curvePoints[0].y;
var yStart=false;
var xStart=false;
var x1,x2,y1,y2;
x1=xp;
x2=xp;
y1=yp;
y2=yp;
var penWidth=parseInt(pen.width);
var hexColor=pen.color.getHex();
var divWidth=penWidth;
var divHeight=penWidth;
var isEliminated=new Array();
for(var i=0;i";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
y1=yp;
y2=yp;
xStart=false;
}
if(y!=yp && !xStart )
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
xp=x;
yp=y;
x1=xp;
x2=xp;
yStart=false;
}
if(xStart && !yStart)
{
if(y<=y1)
y1=y;
if(y>y2)
y2=y;
}
else
{
y1=y;
y2=y;
}
if(yStart && !xStart)
{
if(x<=x1)
x1=x;
if(x>x2)
x2=x;
}
else
{
x1=x;
x2=x;
}
if(i==curvePoints.length-1) //last step in the loop
{
if(!xStart)
{
if(x2==x1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
if(!yStart)
{
if(y2==y1)
{
iHtml[iHtml.length]="";
}
else
{
iHtml[iHtml.length]="";
}
}
}
}
}
}
//Draw color filled closed curve passing through the specified points
//with specified tension
function fillClosedCurve(color,points,tension)
{
if(!color || !points)
return false;
if(!tension)
{
tension=0;
}
var phPoints=new Array();
for(var i=0;iallXDataArray[i].xMax)
curWidth=allXDataArray[i+1].xMax-allXDataArray[i].xMin+1;
else
curWidth=allXDataArray[i].xMax-allXDataArray[i].xMin+1;
}
else
{
curX=allXDataArray[allXDataArray.length-1].xMin;
curWidth=allXDataArray[allXDataArray.length-1].xMax-allXDataArray[allXDataArray.length-1].xMin+1;
}
iHtml[iHtml.length]="";
}
}
curveDiv.innerHTML=iHtml.join("");
return curveDiv;
//Internal sort function for allXDataArray array
function sortXDataArray(a,b)
{
return a.xMin - b.xMin;
}
}
//Private function used by fillClosedCurve method to get curve points
//(in curvePoints array) for a single curve segment (connecting 2 points)
function getCurveSegPixels(segPoints,tension,curvePoints)
{
var x=0;
var y=0;
var xl=segPoints[1].x-1;
var yl=segPoints[1].y-1;
var t=0;
var f=1;
var k=1.1;
var penWidth=1;
var divWidth=1;
var divHeight=1;
var m1x=(1-tension)*(segPoints[2].x-segPoints[0].x)/2;
var m2x=(1-tension)*(segPoints[3].x-segPoints[1].x)/2;
var m1y=(1-tension)*(segPoints[2].y-segPoints[0].y)/2;
var m2y=(1-tension)*(segPoints[3].y-segPoints[1].y)/2;
while(t<=1)
{
x=0;
y=0;
x= (2*t*t*t-3*t*t+1)*segPoints[1].x + (t*t*t-2*t*t+t)*m1x + (-2*t*t*t+3*t*t)*segPoints[2].x + (t*t*t-t*t)*m2x;
y= (2*t*t*t-3*t*t+1)*segPoints[1].y + (t*t*t-2*t*t+t)*m1y + (-2*t*t*t+3*t*t)*segPoints[2].y + (t*t*t-t*t)*m2y;
x=Math.round(x);
y=Math.round(y);
if(x!=xl || y!=yl)
{
if(x-xl>1 || y-yl>1 || xl-x>1 || yl-y>1)
{
t-=f;
f=f/k;
}
else
{
curvePoints[curvePoints.length]=new jsPoint(x,y);
xl=x;
yl=y;
if(t+f>1)
t=1-f;
}
}
else
{
f=f*k;
}
t+=f;
}
}
//Private function that processes the points data from curvePoints
//xDataArray is also populated by the fuction
function getAllCurvePointsArray(xDataArray,yArray,curvePoints)
{
function xData()
{
this.xMax=0;
this.xMin=0;
this.i=0;
}
var isEliminated=new Array();
var yMin;
var yMax;
var lastY;
var firstY;
var isFirst=true;
var xDataArrayLast;
var iLast=-1;
var yTop1,yTop2;
for(var i=0;iyMax)
yMax=y;
if(!xDataArray[y])
{
xDataArray[y]=new Array();
xDataArray[y][0]=new xData();
xDataArray[y][0].xMin=x;
xDataArray[y][0].xMax=x;
xDataArray[y][0].i=i;
}
else
{
xDataArrayLast=xDataArray[y][xDataArray[y].length-1];
if(i-xDataArrayLast.i==1)
{
if(xDataArrayLast.xMin>x)
xDataArrayLast.xMin=x;
if(xDataArrayLast.xMax y && yTop2 < yTop1) || (yTop1 < y && yTop2 > yTop1))
{
xDataArray[yTop1][xDataArray[yTop1].length]=xDataArray[yTop1][xDataArray[yTop1].length-1];
}
}
if(!yArray[0])
{
yArray[0]=y;
}
else if(yArray[yArray.length-1]!=y)
{
yArray[yArray.length]=y;
}
lastY=y;
}
}
yTop1=yArray[0];
yTop2=yTop1;
var i=1;
while(yTop1==yTop2)
{
yTop2=yArray[yArray.length-i];
i++;
}
if(yTop1 && yTop2)
{
if((yTop1 > yArray[1] && yTop2 < yTop1) || (yTop1 < yArray[1] && yTop2 > yTop1))
{
xDataArray[yTop1][xDataArray[yTop1].length]=xDataArray[yTop1][xDataArray[yTop1].length-1];
}
}
if(firstY==lastY)
{
var firstXDataA=xDataArray[firstY][0];
var lastXDataA=xDataArray[lastY][xDataArray[lastY].length-1];
if(lastXDataA.xMax>firstXDataA.xMax)
xDataArray[firstY][0].xMax=lastXDataA.xMax;
if(lastXDataA.xMin1)
xDataArray[lastY].pop();
else
xDataArray.pop();
}
return new Array(yMin,yMax);
}
//Draw text string at specified point with specified color,font,width & alignment
function drawText(text,point,font,color,width,align)
{
//Check arguments for null values
if(!text || !point)
return false;
phPoint=logicalToPhysicalPoint(point);
if(width!=null)
width=Math.round(width*scale) + "px";
var textDiv=canvasDiv.appendChild(document.createElement("div"));
textDiv.style.position="absolute";
textDiv.style.left=phPoint.x + "px";
textDiv.style.top=phPoint.y + "px";
if(color)
textDiv.style.color=color.getHex();
//set font
if(font)
{
if(font.family)
textDiv.style.fontFamily=font.family;
if(font.weight)
textDiv.style.fontWeight=font.weight;
if(font.size)
textDiv.style.fontSize=font.size;
if(font.style)
textDiv.style.fontStyle=font.style;
if(font.variant)
textDiv.style.fontVariant=font.variant;
}
if(width)
textDiv.style.width=width;
if(align)
textDiv.style.textAlign=align;
textDiv.innerHTML=text;
return textDiv;
}
//Draw image at specified point with specified width & height
function drawImage(url,point,width,height)
{
if(!url || !point)
return false;
phPoint=logicalToPhysicalPoint(point);
if(width!=null)
width=Math.round(width*scale) + "px";
if(height!=null)
height=Math.round(height*scale) + "px";
var imgDiv=canvasDiv.appendChild(document.createElement("div"));
imgDiv.style.position="absolute";
imgDiv.style.left=phPoint.x + "px";
imgDiv.style.top=phPoint.y + "px";
//create and set img tag/element
var img=imgDiv.appendChild(document.createElement("img"));
img.src=url;
if(width!=null)
{
img.style.width=width;
imgDiv.style.width=width;
}
if(height!=null)
{
img.style.height=height;
imgDiv.style.height=height;
}
return imgDiv;
}
//Clear the canvas div element
function clear()
{
canvasDiv.innerHTML="";
}
}