ChartJS 堆积条形图:显示相反方向的值

ChartJS Stacked Bar Chart: Showing value in opposite directions

我想生成一个 stacked bar chart like this。我怎样才能做到这一点?任何解决方案将不胜感激。

经过一些研究和研究,我终于找到了解决我在这里发布的问题的方法。

public static drawDashboard2Chart(data: Dashboard2Data[], canvas: ElementRef) {
const planProfit = data.map(dataUnit => dataUnit.p_profit);
const planExpenses = data.map(dataUnit => dataUnit.p_expenses);
const planSalary = data.map(dataUnit => dataUnit.p_salary);
const factProfit = data.map(dataUnit => dataUnit.f_profit);
const factExpenses = data.map(dataUnit => dataUnit.f_expenses);
const factSalary = data.map(dataUnit => dataUnit.f_salary);

const ctx = canvas.nativeElement.getContext('2d');

const dataArray = [
  {
    label: 'REVENUES PLAN',
    backgroundColor: '#d14035',
    hoverBackgroundColor: '#d14035',
    stack: '0',
    data: planProfit,
    datalabels: {
      color: '#d14035',
    }
  },
  {
    label: 'SALARY PLAN',
    backgroundColor: '#72598e',
    hoverBackgroundColor: '#72598e',
    stack: '1',
    data: planSalary,
    datalabels: {
      color: '#72598e',
    }
  },
  {
    label: 'EXPENSES PLAN',
    backgroundColor: '#a9bb30',
    hoverBackgroundColor: '#a9bb30',
    stack: '1',
    data: planExpenses,
    datalabels: {
      color: '#a9bb30',
    }
  },
  {
    label: 'ACTUAL REVENUES',
    backgroundColor: '#05a6a6',
    hoverBackgroundColor: '#05a6a6',
    stack: '2',
    data: factProfit,
    datalabels: {
      color: '#05a6a6',
    }
  },
  {
    label: 'ACTUAL SALARY',
    backgroundColor: '#c2718c',
    hoverBackgroundColor: '#c2718c',
    stack: '3',
    data: factSalary,
    datalabels: {
      color: '#c2718c',
    }
  },
  {
    label: 'ACTUAL EXPENSES',
    backgroundColor: '#eb8a3c',
    hoverBackgroundColor: '#eb8a3c',
    stack: '3',
    data: factExpenses,
    datalabels: {
      color: '#eb8a3c',
    }
  }
]

const options = {         
  responsive: true,
  maintainAspectRatio: false,
  hover: {
    animationDuration: 0
  },
  plugins: {
    datalabels: {
      display: true,
      align: 'center',
      anchor: 'center',
      font: {
        size: '18',
        weight: '700'
      },
      rotation: 270,
      formatter: function (value, context) {
        return value !== 0 ? value : null;
      }
    }
  },
  legend: {
    onClick: (e) => e.stopPropagation(),
    display: true,
    position: 'top',
    labels: {
      fontFamily: '\'Montserrat\', sans-serif',
      fontSize: 14,
      fontColor: '#000'
    }
  },
  tooltips: {
    callbacks: {
      label: function (tooltipItem, data) {
        return tooltipItem.yLabel.toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');
      }
    }
  },
  scales: {
    xAxes: [{
      stacked: true,
      ticks: {
        fontSize: 15,
        fontStyle: 'normal',
        padding: 100            
      }
    },
    {
      type: 'category',
      offset: true,
      position: 'top',
      ticks: {
        fontColor: "#000",
        fontSize: 18,
        fontStyle: 'bold',
        callback: function (value, index, values) {              
            return "";
        }
      }
    }
  ],
    yAxes: [{
      stacked: true,
      ticks: {
        fontSize: 15,
        fontStyle: 'normal'            
      },
    }],
  },
  animation: {
    duration: 1,
    onComplete: function () {
      var chartInstance = this.chart,
        ctx = chartInstance.ctx;
      var fontSize = 15;
      var fontStyle = 'normal';
      ctx.font = Chart.helpers.fontString(fontSize, fontStyle, Chart.defaults.global.defaultFontFamily);
      ctx.textAlign = 'center';
      ctx.textBaseline = 'center';

      this.data.datasets.forEach(function (dataset, i) {
        var meta = chartInstance.controller.getDatasetMeta(i);
        meta.data.forEach(function (bar, index) {
          if (dataset.data[index] > 0) {    
            if(dataset.stack == '0')   
            {  
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y + bar.height());                
            ctx.rotate(0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }              
            else if(dataset.stack == '1' && dataset.label == 'EXPENSES PLAN')   
            {  
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y);                
            ctx.rotate(-0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }
            else if(dataset.stack == '1' && dataset.label == 'SALARY PLAN')   
            { 
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y + bar.height());                
            ctx.rotate(0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }
            else if(dataset.stack == '2')   
            {  
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y + bar.height());                
            ctx.rotate(0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }    
            else if(dataset.stack == '3' && dataset.label == 'ACTUAL EXPENSES')   
            {  
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y);                
            ctx.rotate(-0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }  
            else if(dataset.stack == '3' && dataset.label == 'ACTUAL SALARY')   
            {  
            var data = dataset.data[index].toFixed().replace(/(\d)(?=(\d{3})+(?!\d))/g, ' ');                          
            ctx.save();
            ctx.translate(bar._model.x, bar._model.y + bar.height());                
            ctx.rotate(0.5 * Math.PI);                           
            ctx.fillText(data, 35, 0); 
            ctx.restore();
            }                           
          }
        });
      });
    }
  }
}

new Chart(ctx, {
  type: "bar",
  data: {
    labels: MONTHS,
    datasets: dataArray
  },
  options: options
});
}