Wer solche Diagramme mit dem Canvas Element und etwas Javascript zeichnen möchte, kann gerne diese von mir geschriebene Klasse verwenden:
function BarChartFactory(canvasElement,unitName,plotEvery){
	this.canvas=canvasElement;
	
	this.maxValue=0;
	this.categoryTitleWidth=50;
	this.valueTitleWidth=50;
	this.bottomScalaHeight=10;
	this.padding=5;
	this.linesSeperateValues=true;
	
	this.barStart=0;
	this.barEnd=0;
	this.barTranslationFactor=1;
	this.barHeight=20;
	this.barPadding=4; //top + bottom
	
	this.xPlotEvery=plotEvery;
	this.unitName=unitName;
	
	this.categoryValueSize=2; //if more.. ignore.. if less.. paint empty
	
	this.categories=[];
	
	this.ctx=null;
	this.width=200;
	this.height=0;
	
	this.addValue=function(categoryTitle,valueTitle,value,valueColor){
		var cat=null;
		for(var ii=0;ii<this.categories.length && cat==null;ii++){
			if(this.categories[ii].title==categoryTitle){
				cat=this.categories[ii];
				console.log("found existing category: "+categoryTitle);
			}
		}
		
		if(cat==null){
			cat={title:"",values:[]};
			cat.title=categoryTitle;
			this.categories[this.categories.length]=cat;
		}
		
		cat.values[cat.values.length]={value:value,title:valueTitle,color:valueColor};
	};
	
	this.init=function(ctx,width){
		this.barStart=this.categoryTitleWidth+this.valueTitleWidth;
		this.barEnd=width;
		
		for(var ii=0;ii<this.categories.length;ii++){
			var cat=this.categories[ii];
			for(var j=0;j<cat.values.length;j++){
				if(cat.values[j].value>this.maxValue){
					this.maxValue=cat.values[j].value;
				}
			}
			if(cat.values.length>this.categoryValueSize){
				this.categoryValueSize=cat.values.length;
			}
		}
		this.maxValue=this.maxValue+(this.maxValue/10);
		
		this.barTranslationFactor=(this.barEnd-this.barStart)/this.maxValue;
		
		this.ctx=ctx;
		this.ctx.canvas.width=width+(this.padding*2);
		this.ctx.canvas.height=(this.categories.length*this.categoryValueSize*this.barHeight)+this.bottomScalaHeight+(this.padding*2);
		
		this.width=this.ctx.canvas.width;
		this.height=this.ctx.canvas.height;
		
		//TODO clearRect
	};	
	
	this.paintStructure=function(){
		//paint main structure
		this.ctx.strokeStyle="#AAAAAA";
		this.ctx.beginPath();
		this.ctx.moveTo(this.categoryTitleWidth+this.valueTitleWidth,0+this.padding);
		this.ctx.lineTo(this.categoryTitleWidth+this.valueTitleWidth,this.height-this.barHeight+this.barPadding);
		this.ctx.stroke();
		
		if(this.xPlotEvery>0){
			console.log("paint structure ("+this.maxValue+")");
			var xStart=this.categoryTitleWidth+this.valueTitleWidth;
			for(var i=this.xPlotEvery;i<this.maxValue;i=i+this.xPlotEvery){
				this.ctx.beginPath();
				this.ctx.moveTo(xStart+(i*this.barTranslationFactor),0+this.padding);
				this.ctx.lineTo(xStart+(i*this.barTranslationFactor),this.height-this.barHeight+this.barPadding);
				this.ctx.stroke();
				
				this.ctx.fillStyle="#000000";
				this.ctx.fillText(""+Math.round(i)+this.unitName,xStart+(i*this.barTranslationFactor), this.height-this.barHeight+this.barPadding+12);
			}
		}
	};
	
	this.paint=function(width){
		this.init(this.canvas.getContext("2d"),width);					
		
		this.ctx.lineWidth=1;
		this.ctx.strokeStyle="#000000";					
		this.paintStructure();
		this.ctx.strokeStyle="#000000";
		
		for(var iC=0;iC<this.categories.length;iC++){
			var cat=this.categories[iC];
			
			this.ctx.fillStyle="#000000";
			this.ctx.fillText(cat.title,this.padding,(((iC)*this.categoryValueSize)+Math.round(this.categoryValueSize/2))*this.barHeight+this.padding);
			
			for(var i=0;i<this.categoryValueSize;i++){
				var value={value:0,title:"",color:"#FF0000"};
				if(cat.values){
					value=cat.values;								
				}
				
				this.ctx.fillStyle="#000000";
				this.ctx.fillText(value.title,this.categoryTitleWidth,((iC*this.categoryValueSize)+i+1)*this.barHeight);
				
				//line under value title							
				this.ctx.beginPath();
				if(i==this.categoryValueSize-1){
					this.ctx.moveTo(this.padding,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
				}
				else{
					this.ctx.moveTo(this.categoryTitleWidth,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
				}
				
				if(this.linesSeperateValues){
					this.ctx.lineTo(this.width-this.padding,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
				}
				else{
					this.ctx.lineTo(this.categoryTitleWidth+this.valueTitleWidth,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
				}
				
				this.ctx.stroke();							
				
				//paint real value					
				this.ctx.beginPath();
				this.ctx.rect(this.categoryTitleWidth+this.valueTitleWidth,((iC*this.categoryValueSize)+i)*this.barHeight+this.padding+this.barPadding,value.value*this.barTranslationFactor,this.barHeight-(this.barPadding*2));
				this.ctx.stroke();
				this.ctx.fillStyle=value.color;
				this.ctx.fill();
			}
		}
	};
}
Das Beispiel zum Bild sieht dann so aus:
<html>
	<head>
		<title>2dbar test</title>
		<script type="text/javascript" src="./BarChartFactory.js"></script>
	</head>
	<body>
		<canvas id="can" style="border:1px solid #000000;border-radius:4px;">		
		</canvas>
		<script type="text/javascript">			
			var bcf=new BarChartFactory(document.getElementById("can"),"fps",10);
			bcf.addValue("386SX","16 Mhz",20,"#70B4B6");
			bcf.addValue("386SX","25 Mhz",25,"#0000FF");
			bcf.addValue("386DX","25 Mhz",40,"#70B4B6");
			bcf.addValue("386DX","33 Mhz",60,"#70B4B6");
			bcf.paint(400);
		</script>
	</body>
</html>