

function vis_stackedbarchart_Create(ob)
{	
	var margin = {top: 20, right: 20, bottom: 70, left: 30};
	
	/*if (ob.data.length == 1)
	{
		margin.bottom = 20;
	}*/
	
	var svg = d3.select("#plotarea_" + (ob.number-1))
	  .append("svg")		
		.attr("viewBox", "0 0 " + ob.width + " " + ob.height)
		.attr("preserveAspectRatio","xMidYMid meet")
		.attr("width","100%")
		.attr("height","100%")
	  .append("g")
		.attr("transform",
			  "translate(" + margin.left + "," + margin.top + ")");
			  
	var width = ob.width - margin.left - margin.right;
    var height = ob.height - margin.top - margin.bottom;
	
	var data = ob.data;
	
	var bgr = svg.append('rect')
	     .attr("width",width)
		 .attr("height",height)
		 .attr("fill","black")
		 .attr("stroke","none")
		 .attr("data-panel", ob.number-1)
		 .attr("data-id", -1)	
		 .attr("data-assetid","-1")		
		.attr("data-range", "live")		 
		 .on("click",function(e) { NavMenu(e); })
		 .on("contextmenu",function(e) { e.preventDefault(); e.stopPropagation(); ContextMenu(e);});	
		 
	if (ob.data.length == 1)
	{
		bgr.attr("data-id","0")
		   .attr("data-assetid",ob.data[0].asset)
		   .attr("data-propertyid", ob.data[0].property)
		   .attr("data-range", "live");
	}

	// gridlines in x axis function
	function make_x_gridlines() {		
		return d3.axisBottom(x)
			.ticks(5)
	}

	// gridlines in y axis function
	function make_y_gridlines() {		
		return d3.axisLeft(y)
			.ticks(5)
	}

	var x = d3.scaleBand()
	  .range([ 0, width ])
	  .domain(data.map(function(d) { return d.name; }))
	  .padding(0.2);
	  
	var bottomclass = "axis";
	//if (data.length == 1) bottomclass="hiddenaxis";
	
	svg.append("g")
	  .attr("transform", "translate(0," + height + ")")
	  .call(d3.axisBottom(x))
	  .selectAll("text")
		.attr("transform", "translate(-10,0)rotate(-45)")
		.style("text-anchor", "end")
		.attr("class",bottomclass);
			
	// Add Y axis
	var bounds = [0, 100];
	
	var y = d3.scaleLinear()	  
	  .domain(bounds)
	  .range([ height, 0]);
	svg.append("g")
	  .call(d3.axisLeft(y));
	
	ob.zeropoint = 0;
	  
	// add the X gridlines
	svg.append("g")			
	  .attr("class", "grid")
	  .attr("transform", "translate(0," + height + ")")
	  .call(make_x_gridlines()
		  .tickSize(-height)
		  .tickFormat("")
	  )

	// add the Y gridlines
	svg.append("g")			
	  .attr("class", "grid")
	  .call(make_y_gridlines()
		  .tickSize(-width)
		  .tickFormat("")
	  )	
	  
	var origin = 0;
	var realdata = null;
		
	ob.update = function(dt) {
		
		var margin = {top: 20, right: 20, bottom: 70, left: 30};
		
		var totaltime = 0;
		realdata = [];		
		for(var xl = 0;xl<ob.data.length;xl++)
		{
			var hs = ob.data[xl].hist;
			chunks = [];
			
			var ttime = 0;
			var totaloffset = 0;
			var ltime = null;
			var lvl = null;
			var tm = null;
			var values = [];
			var times = [];
			var chnkid = -1;
			var vl = null;
			for(var yl =0;yl<hs.length;yl++)
			{
				vl = parseFloat(hs[yl][1]);
				if (ltime == null)
				{
					lvl = vl;
					ltime = parseDateTime(hs[yl][0]);
					continue;
				}
				tm = parseDateTime(hs[yl][0]);
				exp = tm.getTime() - ltime.getTime();
				if (exp == 0) continue;
				ttime += exp;
				
				//console.log("Time Period: " + exp + " at value " + lvl);
				
				//Record It...
				chnkid = -1;
				for(var q=0;q<values.length;q++)
				{
					if (values[q] == vl)
					{
						chnkid = q;
						break;						
					}
				}
				if (chnkid == -1)
				{
					values.push(vl);
					chnkid = values.length-1;
					times.push([]);
				}
				times[chnkid].push(exp);
				
				lvl = vl;
				ltime = tm;				
			}
			
			for (var q=0;q<values.length;q++)
			{
				newob = Object();
				
				newob.name = ob.data[xl].name;				
			
				ttl = 0;
				for(var n=0;n<times[q].length;n++)
				{
					ttl += times[q][n];
				}				
				newob.value = (ttl / ttime)*100;								
				newob.vl = values[q];				
				newob.zeropoint = 0;	
				newob.asset	= ob.data[xl].asset;
				newob.property = ob.data[xl].property;
				newob.offset = totaloffset;
				newob.subchannel = realdata.length;
				newob.seconds = ttl / 1000;
				totaloffset += newob.value;
				realdata.push(newob);
			}			
			
		}		
		
		var width = ob.width - margin.left - margin.right;
		var height = ob.height - margin.top - margin.bottom;
		
		bars = svg.selectAll(".clickbars").data(realdata)
		bars.join(
		  enter => 
			enter.append("rect") 		  
				.attr("class","clickbars")
				.attr("x", function(d) { 
					return x(d.name) + (x.bandwidth() * 0.25); 
				})	
				.attr("y", y(bounds[0]+1))
				.attr("width", x.bandwidth()*0.5)
				.attr("data-panel", ob.number-1)
				.attr("data-id", function (d,i) { return i; })
				.attr("data-assetid", function (d) { return d.asset;})
				.attr("data-propertyid", function (d) { return d.property;})
				.attr("data-range", "live")
				.on("mouseover",function(e) { ShowTooltip(e); })
				.on("mousemove",function(e) { UpdateTooltip(e); })
				.on("mouseout",function(e) { HideTooltip(e); })	
				.on("contextmenu",function(e) { e.preventDefault(); e.stopPropagation(); ContextMenu(e);})
				.on("click",function(e) { NavMenu(e);})				
				.attr("fill","#111111")	
				.attr("opacity","0.2")				
				.transition(1000)
				.attr("y", function(d) {
					if (d.value < 0)
					{
						return y(ob.zeropoint); 
					}
					else
					{
						return y(d.value); 
					}
				})
				.attr("height",y(bounds[0]) - y(bounds[1])-2)			
		);
		
		bars = svg.selectAll(".bars").data(realdata)
		bars.join(
		  enter => 
			enter.append("rect") 		  
				.attr("class","bars")
				.attr("x", function(d) { return x(d.name); })	
				.attr("y", y(origin))
				.attr("width", x.bandwidth())
				.attr("data-panel", ob.number-1)
				.attr("data-id", function (d,i) { return i; })
				.attr("data-assetid", function (d) { return d.asset;})
				.attr("data-subchannel", function (d) { return d.subchannel;})
				.attr("data-propertyid", function (d) { return d.property;})
				.attr("data-seconds", function (d) { return d.seconds;})
				.attr("data-range", "live")
				.on("mouseover",function(e) { ShowTooltip(e); })
				.on("mousemove",function(e) { UpdateTooltip(e); })
				.on("mouseout",function(e) { HideTooltip(e); })	
				.on("contextmenu",function(e) { e.preventDefault(); e.stopPropagation(); ContextMenu(e);})
				.on("click",function(e) { NavMenu(e);})				
				.attr("fill", function(d) {		
					try
					{
						return ob.data[0].colourmap[d.vl];
					}
					catch(e)
					{
						return ColourSequence[d.vl % ColourSequence.length];
					}
				})
				.transition(1000)
				.attr("y", function(d) {
					if (d.value < 0)
					{
						return y(ob.zeropoint); 
					}
					else
					{
						return y(d.value + d.offset); 
					}
				})
				.attr("height", function(d) { 
					if (d.value == null) return 0;
					
					var ht = y(ob.zeropoint) - y(d.value); 
					if (ht < 0) ht = 0;
					return ht;
					
				}),
		  update =>
		    update
				.transition()				
				.attr("height", function(d) {					
					if (d.value == null) return 0;
					
					var ht = y(ob.zeropoint) - y(d.value); 
					if (ht < 0) ht = 0;
					return ht;
					
				})
				.attr("y", function(d) { 
					if (d.value < 0)
					{
						return y(ob.zeropoint); 
					}
					else
					{
						return y(d.value + d.offset); 
					}
				})
				.attr("fill", function(d) {					
					try
					{
						return ob.data[0].colourmap[d.vl];
					}
					catch(e)
					{
						return ColourSequence[d.vl % ColourSequence.length];"#445566";
					}
				})
		);
			
		
			

	}
	ob.update(ob.data);
	
	ob.updateTooltip = function(pntno,ctx) {
		var pnt = ctx.currentTarget.getAttribute("data-subchannel");
		var nm = "Unknown";
		try
		{
			nm = ob.data[0].map[realdata[pnt].vl];
		}
		catch(e)
		{
		}
		nm += " (" + realdata[pnt].vl + ")";
		var times = realdata[pnt].seconds.toFixed(2) + " sec";
		if (realdata[pnt].seconds > 90)
		{
			times = (realdata[pnt].seconds / 60).toFixed(2) + " mins";
			if (realdata[pnt].seconds > (1.5 * (60*60)))
			{
				times = (realdata[pnt].seconds / (60*60)).toFixed(2) + " hours";
			}
		}
		return realdata[pnt].name + ": " + nm + "<br/><strong>" + (Math.round(realdata[pnt].value*100)/100).toFixed(2) + "%</strong><br/>" + times;
	}
	
}