基本思路:
主要是利用HTML5 Canvas实现饼图绘制,绘制弧度的API主要是使用
context.arc与lineto两个API。
实现的功能有:
1. 支持标签Legend显示或者隐藏
2. 首次载入动画效果
3. 鼠标tooltip效果
4. 自定义饼图大小与是否添加文字
效果如下:
调用代码:
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
源代码可以直接使用