【问题标题】:Horizontal stacked angular bar charts水平堆叠角度条形图
【发布时间】:2017-06-10 02:39:09
【问题描述】:

我正在尝试实现一个 Angular 水平堆积条形图 - 类似于 this example

但是,我只想要一个堆叠的条形图。

我正在使用 AngularJS 和 Chart.js。我有页面上显示的示例。

在 PieController 中,ChartData 包含:

 {"data":["63","38"],"labels":["Ford","GM"]}

在示例中,我希望将标签和数字放在图表内部,而不是外部的标签。像 [=====Ford 63====|===GM 38===] 等号代表条形颜色。数据点将比目前的两个多。

这是我的页面

<div ng-controller="PieController">
            data {{ChartData}}   //testing purposes
            <div ng-init="getBarChart()">
            <canvas id="Chart1"></canvas>
</div>

这是我的 JavaScript 控制器

app.controller('PieController', function($scope, ChartService) {


$scope.getBarChart = function(){
    ChartService.get({name: 'main'}, function(data) {
        $scope.ChartData = data;

        var barOptions_stacked = {
            tooltips: {
                enabled: false
            },
            hover: {
                animationDuration: 0
            },
            scales: {
                xAxes: [{
                    ticks: {
                        beginAtZero: true,
                        fontFamily: "'Open Sans Bold', sans-serif",
                        fontSize: 11
                    },
                    scaleLabel: {
                        display: false
                    },
                    gridLines: {},
                    stacked: true
                }],
                yAxes: [{
                    gridLines: {
                        display: false,
                        color: "#fff",
                        zeroLineColor: "#fff",
                        zeroLineWidth: 0
                    },
                    ticks: {
                        fontFamily: "'Open Sans Bold', sans-serif",
                        fontSize: 11
                    },
                    stacked: true
                }]
            },
            legend: {
                display: false
            },

            animation: {
                onComplete: function () {
                    var chartInstance = this.chart;
                    var ctx = chartInstance.ctx;
                    ctx.textAlign = "left";
                    ctx.font = "9px Open Sans";
                    ctx.fillStyle = "#fff";


                    Chart.helpers.each(this.data.datasets.forEach(function (dataset, i) {
                        var meta = chartInstance.controller.getDatasetMeta(i);
                        Chart.helpers.each(meta.data.forEach(function (bar, index) {
                            data = dataset.data[index];
                            if (i == 0) {
                                ctx.fillText(data, 50, bar._model.y + 4);
                            } else {
                                ctx.fillText(data, bar._model.x - 25, bar._model.y + 4);
                            }
                        }), this)
                    }), this);
                }
            },
            pointLabelFontFamily: "Quadon Extra Bold",
            scaleFontFamily: "Quadon Extra Bold",
        };

        var ctx = document.getElementById("Chart1");
        var myChart = new Chart(ctx, {
            type: 'horizontalBar',
            data: {
                labels: ["2014", "2013", "2012", "2011"],

                datasets: [{
                    data: [727, 589, 537, 543, 574],
                    backgroundColor: "rgba(63,103,126,1)",
                    hoverBackgroundColor: "rgba(50,90,100,1)"
                }, {
                    data: [238, 553, 746, 884, 903],
                    backgroundColor: "rgba(163,103,126,1)",
                    hoverBackgroundColor: "rgba(140,85,100,1)"
                }, {
                    data: [1238, 553, 746, 884, 903],
                    backgroundColor: "rgba(63,203,226,1)",
                    hoverBackgroundColor: "rgba(46,185,235,1)"
                }]
            },

            options: barOptions_stacked,
        })

    });//end chat service.get
}

});

与其现在在数据集中进行硬编码,有没有一种方法可以使用我在帖子开头概述的数据“ChartData”?

我不知道该怎么做,或者它是否可能。

【问题讨论】:

    标签: javascript angularjs chart.js


    【解决方案1】:

    为了让标签显示在栏中,请参考$scope.ChartDatalabels属性:

    ctx.fillText($scope.ChartData.labels[index] +" "+ data, 50, bar._model.y + 4);
    

    与其现在在数据集中进行硬编码,有没有一种方法可以使用我在帖子开头概述的数据“ChartData”?

    使用 data 变量的属性(由 ChartService 的 get 函数提供),即 data.labelsdata.data,而不是硬编码值。

    所以更新标签行:

    labels: ["2014", "2013", "2012", "2011"],
    

    到这里:

    labels: data.labels,
    

    对于数据集也是如此:

    datasets: [{
        data: data.data,
    

    所以在创建图表时,它应该如下所示:

    var myChart = new Chart(ctx, {
        type: 'horizontalBar',
        data: {
            labels: data.labels,
            datasets: [{
                data: data.data,
                backgroundColor: "rgba(63,103,126,1)",
                hoverBackgroundColor: "rgba(50,90,100,1)"
            }]
        },
    
        options: barOptions_stacked,
    });
    

    展开下面的代码 sn-p 进行演示。

    注意:resize-listener 目前存在问题,被 CORS 问题阻止 - 我正在尝试找到一种方法来禁用它。

    更新:

    根据您关于堆叠条形(水平)的评论 - 是的,这是可能的。 datasets 数组中的每一项只需有一个元素。一种简单的方法是使用Array.map() 创建一个类似于示例的数组:

    var bgColors = [
        "rgba(63,103,126,1)",
        "rgba(50,90,100,1)"
    ];
    var hoverBgColors = [
        "rgba(50,90,100,1)",
        "rgba(140,85,100,1)"
    ];
    var datasets = data.data.map(function(value, index) {
        return {
          data: [value],
          backgroundColor: bgColors[index],
          hoverBackgroundColor: hoverBgColors[index]
        }
    });
    

    然后在创建图表对象时使用变量datasets

    var myChart = new Chart(ctx, {
        type: 'horizontalBar',
        data: {
            labels: data.labels,
            datasets: datasets
        },
        options: barOptions_stacked,
    });
    

    另外,第二个标签的位置有一些奇怪的数学运算,但辅助函数可以如下更新(我尝试将 x 值除以 75,但这可能需要调整 - 我不确定什么是“合适的”值......):

    if (i == 0) {
        ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
    } else {
        ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
    }
    

    var app = angular.module('myApp', []);
    app.factory('ChartService', function() {
      return { //dummy chart service
        get: function(obj, callback) {
          var data = {
            "data": ["63", "38"],
            "labels": ["Ford", "GM"]
          };
          callback(data);
        }
      };
    });
    app.controller('PieController', function($scope, ChartService) {
      $scope.getBarChart = function() {
        ChartService.get({
          name: 'main'
        }, function(data) {
          $scope.ChartData = data;
          var barOptions_stacked = {
            tooltips: {
              enabled: false
            },
            hover: {
              animationDuration: 0
            },
            scales: {
              xAxes: [{
                ticks: {
                  beginAtZero: true,
                  fontFamily: "'Open Sans Bold', sans-serif",
                  fontSize: 11
                },
                scaleLabel: {
                  display: false
                },
                gridLines: {},
                stacked: true
              }],
              yAxes: [{
                gridLines: {
                  display: false,
                  color: "#fff",
                  zeroLineColor: "#fff",
                  zeroLineWidth: 0
                },
                ticks: {
                  fontFamily: "'Open Sans Bold', sans-serif",
                  fontSize: 11
                },
                stacked: true
              }]
            },
            legend: {
              display: false
            },
            animation: {
              onComplete: function() {
                var chartInstance = this.chart;
                var ctx = chartInstance.ctx;
                ctx.textAlign = "left";
                ctx.font = "9px Open Sans";
                ctx.fillStyle = "#fff";
    
                Chart.helpers.each(this.data.datasets.forEach(function(dataset, i) {
                  var meta = chartInstance.controller.getDatasetMeta(i);
                  Chart.helpers.each(meta.data.forEach(function(bar, index) {
                    data = dataset.data[index];
                    if (i == 0) {
                      ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
                    } else {
                      ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
                    }
                  }), this)
                }), this);
              }
            },
            pointLabelFontFamily: "Quadon Extra Bold",
            scaleFontFamily: "Quadon Extra Bold",
          };
    
          var ctx = document.getElementById("Chart1");
          var bgColors = [
            "rgba(63,103,126,1)",
            "rgba(50,90,100,1)"
          ];
          var hoverBgColors = [
            "rgba(50,90,100,1)",
            "rgba(140,85,100,1)"
          ];
          var datasets = data.data.map(function(value, index) {
            return {
              data: [value],
              backgroundColor: bgColors[index],
              hoverBackgroundColor: hoverBgColors[index]
            }
          });
          var myChart = new Chart(ctx, {
            type: 'horizontalBar',
            data: {
              //use empty labels because the labels are on the bars
              labels: data.labels.map(function() {
                return '';
              }),
              datasets: datasets
            },
            options: barOptions_stacked,
          })
        }); //end chat service.get
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div ng-app="myApp" ng-controller="PieController">
      data {{ChartData}} //testing purposes
      <div ng-init="getBarChart()">
        <canvas id="Chart1"></canvas>

    【讨论】:

    • 这很好,感谢您深思熟虑的回复,但是有没有办法让它们堆叠起来?就像在同一条线上的福特 63 之后的 GM 38?这也是我想要的
    • 另外,将标签设置为空是红色的。它可以工作,但是那条线加上它下面的所有东西都是红色的。标签:data.labels.map(()=>''),
    • 好的,看看我更新的答案。当你说“将标​​签设置为红色”时,我认为你的意思是你的 IDE 将该代码报告为错误。这很可能是因为它是arrow function,是ECMAScript 2015 (6th Edition, ECMA-262) 规范的一部分,IDE 可能未针对它进行配置...无论如何,我将其转换回常规函数以返回空字符串labels: data.labels.map(function() { return '';})跨度>
    • 让我实现这个并回复你。
    • 出于某种原因,我看到标签和数据在第一个栏中重叠。我运行了您的代码 sn-p 并看到您的代码没有这样做,所以不确定我的代码为什么会这样。堆叠条运行良好
    猜你喜欢
    • 2012-05-11
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 2015-02-11
    • 2020-04-10
    • 2021-10-08
    • 1970-01-01
    • 2022-10-13
    相关资源
    最近更新 更多