纯HTML5 Canvas实现的饼图

基本思路:

主要是利用HTML5 Canvas实现饼图绘制,绘制弧度的API主要是使用

context.arc与lineto两个API。

实现的功能有:

1. 支持标签Legend显示或者隐藏

2. 首次载入动画效果

3. 鼠标tooltip效果

4. 自定义饼图大小与是否添加文字

效果如下:

纯HTML5 Canvas实现的饼图_第1张图片

调用代码:






My Demo 1
	


Pie Chart Demo

饼图JS的代码:

var pieChart = {
    width: 600,
    height: 400,
    series: [],
    unit: "kg",
    chartCanvas: null,
    selectable : true,
    title: "Pie Chart",
    legend : {
    	enable : true
    },
    edge : {
    	width: 50,
    	height: 50
    },
    animation: {
    	enable: true,
    	animCanvas : null,
    	hh: 1, // trick is here!! for animation play
    	pctx: null
    },
    tooltips: {
    	enable: true,
    	tooltipCanvas : null,
    	ttContext: null,
    	index: -1
    },
    circle : {
    	cx: 0,
    	cy: 0,
    	radius: 0
    	
    },
    text : {
    	enable: false,
    	content:[]
    },
    
    initSettings: function (config) {
    	this.chartCanvas = config.canvas;
    	this.chartCanvas.width = config.width;
    	this.chartCanvas.height = config.height;
        this.width = config.width;
        this.height = config.height;
        this.series = config.series;
        this.title = config.title;
        this.unit = config.unit;
        if(config.tooltips != undefined) {
        	this.tooltips.enable = config.tooltips.enable;        	
        }
        if(config.animation != undefined) {
        	this.animation.enable = config.animation.enable;        	
        }
        if(config.legend != undefined) {
        	this.legend.enable = config.legend.enable;        	
        }
        if(config.text != undefined) {
        	this.text.enable = config.text.enable;
        }
    },
    
    render : function() {
    	// initialization circle
    	this.circle.cx = this.width/2;
    	this.circle.cy = this.height/2;
    	this.circle.radius = Math.min(this.width/2, this.height/2) - Math.max(this.edge.width, this.edge.height);
    	var ctx = null;
    	if(this.animation.enable) {
    		this.animation.animCanvas = document.createElement("canvas");
        	this.animation.animCanvas.width = this.width;
        	this.animation.animCanvas.height = this.height;
        	ctx = this.animation.animCanvas.getContext("2d");
    	} else {
    		ctx = this.chartCanvas.getContext("2d");
    		this.renderBorder(ctx);
    	}
    	
    	if(this.circle.radius <= 0) {
    		ctx.strokeText("Can not reader the chart, Circle is too small.");
    		return;
    	}
    	
    	// draw each arc according to data series 
    	var sum = 0;
    	var nums = this.series.length;
    	for(var i=0; i this.width) {
				loc.x = loc.x - this.tooltips.tooltipCanvas.width;
			}
			if((loc.y - this.tooltips.tooltipCanvas.height) <= 0) {
				loc.y = loc.y + this.tooltips.tooltipCanvas.height;
			}
			ctx.drawImage(this.tooltips.tooltipCanvas, 0, 0, this.tooltips.tooltipCanvas.width, this.tooltips.tooltipCanvas.height, 
					loc.x, loc.y-this.tooltips.tooltipCanvas.height, this.tooltips.tooltipCanvas.width, this.tooltips.tooltipCanvas.height);	
    	} else {
    		this.tooltips.index = -1;
    		this.clearTooltips(ctx);
    	}
    },
    
    clearTooltips : function(ctx) {
		ctx.clearRect(0,0,this.width, this.height);
		this.renderBorder(ctx);
		ctx.drawImage(this.animation.animCanvas, 0, 0, this.width, this.height, 0, 0, this.width, this.height); 
    },
    
    renderBorder : function(ctx) {
		ctx.save();
		ctx.fillStyle="white";
		ctx.strokeStyle="black";
		ctx.fillRect(0, 0, this.width, this.height);
		ctx.strokeRect(0, 0, this.width, this.height);
		ctx.restore();
    },
    
    renderPie : function(ctx, index, precent, deltaArc) {
    	var endAngle = deltaArc + 2*Math.PI*precent;
    	ctx.beginPath();
    	ctx.arc(this.circle.cx, this.circle.cy, this.circle.radius, deltaArc, endAngle, false);
    	ctx.moveTo(this.circle.cx, this.circle.cy);
    	ctx.lineTo(this.circle.cx + this.circle.radius * Math.cos(deltaArc), this.circle.cy + this.circle.radius * Math.sin(deltaArc));
    	ctx.lineTo(this.circle.cx + this.circle.radius * Math.cos(endAngle), this.circle.cy + this.circle.radius * Math.sin(endAngle));
    	ctx.lineTo(this.circle.cx, this.circle.cy);
    	ctx.closePath();
    	ctx.fillStyle = this.series[index].color;
    	ctx.fill();
    	
    	// render text content
    	if(this.text.enable) {    		
    		var halfEndAngle = deltaArc + Math.PI*precent;
    		var hx = this.circle.cx + this.circle.radius * Math.cos(halfEndAngle);
    		var hy = this.circle.cy + this.circle.radius * Math.sin(halfEndAngle);
    		ctx.beginPath();
    		ctx.moveTo(hx, hy);
    		var linePos = (hx < this.circle.cx) ? (hx - this.edge.width) : (hx + this.edge.width);
    		ctx.lineTo(linePos, hy);
    		ctx.closePath();
    		ctx.strokeStyle="black";
    		ctx.stroke();
    		var textPos = (hx < this.circle.cx) ? (hx - this.edge.width*2) : (hx + this.edge.width);
    		precent = Math.round (precent*100) / 100;
    		var size = this.text.content.length;
    		var tipStr = (size > index) ? this.text.content[index] : this.series[index].name + ": " + (precent * 100).toFixed(0) + "%";
    		ctx.font = '10pt Calibri';
    		ctx.fillStyle="black";
    		ctx.fillText(tipStr, textPos, hy);
    	}
    },
    
    renderLegend : function(ctx, sum) {
    	if(!this.legend.enable) return;
    	var nums = this.series.length;
    	ctx.font = '10pt Calibri';
    	var pos = (this.width/2 > (this.circle.radius+50)) ? 50 : (this.circle.cx - this.circle.radius);
    	for(var i=0; i
源代码可以直接使用

你可能感兴趣的:(纯HTML5 Canvas实现的饼图)