备注挺详细的,这里做个记录存一下。。
参考网址:
https://www.cnblogs.com/merryZhang/archive/2017/07/24/7126168.html
https://blog.csdn.net/xutongbao/article/details/82786929
https://www.cnblogs.com/OrochiZ-/p/11646841.html
最后效果图
canvas.html内容
<body>
<canvas id="drawing" width="600px" height="456px">
<span>不支持canvas浏览器</span>
</canvas>
<script src="./canvas.js"></script>
<script>
var data = [
{percent: 0.426, color: '#2ec7c9', title: '卧房'},
{percent: 0.139, color: '#b6a2dd', title: '客厅'},
{percent: 0.188, color: '#5bb1ee', title: '卫生间'},
{percent: 0.109, color: '#ffb981', title: '阳台'},
{percent: 0.149, color: '#d87a80', title: '厨房'},
]
var centerData = {
price: '74,007',
miniPrice: '740'
}
var pieChart = new PieChart('drawing', 160, 120)
pieChart.init(data, centerData)
</script>
</body>
canvas.js
var PieChart = function(canvasId, outr, inr) {
this.drawing = document.getElementById(canvasId);
this.ctx = this.drawing.getContext('2d');
this.outr = outr; //环形外半径
this.inr = inr; //环形外半径
// 环形图圆心
this.ox = (drawing.width - this.outr * 2) / 2 + this.outr;
this.oy = (drawing.height - this.outr * 2) / 2 + this.outr;
this.outLineW = this.outr + 30
}
PieChart.prototype.init = function(data,centerData) {
this.drawPie(data);
this.drawingCenterText(centerData);
}
PieChart.prototype.drawPie = function(data) {
// 绘制饼图
var startAngle = 0, endAngle = 0;//起始、结束弧度
for (var i = 0,len = data.length; i < len; i++) {
this.ctx.beginPath()//开始绘制
endAngle += data[i].percent * 2 * Math.PI;//确定结束弧度
this.ctx.fillStyle = data[i].color;//设置填充颜色
this.ctx.moveTo(this.ox,this.oy)//位置挪到先前设置的圆心
this.ctx.arc(this.ox, this.oy, this.outr, startAngle, endAngle, false)//画大饼
this.ctx.fill();//填充
var lineAngle = (startAngle + endAngle) / 2;//先算出画线角度
// 画延长线
this.drawingLine(lineAngle, data[i])
startAngle = endAngle//更新起始弧度
// 绘制中间圆
this.drawingCover();
}
}
// 绘制延长线
PieChart.prototype.drawingLine = function(lineAngle, dataItem){
var outX = this.ox + this.outLineW * Math.cos(lineAngle)
var outY = this.oy + this.outLineW * Math.sin(lineAngle)
this.ctx.beginPath()
this.ctx.moveTo(this.ox,this.oy)
this.ctx.lineTo(outX, outY);
if(outX >= this.ox) {
this.ctx.lineTo(outX + 20, outY);
this.drawingText(outX + 30, outY, 'left', dataItem)
} else {
this.ctx.lineTo(outX - 20, outY);
this.drawingText(outX - 30, outY, 'right', dataItem)
}
this.ctx.strokeStyle = dataItem.color;
this.ctx.stroke();
}
// 绘制文字
PieChart.prototype.drawingText = function(tX, tY, algin, dataItem){
this.ctx.textAlign = algin;//对齐方式
this.ctx.font = '24px 微软雅黑';//字体
this.ctx.fillStyle = '#333';//文字颜色
this.ctx.fillText(dataItem.title, tX, tY + 25);
this.ctx.fillText((dataItem.percent*100).toFixed(1)+'%',tX, tY);
}
// 绘制中间遮挡圆
PieChart.prototype.drawingCover = function(){
this.ctx.beginPath()//开始绘制
this.ctx.moveTo(this.ox,this.oy)//位置挪到先前设置的圆心
this.ctx.fillStyle = '#FFFFFF';
this.ctx.arc(this.ox, this.oy, this.inr, 0, Math.PI*2, false);
this.ctx.fill();
}
// 绘制中间文字
PieChart.prototype.drawingCenterText = function(centerData){
var price = centerData.price,
symbol = '¥',
miniText = '约' + centerData.miniPrice + '元/㎡';
//开始绘制价格
this.ctx.beginPath();
this.ctx.textAlign = 'center';
this.ctx.font = '46px 微软雅黑';
var priceW = this.ctx.measureText(price).width;//必须在字体之后才能正常获取宽度
this.ctx.fillStyle = '#ff5384';
this.ctx.fillText(price,this.ox + 12, this.oy - 12);
//开始绘制左侧符号
this.ctx.beginPath();
this.ctx.font = '28px 微软雅黑';
this.ctx.fillStyle = '#ccc';
this.ctx.fillText(symbol,this.ox - priceW/2, this.oy - 12);
// 绘制底部弧形背景矩形
this.fillRoundRect(this.ctx, this.ox-76, this.oy+10, 152, 52, 26, '#f8f8f8');
// 开始绘制底部小文字
this.ctx.beginPath();
this.ctx.textAlign = 'center';
this.ctx.font = '24px 微软雅黑';
this.ctx.fillStyle = '#333333';
this.ctx.fillText(miniText,this.ox, this.oy + 46);
}
// 绘制底部弧形背景矩形
PieChart.prototype.fillRoundRect = function(cxt, x, y, width, height, radius, fillColor) {
//圆的直径必然要小于矩形的宽高
if (2 * radius > width || 2 * radius > height) { return false; }
cxt.save();
cxt.translate(x, y);
//绘制圆角矩形的各个边
this.drawRoundRectPath(cxt, width, height, radius);
cxt.fillStyle = fillColor || "#000"; //若是给定了值就用给定的值否则给予默认值
cxt.fill();
cxt.restore();
}
PieChart.prototype.drawRoundRectPath = function(cxt, width, height, radius) {
cxt.beginPath(0);
//从右下角顺时针绘制,弧度从0到1/2PI
cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
//矩形下边线
cxt.lineTo(radius, height);
//左下角圆弧,弧度从1/2PI到PI
cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
//矩形左边线
cxt.lineTo(0, radius);
//左上角圆弧,弧度从PI到3/2PI
cxt.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
//上边线
cxt.lineTo(width - radius, 0);
//右上角圆弧
cxt.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);
//右边线
cxt.lineTo(width, height - radius);
cxt.closePath();
}