首页 > 解决方案 > 使用 Charts.js 和 Angular 8 在 y 轴上带有百分比值的堆积面积图

问题描述

我正在使用 Angular 8 和 ng2-charts 包来创建堆叠面积图。我想创建一个这样的图表。我尝试使用最小值和最大值来创建从 0% 到 100% 的 Y 轴,但它对不同的数据不正确(如果每个标签的数据总和大于 100,则图表超出范围)。我也想将它们堆叠在一起显示,但不知道如何实现这一点。

我还将我的代码附在我试图写这个的 stackblitz 上。

标签: javascriptangularchart.jsng2-charts

解决方案


更新的答案:

我对打字稿或角度一无所知。这就是为什么我用纯 Javascript 编写程序的原因。

花了我一些时间,更新图例并不容易chart.js......

我知道这很复杂,可能不是最佳解决方案。请随时向我询问代码或告诉我可能的改进。

带有实时预览的完整代码:https ://jsbin.com/detiqucime/6/edit?js,output

完整代码:

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

const dataLabels = [
  'First', 
  'Second', 
  'Third'
]

const colors = {
  'First': '#bad96b',
  'Second': '#8ad0f9',
  'Third': '#ffda78'
}

let data = [
  [65, 59, 80, 81, 56, 55, 40],
  [28, 48, 40, 19, 86, 27, 90],
  [22, 44, 23, 69, 82, 47, 50]
]

// hiddenArray (array with 'true' or 'null' (hidden or not) to know which datasets are hidden, those get not calculated)
let hiddenArray = []
// Initiate hiddenArray: nothing hidden at start
for (let i = 0; i < data.length; i++) {
  hiddenArray.push(null)
}

// New data array we use for the chart
let percentageData = []

calcPercentages(hiddenArray)

function calcPercentages(hiddenArray) {
  percentageData = []

  // Fill percentageData with empty arrays for same structure like data
  for (let i = 0; i < data.length; i++) {
    percentageData.push([])
  }

  for (let innerKey in data[0]) {
    // Get the sum of each data
    let sum = 0
    for (let outerKey in data) {
      if (hiddenArray[outerKey]) {
        continue;
      }
      sum = sum + data[outerKey][innerKey]
    }

    // Calculate the new percentageData
    for (let outerKey in data) {
      if (hiddenArray[outerKey]) {
        percentageData[outerKey][innerKey] = 0
      } else {
        percentageData[outerKey][innerKey] = (data[outerKey][innerKey]/sum)*100
      }
    }
  }
}

let chartData = {
  labels: ['2006', '2007', '2008', '2009', '2010', '2011', '2012'],
  datasets: []
}

for (let i = 0; i < data.length; i++) {
  let newDataset = {}
  newDataset.label = dataLabels[i]
  newDataset.backgroundColor = colors[dataLabels[i]]
  newDataset.data = percentageData[i]
  chartData.datasets.push(newDataset)
}

let options = {
  responsive: true,
  legend: {
    //reverse: true,
    onClick: function(e, legendItem) {
      let index = legendItem.datasetIndex;
      let ci = this.chart;      
      let meta = ci.getDatasetMeta(index);

      // Change 'hidden'-property
      meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;      

      // Get hiddenArray
      let hiddenArray = []

      ci.data.datasets.forEach(function(e, i) {
        let meta = ci.getDatasetMeta(i);
        hiddenArray.push(meta.hidden)
      });

      // Update percentageData
      calcPercentages(hiddenArray)

      for (let i = 0; i < percentageData.length; i++) {
        chartData.datasets[i].data = percentageData[i]
      }

      // Rerender the chart
      ci.update();
    }
  },
  scales: {
    yAxes: [{
      stacked: true,
      ticks: {
        min: 0,
        max: 100,
        callback: function(value) {
          return value + '%'
        }
      }
    }],
  },
  tooltips: {
    callbacks: {
      label: function(tooltipItem){
        return data[tooltipItem.datasetIndex][tooltipItem.index]
      }
    }
  }
}

let myChart = new Chart(ctx, {
  type: 'line',
  data: chartData,
  options: options,
});

推荐阅读