//CHECKJS  E:\js\gca\site\chart.js 8/18/2008 6:51:19 PM
//9:41 AM 8/18/2008
//chart.js  expanding pie charts for the Green Chemistry Assistant
//see chart.htm for application of these functions
//Bob Hanson, St. Olaf College
usemasks=1
Chart={}	
chartinfotimeout=0
chartisrunning=0
ChartImageCache={}
ChartKey={}
ChartKey["qreact"]=["Remaining Reactants","a0ffff"]
ChartKey["qexcess"]=["Excess Reactants","004080"]
ChartKey["qprod_"]=["Desired Product","00ff00"]
ChartKey["qtheor_"]=["Theoretical Yield<A style=\"text-decoration:none\" HREF=\"javascript:alert('Unlike the other areas, the area representing theoretical yield extends to the center of the diagram.')\">*</a>","ffffff"]
ChartKey["qcoprod"]=["Coproduct","8a5c8a"]
ChartKey["qsolv"]=["Solvent","c0c0c0"]
ChartKey["qcat"]=["Catalyst","ffffa0"]
ChartKey["qother"]=["Other Reagents","c0e0c0"]
ChartKey["qbyproduct"]=["Byproduct","000000"]
ChartKey["qloss"]=["Losses (shaded)","604040"]
ChartCalc={}
ChartCalc["cae"]=["Atom Economy","C.xPAE",1,"%"]
ChartCalc["cre"]=["Relative Excess","C.xPExcess",1,"%"]
ChartCalc["ccr"]=["Catalytic Ratio","C.qprod/C.qcat",.1,"1:"]
ChartCalc["cexpae"]=["Experimental Atom Economy","100*C.qtheor/C.qinput",1,"%"]
ChartCalc["crme"]=["Reaction Mass Efficiency","100*C.qprod/C.qinput",1,"%"]
ChartCalc["cpme"]=["Process Mass Efficiency","100*C.qprod/C.qinputall",1,"%"]
ChartCalc["cefactor"]=["E-Factor","(C.qloss)/C.qprod",.1,":1"]
ChartCalc["-"]=["","",0,""]
SliceOffsets={}
SliceOffsets["r"]=[-2,-1 , 0,-1, 3, 2] //100-x,100-x,thisx-2,thisy-3
SliceOffsets["p"]=[0,-.5,  -1,-1,  0, 3]
SliceOffsets["u"]=[2,  0,  0,-1, -3, 2]
SliceOffsets["c"]=[-2, -1,  2, 0, 3, -2]
SliceOffsets["s"]=[0,-.5,  2, 0 , 0 ,-3]
SliceOffsets["o"]=[2,  0,  2, 0 ,-3 ,-2]
ChartScroll={}
ChartScroll[""]=[]
ChartScroll["Scale"]=["Chart Scale|%",0,300]
ChartScroll["Rextent"]=["Reaction Extent|",0,1]
ChartScroll["PAE"]=["Atom Economy|%",0,100]
ChartScroll["PExcess"]=["Relative Excess|%",0,200]
ChartScroll["RRec"]=["<font color=#008000>Reactant Recovery|%",0,100]
ChartScroll["PYield"]=["<font color=#008000>Percent Yield</font>|%",0,100]
ChartScroll["Catalysts"]=["Catalysts|%",0,200]
ChartScroll["CRec"]=["<font color=#008000>Catalyst Recovery</font>|%",0,100]
ChartScroll["Solvents"]=["<font color=#800000>Solvents</font>|%",0,2000]
ChartScroll["SRec"]=["<font color=#008000>Solvent Recovery</font>|%",0,100]
ChartScroll["Other"]=["<font color=#800000>Other</font>|%",0,2000]
ChartScroll["ORec"]=["<font color=#008000>Other Recovery</font>|%",0,100]
ChartScroll["Byproducts"]=["<font color=#800000>Byproducts</font>|%",0,100]
function addChartScrollers(C){
	C.Scrollers=[]
	var what=""
	for(i=1;i<arguments.length;i++){
		what=arguments[i]
		if(what){
			C.Scrollers[i-1]=[what,0,0,0,C["x"+what]]
			for(var j=0;j<3;j++)C.Scrollers[i-1][j+1]=ChartScroll[what][j]
		}else{
			C.Scrollers[i-1]=[]
		}
	}
}
function addSnapCoord(sout,P){
	stest+="\n"+P
	var A=[0,1,4,5]
	var i1=(P.length==2?2:4)
	for(var i=0;i<i1;i++)sout=sout.replace(/\:0/,": "+P[A[i]])
	return sout
}
function chartRound(v,frac){
	return Math.floor((v+frac/2)/frac)*frac
}
function checkInlineData(C){
	var sdata=document.location.search
	if(sdata.length<2)sdata=""
	sdata=sdata.replace(/(\?|\&)do/,";do").replace(/(\?|\&)/g,";Chart.x")
	if(sdata==""){
	}else if(sdata.indexOf(";do")>=0){
		newChart("Chart","")
		eval(sdata)
	}else{
		newChart("Chart","")
		setChartExample(Chart,99,sdata)
	}
	divSetDisplay(C.name+"div","block")
}
function createChartMap(){
	var s='<map name=chartmap>'
	+'<area shape=poly coords="0,0, 40,0, 100,100, 0,100" title="reactant">'
	+'<area shape=poly coords="40,0, 160,0, 100,100" title="product">'
	+'<area shape=poly coords="160,0, 200,0, 200,100, 100,100" title="coproduct">'
	+'<area shape=poly coords="0,200, 40,200, 100,100, 0,100" title="catalyst">'
	+'<area shape=poly coords="40,200, 160,200, 100,100" title="solvent">'
	+'<area shape=poly coords="160,200, 200,200, 200,100, 100,100" title="other reagents"></map>'
	document.write(s)
}createChartMap()
function createChartSnapshot(C){
	var sout="<style>.cpic{position:absolute;left:1;top:1;}</style>"
	sout+=getChartWindowLink(C)
	if(issafari)return sout+"<p>The capability to view charts in a new window with Safari is not available at this time." //sorry :(
	var d=divFind(C.name+"Box",1)
	if(!d)return "div "+C.name+"Box not found: "+navigator.appName+" "+navigator.appVersion
	sout+=d.innerHTML
	sout=sout.replace(/(overflow|OVERFLOW)\:(\s)*auto/g,"$1: hidden")//.replace(/top\:/g,"position:absolute;top:")
	return sout
}
function createScrollers(C,w,x,y,dy){
	var sout=""
	var caption=""
	for(var i=0;i<C.Scrollers.length;i++){
		var S=C.Scrollers[i]
		C["scr"+S[0]]=1
		if(S.length==5){
			caption=S[1].replace(/\|/,"&nbsp;&nbsp;&nbsp;_v")
			sout+=newScroller(C.name+"_"+S[0],caption,"doChartScroll("+C.name+",'_n',_v)",w,x,y,S[2],S[3],S[4],8)
			y+=dy
		}else{
			y+=dy/2
		}
	}
	return sout
}
function doChartRun(C,what,ifrom,ito,iby,ims,isiter){
	ifrom=chartRound(ifrom+iby,.001)
	if(!isiter)isiter=0
	if(isiter && !chartisrunning)return
	if(chartisrunning && !isiter || ifrom>ito){
		chartisrunning=0
		return
	}
	chartisrunning=1
	isiter=1
	//document.title=ifrom+" "+ito+" "+iby
	updateChart(C,what,ifrom)
	updateAllChartScrollers(C)
	setTimeout("doChartRun("+C.name+",'"+what+"',"+ifrom+","+ito+","+iby+","+ims+",1)",ims)
}
function doChartScroll(C,what,value){
	what=what.split("_")[1]
	updateChart(C,what,value)
}
function doChartSnapshot(C){
	var opt="menubar,scrollbars,width=600,height=600,left=100,top=30"
	docWrite("<html>"+createChartSnapshot(C)+"</html>")
}
function doRunChartReaction(C){
	if(!C)C=Chart
	if(C.xRextent==1)C.xRextent=0
	doChartRun(C,"Rextent",C.xRextent,1,.05,10)
}
function doShowChart(C,icheckinline){
	if(!C||!C.name){
		C=newChart("Chart")
	}
	if(!C.isinitialized){
		if(!ChartImageCache.isinitialized)getChartImages(C,0)
		divWrite(C.name+"div",getChartImages(C,1))
		getChartImages(C,2)
		divMove(C.name+"div",C.xOffset,C.yOffset)
		moveChartMap(C)
		if(C.scrollerdiv){
			divWrite(C.name+C.scrollerdiv,createScrollers(C,C.scrollerwidth,0,0,C.scrolldy))
			divMove(C.name+C.scrollerdiv,C.xOffset+C.xScrollers,C.yOffset+C.yScrollers)
			C["p_scroll"]=[C.xScrollers,C.yScrollers]
		}
		if(!getChartObject(C,"keyobject",C.keydiv))C.idokey=0
		if(C.idokey && C.keydiv){
			divWrite(C.name+C.keydiv,"")
			divMove(C.name+C.keydiv,C.xOffset+C.xKey,C.yOffset+C.yKey)
			C["p_key"]=[C.xKey,C.yKey]
		}
		if(!getChartObject(C,"calcobject",C.calcdiv))C.idocalc=0
		if(C.calcdiv){
			divWrite(C.name+C.calcdiv,"")
			divMove(C.name+C.calcdiv,C.xOffset+C.xCalc,C.yOffset+C.yCalc)
			C["p_calc"]=[C.xCalc,C.yCalc]
		}
		if(C.commentdiv){
			divWrite(C.name+C.commentdiv,"")
			divMove(C.name+C.commentdiv,C.xOffset+C.xComment,C.yOffset+C.yComment)
			C["p_comment"]=[C.xComment,C.yComment]
		}
	}
	C.isinitialized=true
	updateChart(C)
	divSetDisplay(C.name+"div",icheckinline?"none":"block")
	initScrollers()
	if(icheckinline)setTimeout("checkInlineData("+C.name+")",100)
	if(C.idokey||C.idocalc)showChartInfo(C)
	updateAllChartScrollers(C)
}
function fixFrac(v){
	return (v+"").split("0000")[0]
}
function getChartImages(C,imode){
	var name=C.name
	var sout=""
	var r=""
	var c=""
	var id=""
	var D=new Array(20,2,"2m",10,1,"m",0,"")
	var S=C.list.split("|")
	var ifirst=0
	C.List=[]
	for(var i=0;i<S.length;i++){
		r=S[i].split(",")[0]
		C[r+"Caption"]=S[i].split(",")[1]
		C.List[C.List.length]=r
		ifirst=(r=="r"||r=="p"?0:3) //excess R between R_rec and R_lost; Theor for p
		for(var j=ifirst;j<D.length;j++){
			id=name+r+D[j]
			if(imode==0){
				ChartImageCache[r+D[j]+"gif"]=C.imageroot+r+(D[j]&&!isNaN(D[j])?D[j]%10:D[j])+".gif"
			}else if(imode==1){
				sout+="\n<div id="+id+" class=cpic style=\"position:absolute;left:0;top:0;\"><img id="+id+"gif></div>"
			}else{
				divFind(id+"gif").src=ChartImageCache[r+D[j]+"gif"]
			}
		}
	}
	if(imode==0)ChartImageCache.isinitialized=1
	return sout
}
function getChartObject(C,obj,div){
	var d=C[obj]
	if(d==0||!div)return 0
	if(d)return d
	C[obj]=d=divFind(C.name+div,1)
	if(!d)C[obj]=0
	return d
}
function getChartWindowLink(C){
	var slist="Scale,PAE,Rextent,PExcess,Catalysts"
	var S=slist.split(",")
	var key=""
	var s=""
	for(var i=0;i<C.Scrollers.length;i++){
		key=C.Scrollers[i][0]
		if(key&&slist.indexOf(key)<0)slist+=","+key
	}
	for(var i=0;i<S.length;i++)s+="&"+S[i]+"="+C["x"+S[i]]
	return "<a target=_blank href=http://www.stolaf.edu/depts/chemistry/gca/chart.htm?"+s+">activate in new window</a>"
}
function insertChart(name,comment,x,y){
	if(!name)name="Chart"
	if(!comment)comment=""
	if(arguments.length<3)x=NaN
	var C=eval(name)
	if(C)C.comment=comment
	var sout="<div id="+name+"Box class=cpic style=\"position:absolute;"+(isNaN(x)?"":"left:"+x+";top:"+y+";")+"\">"
	+"<div id="+name+"div class=cpic style=\"position:absolute;left:1;top:1;\"></div>"
	+"<div id="+name+"scrollerdiv class=cpic style=\"position:absolute;left:0;top:0;\"></div>"
	+"<div id="+name+"keydiv class=cpic style=\"position:absolute;left:0;top:0;\"></div>"
	+"<div id="+name+"calcdiv class=cpic style=\"position:absolute;left:0;top:0;width:300px\"></div>"
	+"<div id="+name+"commentdiv class=cpic style=\"position:absolute;left:0;top:0;width:300px\"></div>"
	+"<div id="+name+"imgmap class=cmap style=\"position:absolute;left:0;top:0;\"><img border=0 src=transp.gif height=200 width=200 usemap=#chartmap></div>"
	+"</div>"
	document.write(sout)
}
function moveChartMap(C){
	divMove(C.name+"imgmap",C.xOffset-100+C.xCenter+C.xScale-100,C.yOffset-100+C.yCenter+C.xScale-100)
}
function newChart(name,comment){
	if(!name)name="Chart"
	if(!comment)comment=""
	var C=eval(name+"={}")
	C.name=name
	C.comment=comment
	setChartExample(C,-1)
	C.margin=5
	C.xOffset=50
	C.yOffset=50
	C.xCenter=200
	C.yCenter=300
	C.xScale=100

	C.scrollerdiv="scrollerdiv"
	C.scrollerwidth=200
	C.xScrollers=750
	C.yScrollers=0
	C.scrolldy=40

	C.idocomment=1
	C.commentdiv="commentdiv"
	C.xComment=0
	C.yComment=60

	C.idokey=1
	C.keydiv="keydiv"
	C.xKey=0
	C.yKey=100
	C.keytext=""

	C.idocalc=1
	C.calcdiv="calcdiv"
	C.xCalc=450
	C.yCalc=100
	C.calctext=""
	C.calcs="cae,-,cexpae,ccrx,crex,-,crme,-,cpme,-,cefactor"

	C.list="r,Reactants|u,Unwanted Coproducts|c,Catalyst|o,Other Reagents|p,Desired Product|s,Solvent"
	//	C.excess=0
	C.bindOCS=0

	addChartScrollers(C,"Rextent","PAE","","PExcess","","PYield","Catalysts","Solvents","Other","RRec","CRec","SRec","ORec","Byproducts","Scale")
	C.Captions=[
		["r","Reactants",0,-20],
		["p","Products",0,20],
		["p2","Theoretical Yield",0,20],
		["r1","Excess Reactants",0,0],
		["r2","Reactant Loss",0,0]
	]
	C.imageroot="img/hex"
	return C
}
function newSlicePic(C,a,x,S,xv,xmargin,mask){
	var d=0
	if(!xmargin)xmargin=0
	x=x*C.xScale/100
	var x0=(C.xCenter+S[0]+x*S[1])+(C.xScale-100)
	var y0=C.yCenter+S[2]+x*S[3]+(C.xScale-100)
	d=divFind(C.name+a+"gif")
	d.height=d.width=x
	divMove(C.name+a,x0,y0)
	if(mask){
		d=divFind(C.name+mask+"gif")
		d.height=d.width=(usemasks?x:0)
		divMove(C.name+mask,x0,y0)
	}
	var xx=(x?x+(C.margin?C.margin:5):0)+xmargin*C.xScale/100
	var x1=(C.xCenter+S[0]+xx*S[1]+S[4])+(C.xScale-100)
	var y1=(C.yCenter+S[2]+xx*S[3]+S[5])+(C.xScale-100)
	d=divFind(C.name+a+"0gif")
	d.height=d.width=xx
	divMove(C.name+a+"0",x1,y1)
	C["p_"+a]=[x1,y1,xx,xx,x0,y0,x,x,xv]
}
function setChartExample(C,i,sdata){

	if(i<=0){
		C.xRextent=0
		C.xPYield=100 //would be same as "xPRec"
		C.xPAE=100
		C.xPExcess=0
		C.xCatalysts=0
		C.xSolvents=0
		C.xByproducts=0
		C.xOther=0
		C.xRRec=100
		C.xURec=0
		C.xORec=50
		C.xCRec=50
		C.xSRec=50
	}

	if(sdata)eval(sdata)

	if(i>=0){
		updateChart(C,"example",i)
		updateAllChartScrollers(C)
	}
}
function setSlice(C,a,xv,x1v,x2v,x3v){
	if(!x3v)x3v=0
	if(!x2v)x2v=0
	if(!x1v)x1v=0
	if(xv<0)xv=0
	if(x1v<0)x1v=0
	if(x2v<0)x2v=0
	if(x3v<0)x3v=0
	var ihaveouter=(arguments.length==5)
	var S=SliceOffsets[a]
	var x=0
	var x1=0
	var x2=0
	var iforce=(1||C.forcenew||x3v)
	//xv volume 0 to 1 (could be >1)

	//inner radius: sqrt(xv)*100

	x=Math.pow(xv+x1v,.5)*100
	x=Math.pow(xv,.5)*100
	if(iforce||!C[a+"radius"]||C[a+"radius"]!=x+1){
		C[a+"radius"]=x+1
		newSlicePic(C,a,x,S,x)
	}

	//middle radius -- brown except for reactants?

	x1=Math.pow(xv+x1v,.5)*100
	x2=Math.pow(xv+x1v+x3v,.5)*100

	if(iforce||!C[a+"1radius"]||C[a+"1radius"]!=x1+1){
		C[a+"1radius"]=x1+1
		newSlicePic(C,a+"1",x1,S,x1-x,x2-x1,a+"m")
	}

	//outer radius: sqrt(xv+x1v+x2v)*100 + margin

	if(ihaveouter){
		x=Math.pow(xv+x1v+x3v+x2v,.5)*100
		if(iforce||!C[a+"2radius"]||C[a+"2radius"]!=x+1){
			C[a+"2radius"]=x+1
			newSlicePic(C,a+"2",x,S,x-x2,0,a+"2m")
		}
	}
}
function showChartCalc(C){


	if(!C.idocalc)return
	var d=getChartObject(C,"calcobject",C.calcdiv)
	if(!d){
		C.idocalc=0
		return
	}
	var sout="<table width=220>"
	var v=0
	var i=0
	var s=C.calcs
	var spre=""
	var spost=""
	if(!C.qcat)s=s.replace(/ccr/,"")
	var S=s.split(",")

	for(var j=0;j<S.length;j++){
		i=S[j]
		var A=ChartCalc[i]
		if(A){
			spre=(A[3]=="1:"?A[3]:"")
			spost=(A[3]=="1:"?"":A[3])
			v=(A[1]?eval(A[1]):"")
			v=(v+""==""?"&nbsp;":isNaN(v)?"?":fixFrac(chartRound(v,A[2])))
			sout+="<tr><td class=chartcalctext 	>"+A[0]+"</td><td class=chartcalctext width=20 align=right>"+spre+v+spost+"</td></tr>"
		}
	}
	if(sout==C.calctext)return
	C.calctext=sout
	d.innerHTML=sout
	d.style.display="block"
	d.style.left=C.xOffset+C.xCalc
	d.style.top=C.yOffset+C.yCalc

	//document.title=C.qinput+" "+C.qprod+" "+C.qloss+" "+C.qinputall
}
function showChartInfo(C){
	chartinfotimeout=0
	if(C.idokey)showChartKey(C)
	if(C.idocalc)showChartCalc(C)
}
function showChartKey(C){
	if(!C.idokey)return
	var d=getChartObject(C,"keyobject",C.keydiv)
	if(!d){
		C.idokey=0
		return
	}
	var sout="<table width=350 style=\"width:350px\">"
	var sline="\n<td style=\"width:15px\"><table cellpadding=1 cellspacing=0><tr><td bgcolor=#000000>"
	+"<table cellpadding=0 cellspacing=0><tr><td bgcolor=#cc>"
	+"<img src="+C.imageroot+"transp.gif height=10 width=10>"
	+"</td></tr></table>"
	+"</td></tr></table>"
	+"</td><td width=160 style=\"width:160px;font-size:12px\">xx</td>"
	var n=0
	for(var i in ChartKey){
		if(C[i]>.01){
			if(n%2==0)sout+="<tr>"
			sout+=sline.replace(/cc/,ChartKey[i][1]).replace(/xx/,ChartKey[i][0])
			if((n++)%2)sout+="</tr>"
		}
	}
	if((n++)%2)sout+="</tr>"
	sout+="</table>"
	if(sout==C.keytext)return
	C.keytext=sout
	d.innerHTML=sout
	d.style.display="block"
	d.style.left=C.xOffset+C.xKey
	d.style.top=C.yOffset+C.yKey
}
function updateAllChartScrollers(C){
	for(var i=0;i<C.Scrollers.length;i++)if(C.Scrollers[i].length){
		resetScroller(C.name+"_"+C.Scrollers[i][0],C["x"+C.Scrollers[i][0]])
	}
}
function updateChart(C,what,value) {

	var x=0
	var x2=0
	var d=0
	var xs=0
	var xloss=0

	if(!C.byprodscenario)C.byprodscenario=0

	//0: all from reactants
	//1: all from products

	if(!what){
		what=""
	}else{
		C["x"+what]=value
	}

	C.thisscroller=what
	C.forcenew=(C.thisscroller=="Scale"||what=="new")
	if(what=="new"||what=="Scale")moveChartMap(C)
	var ishowloss=(C.xRextent>0)
	C.qloss=0
	C.qinput=0
	///////////product

	if(C.xRextent>1)C.xRextent=1

	if(what=="Rextent"){
		C.xPYield=C.xRextent*100
		updateChartScroller(C,"PYield")
	}

	x=C.xPAE/100*C.xPYield/100

	if(C.byprodscenario==1){
		x2=C.xRextent*C.xByproducts/100
		if(x<x2){
			C.xByproducts=(x*100/C.xRextent)
			updateChartScroller(C,"Byproducts")
			x2=x
		}
		x=x-x2
	}
	xloss=chartRound(C.xRextent*C.xPAE/100-x,.01)


	if(xloss<0){
		C.xPYield=(x+xloss)*100/(C.xPAE/100)
		updateChartScroller(C,"PYield")
		x+=xloss
		xloss=0
	}
	C.qprod=x
	C.qprod_=x+xloss
	C.qloss+=xloss
	C.qtheor=C.xPAE/100
	C.qtheor_=C.qtheor-x-xloss
	C.qinput+=x+xloss
	setSlice(C,"p",x,xloss,C.qtheor_)

	///////////undesired coproduct

	x=C.xRextent*(1-C.xPAE/100)
	x2=C.xRextent*C.xByproducts/100
	xloss=x*(1-C.xURec/100)
	C.qcoprod=x+xloss
	C.qbyproduct=x2
	C.qloss+=xloss+x2
	C.qinput+=x+x2
	setSlice(C,"u",x-xloss,xloss,0,x2)


	//////////reactant

	xs=C.xPExcess/100
	x=(1-C.xRextent)
	if(C.byprodscenario==0){
		x2=(1-C.xRextent)*C.xByproducts/100
		x=x+x2 //for now
	}


	C.qreact=x
	C.qexcess=xs

	xloss=(x+xs)*(ishowloss?(1-C.xRRec/100):0)
	if(xloss>xs){
		x+=xs-xloss
		xs=0
	}else{
		xs-=xloss
	}
	C.qloss+=xloss
	C.qinput+=x+xs+xloss
	setSlice(C,"r",x,xs,xloss)


	//////////////catalyst, solvent, other (for now):

	C.qinputall=C.qinput
	if(C.bindOCS){
		C.xCRec=C.xORec=C.xSRec
	}
	x=C.xCatalysts/100
	xloss=(ishowloss?x*(1-C.xCRec/100):0)
	C.qcat=x
	C.qloss+=xloss
	C.qinputall+=x
	setSlice(C,"c",x-xloss,xloss)

	x=C.xSolvents/100
	xloss=(ishowloss?x*(1-C.xSRec/100):0)
	C.qsolv=x
	C.qloss+=xloss
	C.qinputall+=x
	setSlice(C,"s",x-xloss,xloss)

	x=C.xOther/100
	xloss=(ishowloss?x*(1-C.xORec/100):0)
	C.qother=x
	C.qloss+=xloss
	C.qinputall+=x
	setSlice(C,"o",x-xloss,xloss)

	if(C.idokey||C.idocalc){
		if(chartinfotimeout)return
		chartinfotimeout=setTimeout("showChartInfo("+C.name+")",500)
	}

}
function updateChartScroller(C,what){
	if(!C["scr"+what])return
	resetScroller(C.name+"_"+what,C["x"+what])
}
