使用 javascript 将标签百分比定位在 canvas 弧上

position the label percentage on canvas arc using javascript

我使用 canvas 和百分比数据绘制了圆弧。现在,我想用百分比文本(例如:20%)标记每个数据。我在 canvas 弧上定位数据百分比标签时遇到问题。我无法在每个圆弧内正确定位文本。

blue-20% , yellow-20%, red-10%

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var jQCanvas = $('#canvas');
var canvas = jQCanvas[0];
canvas.width = jQCanvas.width();
canvas.height = jQCanvas.height();

center_x = canvas.width / 2; //x
center_y = canvas.height / 2; //y
lineWidth = 20;
var radius = canvas.height / 2 - 20; //r
circle(center_x, center_y, radius);

function circle(x, y, r) {
  var starting_point = 1.5 * Math.PI;
  cumulative_degree = 0;
  data = [
    ['#17a2b8', 20],
    ['#ffc107', 20],
    ['#dc3545', 10]
  ]; //value in percent             
  ctx.lineWidth = 20; //arc thickness

  for (j = 0; j < data.length; j++) {
    ctx.strokeStyle = data[j][0]; //arc color
    ctx.beginPath();
    start = cumulative_degree * (Math.PI / 180) + starting_point;
    degree = data[j][1] / 100 * 360;
    cumulative_degree += data[j][1] / 100 * 360;
    end = degree * (Math.PI / 180) + start;
    ctx.arc(x, y, r, start, end);
    //ctx.fillText(data[j][1]+'%', start, end);
    ctx.stroke();

    // draw the label
    var midAngle = ((cumulative_degree - 90) - degree) + ((cumulative_degree - 90) - ((cumulative_degree - 90) - degree)) / 2;
    var labelRadius = r * .75;
    var cx = 50;
    var cy = 50;
    var lbl_x = cx + (labelRadius) * Math.cos(midAngle);
    var lbl_y = cy + (labelRadius) * Math.sin(midAngle);
    ctx.fillStyle = 'black';
    ctx.fontSize = 30;
    ctx.fillText(data[j][1], lbl_x, lbl_y);
  }
  remaining_degree = 360 - cumulative_degree;
  ctx.strokeStyle = 'silver'; //arc color
  ctx.beginPath();
  start = cumulative_degree * (Math.PI / 180) + starting_point;
  degree = remaining_degree;
  end = degree * (Math.PI / 180) + start;
  ctx.arc(x, y, r, start, end);
  if (remaining_degree > 0) {
    ctx.stroke();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" height="150" width="150"></canvas>

我在计算midAngle时使用了起始角和结束角的弧度而不是角度。这是因为在计算弧度时,我添加了 starting_point (1.5*Math.PI) 因为我从顶部画弧。然后,使用midAngle计算标签位置的x和y。

var lbl_x = cx + (labelRadius) * Math.cos(midAngle);
var lbl_y = cy + (labelRadius) * Math.sin(midAngle);

对于cx和cy,我给出了canvas.width/2;canvas.height/2;

的值

var canvas = document.getElementById("canvas");
var ctx = setupCanvas(document.querySelector('#canvas'));//to sharpen blur text on canvas
var ctx = canvas.getContext("2d");
        
        var jQCanvas = $('#canvas');
        var canvas = jQCanvas[0];
        canvas.width = jQCanvas.width();
        canvas.height = jQCanvas.height();
        
        center_x=canvas.width/2;//x
        center_y=canvas.height/2;//y
        lineWidth=20;
        var radius = canvas.height/2 - 20;//r
        circle(center_x, center_y, radius);
    function setupCanvas(canvas) {//increase device pixel ratio by adding 0.05
              // Get the device pixel ratio, falling back to 1.
              var dpr = window.devicePixelRatio || 1;
              // Get the size of the canvas in CSS pixels.
              var rect = canvas.getBoundingClientRect();
              //console.log(dpr+'=>'+rect);
              dpr=dpr+0.05;
              // Give the canvas pixel dimensions of their CSS
              // size * the device pixel ratio.
              canvas.width = rect.width * dpr;
              canvas.height = rect.height * dpr;
              var ctx = canvas.getContext('2d');
              // Scale all drawing operations by the dpr, so you
              // don't have to worry about the difference.
              ctx.scale(dpr, dpr);
              return ctx;
            } //high dpi canvas(https://www.html5rocks.com/en/tutorials/canvas/hidpi/)
    function circle(x,y,r)
    {
      var starting_point=1.5*Math.PI;
                cumulative_degree=0;
                
                data=[['#17a2b8',25],['#ffc107',20],['#dc3545',5]];//value in percent               
                ctx.lineWidth=20;//arc thickness
        
        for(j=0;j<data.length;j++)
                {
                    ctx.strokeStyle=data[j][0];//arc color
                    ctx.beginPath();
                    start=cumulative_degree* (Math.PI / 180)+starting_point;
                    degree=data[j][1]/100*360;
                    cumulative_degree+=data[j][1]/100*360;
                    end=degree * (Math.PI / 180)+start;
                    ctx.arc(x, y, r, start, end);                   
                ctx.stroke();
          //label
                  var midAngle=start+(end-start)/2;
                  var labelRadius = r * .75;
                  var cx = center_x;
                  var cy = center_y;
                  var lbl_x = cx + (labelRadius) * Math.cos(midAngle);
                  var lbl_y = cy + (labelRadius) * Math.sin(midAngle);
                  ctx.fillStyle = 'black';
                  ctx.fontSize= 30;
                  console.log(lbl_x+'=>'+lbl_y);
                  ctx.fillText(data[j][1], lbl_x, lbl_y);   
                }
        
         remaining_degree=360-cumulative_degree;
                 ctx.strokeStyle='silver';//arc color
                    ctx.beginPath();
                    start=cumulative_degree* (Math.PI / 180)+starting_point;
                    degree=remaining_degree;
                    end=degree * (Math.PI / 180)+start;
                    ctx.arc(x, y, r, start, end);   
                    if(remaining_degree>0)
                    {
                        ctx.stroke();
                    }   
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" height="150" width="150"></canvas>