How to use Chart.js plugin data-labels with ng2-chart?

旧街凉风 提交于 2019-12-11 08:38:40

问题


Well, here I am again with my Angular and javascript woes feeling dumber for each question I ask.

But let me try to explain my initial steps and how it lead to this problem. So, in my latest project, I wanted to throw some fancy charts to make things cleaner and more approachable for the user. Chart.js came to mind... or I should say, ng2-charts.

Things were peachy, stuff looked nice, but... I had two problems. On a horizontal bar, I wanted to dynamically alter the size of the chart, so the user didn't have to scroll for an obscure amount of time to get down the page. So instead of this unwieldy beast...

I try to apply some Angular magic. Later on I want to calculate the size of it on my backend end. For now, a static value shall do.

@ViewChild('inventoryChart') itemChart : ElementRef;

constructor(public renderer: Renderer2) { }

ngAfterViewInit() {
   this.renderer.setStyle(this.itemChart.nativeElement, 'height', '230px')
}

Which leads to...

Nice. But my second problem was a lot harder than I assumed it to be. I wanted the charts to have the respective values on each bar chart. I was somewhat shocked to learn, that it wasn't an innate feature of chart.js but a plugin instead. So I tried to narrow down my problems I had by looking at my chart configuration.

@ViewChild('itemChart') itemChart : ElementRef;

  //public context: CanvasRenderingContext2D;

  public chartType: string = 'horizontalBar';

  chartDatalabel: ChartLabel;

  public chartDatasets: Array<any> = [
    { data: [28, 20, 6, 5, 3], label: 'Inventory per country' }
  ];

  public chartLabels: Array<any> = ['DEU', 'SVK', 'FRA', 'GBR', 'AUT'];

  public chartColors: Array<any> = [
    {
      backgroundColor: '#0E599A',
      pointBackgroundColor: 'rgba(220,220,220,1)',
      pointBorderColor: '#fff',
      pointHoverBackgroundColor: '#fff',
      pointHoverBorderColor: 'rgba(220,220,220,1)'
    },
  ];

  public chartOptions: any = {
    responsive: true,
    maintainAspectRatio: false,

    scales: {
      yAxes: [{
        barPercentage: .9,
        categoryPercentage: .9,

        gridLines: {
          offsetGridLines: true,
          display: true,
        },
        ticks: {
          beginAtZero: true
        } 
      }], 
      xAxes: [{
        ticks: {
          beginAtZero: true, 
          min: 0
        },
        gridLines: {
          offsetGridLines: true,
          display: true,
        },
      }]
    },
  };

Since I had a similar question and by looking at the documentation... it would require the chart to register the plugin.

So I added

import { Chart } from 'chart.js';

But quickly realized, I didn't know how to actually get this chart instance I was creating in my component. And how could I add this in the option for this specific chart only? I didn't find many sources with a similar problem to mine (which made me feel even more inept...).

Is there any clean 'angular-way' to add this plugin in ng2-charts?

EDIT: Judging from the documentation, I could define what the plugin can do in the following ways...

var plugin = { /* plugin implementation */ };

And then calling this plugin in the options of the chart or globally...

Chart.plugins.register({
    // plugin implementation
});

Which I would like to avoid. Never a fan of global configuration unless absolutely necessary and time-saving.

EDIT2: Sorta gave up on NOT registering it globally, but it still doesn't help a whole lot. I added to my imports...

import { Chart } from 'chart.js';
import * as ChartLabel from 'chartjs-plugin-datalabels';

And then tried to register the plugin in the global Chart.

  ngOnInit() {
    Chart.plugins.register(ChartLabel);
  }

Which has done 'something' as far as I can tell. So I attempted to do a very basic implementation of the plugin. The other tooltips don't work anymore but it only triggers an error when I hover around the bars.

plugins: {
  datalabels: {
    color: 'white',
    display: true,
    font: {
      weight: 'bold'
    },
    formatter: Math.round
  }
},

No clue what I can do anymore...


回答1:


Well, since there was literally no answer, I could ultimately settle for the "Global" Chart solution.

Chart.pluginService.register({
  // I gave it an id, so I could disable the plugin if needed
  id: 'p1', 
  afterDatasetsDraw: function (chart, _ease) {

    let width = chart.chart.width;
    let ctx = chart.chart.ctx;

    let datasets = chart.data.datasets;

    datasets.forEach(function (_dataset, index) {
      let meta = chart.getDatasetMeta(index);

      // grabbing the array with the data...
      let barLabelData = meta.controller._data;
      // console.log(meta.controller._data)

      if (!meta.hidden) {
        meta.data.forEach(function (segment, _index) {
          let model = segment._model;
          let position = segment.tooltipPosition();


          let x = position.x;
          let y = position.y;

          let height = model.height;

          ctx.restore();

          ctx.textBaseline = "middle";
          // var fontSize = (height / 114).toFixed(2);
          ctx.font = 'bold ' + height / 2 + 'px Arial';
          ctx.fillStyle = '#777'; //first label's font color


          let text = barLabelData[_index];

          ctx.fillText(text, x, y);
          ctx.save();


        })

      }

    });

  }
});

Which ultimately graced me with a sorta okay looking chart. So yeah, it's not at clean as I would like to. But there are still issues with implementation.

My Chart component globally implements my plugin logic. That's awful deisgn here and I have to decouple it. The minor problem is, I have to make sure the labels work always and are properly depicted. But for now I'm pleased it works.



来源:https://stackoverflow.com/questions/50210847/how-to-use-chart-js-plugin-data-labels-with-ng2-chart

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!