canvas绘制一个简单的带标注的环形饼图

备注挺详细的,这里做个记录存一下。。
参考网址:
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();
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值