【问题标题】:Stacked bar chart with rounded corner of bar using Chart.js使用 Chart.js 的条形圆角堆积条形图
【发布时间】:2018-05-04 15:52:30
【问题描述】:

我尝试了各种自定义示例。 但它们只提供单个数据,但我需要最后一个圆角数据

https://jsfiddle.net/ankitkothari/7km2ytjo/2/

请参考以上链接 其中的示例代码 我需要最上面的数据在圆角而不是底部数据

请参考上面的示例代码链接,因为我需要最顶部的数据在圆角而不是底部数据。

Chart.elements.Rectangle.prototype.draw = function() {
    debugger;
    var ctx = this._chart.ctx;
    var vm = this._view;
    var left, right, top, bottom, signX, signY, borderSkipped, radius;
    var borderWidth = vm.borderWidth;
    // Set Radius Here
    // If radius is large enough to cause drawing errors a max radius is imposed
    var cornerRadius = 10;

    if (!vm.horizontal) {
        // bar
        left = vm.x - vm.width / 2;
        right = vm.x + vm.width / 2;
        top = vm.y;
        bottom = vm.base;
        signX = 1;
        signY = bottom > top? 1: -1;
        borderSkipped = vm.borderSkipped || 'bottom';
    } else {
        // horizontal bar
        left = vm.base;
        right = vm.x;
        top = vm.y - vm.height / 2;
        bottom = vm.y + vm.height / 2;
        signX = right > left? 1: -1;
        signY = 1;
        borderSkipped = vm.borderSkipped || 'left';
    }

    // Canvas doesn't allow us to stroke inside the width so we can
    // adjust the sizes to fit if we're setting a stroke on the line
    if (borderWidth) {
        // borderWidth shold be less than bar width and bar height.
        var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
        borderWidth = borderWidth > barSize? barSize: borderWidth;
        var halfStroke = borderWidth / 2;
        // Adjust borderWidth when bar top position is near vm.base(zero).
        var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
        var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
        var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
        var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
        // not become a vertical line?
        if (borderLeft !== borderRight) {
            top = borderTop;
            bottom = borderBottom;
        }
        // not become a horizontal line?
        if (borderTop !== borderBottom) {
            left = borderLeft;
            right = borderRight;
        }
    }

    ctx.beginPath();
    ctx.fillStyle = vm.backgroundColor;
    ctx.strokeStyle = vm.borderColor;
    ctx.lineWidth = borderWidth;

    // Corner points, from bottom-left to bottom-right clockwise
    // | 1 2 |
    // | 0 3 |
    var corners = [
        [left, bottom],
        [left, top],
        [right, top],
        [right, bottom]
    ];

    // Find first (starting) corner with fallback to 'bottom'
    var borders = ['bottom', 'left', 'top', 'right'];
    var startCorner = borders.indexOf(borderSkipped, 0);
    if (startCorner === -1) {
        startCorner = 0;
    }

    function cornerAt(index) {
        return corners[(startCorner + index) % 4];
    }

    // Draw rectangle from 'startCorner'
    var corner = cornerAt(0);
    ctx.moveTo(corner[0], corner[1]);

    for (var i = 1; i < 4; i++) {
        corner = cornerAt(i);
        nextCornerId = i+1;
        if(nextCornerId == 4){
            nextCornerId = 0
        }

        nextCorner = cornerAt(nextCornerId);

        width = corners[2][0] - corners[1][0];
        height = corners[0][1] - corners[1][1];
        x = corners[1][0];
        y = corners[1][1];

        var radius = cornerRadius;

        // Fix radius being too large
        if(radius > height/2){
            radius = height/2;
        }if(radius > width/2){
            radius = width/2;
        }

        ctx.moveTo(x + radius, y);
        ctx.lineTo(x + width - radius, y);
         ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
        ctx.lineTo(x + width, y + height - radius);
        ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
        ctx.lineTo(x + radius, y + height);
        ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
        ctx.lineTo(x, y + radius);
        ctx.quadraticCurveTo(x, y, x + radius, y);

    }

    ctx.fill();
    if (borderWidth) {
        ctx.stroke();
    }
}; 
 var data = {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 5
        },{
            label: '# of Votes',
            data: [20, 5, 10, 15, 12, 13],
            backgroundColor: [
             'rgba(255, 159, 64, 1)',
                'rgba(255, 99, 132, 1)',               
                'rgba(255, 206, 86, 1)',

                'rgba(54, 162, 235, 1)',
                'rgba(153, 102, 255, 1)',
                 'rgba(75, 192, 192, 1)'

            ],
            borderWidth: 5
        }]
    };
var options = {
elements:{ point: {
     radius:25,
     hoverRadius:35,
     pointStyle:'rectRounded'
    }},
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,
                radius:25
            }],
            xAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,

            }]
        }
    };




var ctxBar = document.getElementById("myChart");
var myBarChart = new Chart(ctxBar, {
    type: 'bar',
    data: data,
    options: options
});

【问题讨论】:

    标签: javascript jquery charts chart.js bar-chart


    【解决方案1】:

    这将在下一个主要版本中添加。 https://www.chartjs.org/docs/master/charts/bar#borderradius

    【讨论】:

      【解决方案2】:

      我改变了你的小提琴,所以只有顶部的矩形边框是圆形的。诀窍是使用图表的 getDatasetMeta 检查矩形的可见性状态,并根据它是否是最后一个可见的 om 堆栈来决定。

      这仅适用于您的两个数据集的示例数据,但也可以更改为使用任意数量。

      https://jsfiddle.net/a6m34c01/


      编辑:处理数据的任意计数。

      https://jsfiddle.net/a6m34c01/8/

      Chart.elements.Rectangle.prototype.draw = function() {
          debugger;
          var ctx = this._chart.ctx;
          var vm = this._view;
          var left, right, top, bottom, signX, signY, borderSkipped, radius;
          var borderWidth = vm.borderWidth;
          // Set Radius Here
          // If radius is large enough to cause drawing errors a max radius is imposed
          var cornerRadius = 10;
      
          if (!vm.horizontal) {
              // bar
              left = vm.x - vm.width / 2;
              right = vm.x + vm.width / 2;
              top = vm.y;
              bottom = vm.base;
              signX = 1;
              signY = bottom > top? 1: -1;
              borderSkipped = vm.borderSkipped || 'bottom';
          } else {
              // horizontal bar
              left = vm.base;
              right = vm.x;
              top = vm.y - vm.height / 2;
              bottom = vm.y + vm.height / 2;
              signX = right > left? 1: -1;
              signY = 1;
              borderSkipped = vm.borderSkipped || 'left';
          }
      
          // Canvas doesn't allow us to stroke inside the width so we can
          // adjust the sizes to fit if we're setting a stroke on the line
          if (borderWidth) {
              // borderWidth shold be less than bar width and bar height.
              var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
              borderWidth = borderWidth > barSize? barSize: borderWidth;
              var halfStroke = borderWidth / 2;
              // Adjust borderWidth when bar top position is near vm.base(zero).
              var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
              var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
              var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
              var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
              // not become a vertical line?
              if (borderLeft !== borderRight) {
                  top = borderTop;
                  bottom = borderBottom;
              }
              // not become a horizontal line?
              if (borderTop !== borderBottom) {
                  left = borderLeft;
                  right = borderRight;
              }
          }
      
          ctx.beginPath();
          ctx.fillStyle = vm.backgroundColor;
          ctx.strokeStyle = vm.borderColor;
          ctx.lineWidth = borderWidth;
      
          // Corner points, from bottom-left to bottom-right clockwise
          // | 1 2 |
          // | 0 3 |
          var corners = [
              [left, bottom],
              [left, top],
              [right, top],
              [right, bottom]
          ];
      
          // Find first (starting) corner with fallback to 'bottom'
          var borders = ['bottom', 'left', 'top', 'right'];
          var startCorner = borders.indexOf(borderSkipped, 0);
          if (startCorner === -1) {
              startCorner = 0;
          }
      
          function cornerAt(index) {
              return corners[(startCorner + index) % 4];
          }
      
          // Draw rectangle from 'startCorner'
          var corner = cornerAt(0);
          ctx.moveTo(corner[0], corner[1]);
      
          for (var i = 1; i < 4; i++) {
              corner = cornerAt(i);
              nextCornerId = i+1;
              if(nextCornerId == 4){
                  nextCornerId = 0
              }
      
              nextCorner = cornerAt(nextCornerId);
      
              width = corners[2][0] - corners[1][0];
              height = corners[0][1] - corners[1][1];
              x = corners[1][0];
              y = corners[1][1];
      
              var radius = cornerRadius;
      
              // Fix radius being too large
              if(radius > height/2){
                  radius = height/2;
              }if(radius > width/2){
                  radius = width/2;
              }
      
      
      
              var lastVisible = 0;
              for(var findLast=0, findLastTo=this._chart.data.datasets.length;findLast<findLastTo;findLast++) {
                  if (!this._chart.getDatasetMeta(findLast).hidden) {
                  lastVisible =findLast;
                }
              }
              var rounded = this._datasetIndex  === lastVisible;
      
              if (rounded) {
                ctx.moveTo(x + radius, y);
                ctx.lineTo(x + width - radius, y);
                ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
                ctx.lineTo(x + width, y + height);
                ctx.lineTo(x, y + height);
                ctx.lineTo(x, y + radius);
                ctx.quadraticCurveTo(x, y, x + radius, y);
              } else {
                ctx.moveTo(x, y);
                ctx.lineTo(x + width, y);
                ctx.lineTo(x + width, y + height );
                ctx.lineTo(x , y + height);
                ctx.lineTo(x, y );
              }
      
          }
      
          ctx.fill();
          if (borderWidth) {
              ctx.stroke();
          }
      }; 
       var data = {
          labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
              datasets: [{
                  label: '# of Votes',
                  data: [12, 19, 3, 5, 2, 3],
                  backgroundColor: [
                      'rgba(255, 99, 132, 1)',
                      'rgba(54, 162, 235, 1)',
                      'rgba(255, 206, 86, 1)',
                      'rgba(75, 192, 192, 1)',
                      'rgba(153, 102, 255, 1)',
                      'rgba(255, 159, 64, 1)'
                  ],
                  borderWidth: 5
              },{
                  label: '# of Votes',
                  data: [20, 5, 10, 15, 12, 13],
                  backgroundColor: [
                   'rgba(255, 159, 64, 1)',
                      'rgba(255, 99, 132, 1)',               
                      'rgba(255, 206, 86, 1)',
      
                      'rgba(54, 162, 235, 1)',
                      'rgba(153, 102, 255, 1)',
                       'rgba(75, 192, 192, 1)'
      
                  ],
                  borderWidth: 5
              }]
          };
      var options = {
      elements:{ point: {
           radius:25,
           hoverRadius:35,
           pointStyle:'rectRounded'
          }},
              scales: {
                  yAxes: [{
                      ticks: {
                          beginAtZero:true
                      },
                      stacked : true,
                      radius:25
                  }],
                  xAxes: [{
                      ticks: {
                          beginAtZero:true
                      },
                      stacked : true,
      
                  }]
              }
          };
      
      
      
      
      var ctxBar = document.getElementById("myChart");
      var myBarChart = new Chart(ctxBar, {
          type: 'bar',
          data: data,
          options: options
      });
      

      【讨论】:

      • 嗨,感谢您的快速更新,但我放了两个样本数据集,实际上有多个数据集,所以我需要随机逻辑
      • 嗨,如果有 0 个数据,我更新了小提琴,那么它将显示正方形而不是四舍五入 jsfiddle.net/ankitkothari/a6m34c01/9
      • 嗨,我更新了我目前需要的数据集jsfiddle.net/ankitkothari/a6m34c01/10
      • 嘿,@Joschi 如果当前为 0,是否可以舍入下一个数据集?换句话说,我希望在以下示例中将所有条形都舍入。 jsfiddle.net/ankitkothari/a6m34c01/9
      • @VasilEnchev 解决方案是查看从最后一个数据集到第一个数据集的数据集,当您看到第一个未隐藏且值不为 0 的数据集时,您仅对该数据集进行舍入。