leandrocfe / filament-apex-charts

Apex Charts integration for Filament PHP.
https://filament-apex-charts-demo.leandroferreira.dev.br
MIT License
300 stars 38 forks source link

Datalabel formatter #16

Closed RosiersRobin closed 7 months ago

RosiersRobin commented 1 year ago

Hi,

How can I make use of the datalabel formatter?

I have the following array I return;

return [
            'chart' => [
                'type' => 'bar',
                'height' => 300,
                'animations' => [
                    'enabled' => false
                ],
            ],
            'series' => [
                [
                    'name' => 'Sales',
                    'data' => $totalSoldByProduct->pluck('total_revenue')->toArray(),
                ],
            ],
            'xaxis' => [
                'categories' => $totalSoldByProduct->pluck('name')->toArray(),
                'labels' => [
                    'style' => [
                        'colors' => '#9ca3af',
                        'fontWeight' => 600,
                    ],
                ],
            ],
            'yaxis' => [
                'labels' => [
                    'style' => [
                        'colors' => '#9ca3af',
                        'fontWeight' => 600,
                    ],
                ],
            ],
            'dataLabels' => [
                'enabled' => true,
                'formatter' => 'function(val, opts) {
                    return "Sold " + val;
                }',
                'style' => [
                    'colors' => ['#fff'],
                ],
            ],
            'colors' => ['#1da6e7'],
        ];

As you see, there is a formatter;

 'formatter' => 'function(val, opts) {
                    return "Sold " + val;
                }',

But this does not work? How can I achieve this to work?

leandrocfe commented 1 year ago

Hi,

How can I make use of the datalabel formatter?

I have the following array I return;

return [
            'chart' => [
                'type' => 'bar',
                'height' => 300,
                'animations' => [
                    'enabled' => false
                ],
            ],
            'series' => [
                [
                    'name' => 'Sales',
                    'data' => $totalSoldByProduct->pluck('total_revenue')->toArray(),
                ],
            ],
            'xaxis' => [
                'categories' => $totalSoldByProduct->pluck('name')->toArray(),
                'labels' => [
                    'style' => [
                        'colors' => '#9ca3af',
                        'fontWeight' => 600,
                    ],
                ],
            ],
            'yaxis' => [
                'labels' => [
                    'style' => [
                        'colors' => '#9ca3af',
                        'fontWeight' => 600,
                    ],
                ],
            ],
            'dataLabels' => [
                'enabled' => true,
                'formatter' => 'function(val, opts) {
                    return "Sold " + val;
                }',
                'style' => [
                    'colors' => ['#fff'],
                ],
            ],
            'colors' => ['#1da6e7'],
        ];

As you see, there is a formatter;

 'formatter' => 'function(val, opts) {
                    return "Sold " + val;
                }',

But this does not work? How can I achieve this to work?

Hi! We can't use the formatter function in the current version. I have plans to include it in the next version. Maybe you can transform it in you query or using a map function

MdMotahir commented 1 year ago

@leandrocfe we need the 'formatter' function. cause when we try to pass the time value in the y-axis it's not showing the y-axis label correctly.

leandrocfe commented 1 year ago

@leandrocfe we need the 'formatter' function. cause when we try to pass the time value in the y-axis it's not showing the y-axis label correctly.

If it is urgent, you can publish the views and customize what you want. I have plans to do it but now I don't know when.

VictorCano commented 1 year ago

Could adding something like this into chart.blade be a viable default alternative?

initChart: function(options = null) {

    options = options ?? @js($getCachedOptions)

    if (options.dataLabels && options.dataLabels.formatter) {
        options.dataLabels.formatter = eval(options.dataLabels.formatter)
    }

    if (options.yaxis && options.yaxis.labels && options.yaxis.labels.formatter) {
        options.yaxis.labels.formatter = eval(options.yaxis.labels.formatter)
    }

    if (options.xaxis && options.xaxis.labels && options.xaxis.labels.formatter) {
        options.xaxis.labels.formatter = eval(options.xaxis.labels.formatter)
    }

    if (this.darkModeEnabled) {
        options.theme.mode = this.mode
    }

    this.chart = new ApexCharts(document.querySelector('#{{ $chartId }}'), options)

    return this.chart.render()
}

And in the options array of the widget:

'yaxis' => [
    'labels' => [
        'formatter' => '(val, index) => {
            return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
            }',
    ],
],

We managed to do it this way, if you think this could be a viable approach I can review with all the other available formats and send a PR.

aldesrahim commented 11 months ago

hello, is there any updates yet ? thanks

webtamizhan commented 10 months ago

I fixed myself by changing the view file. In my case i have 4 widgets in a page and i just to need to format currency only for Piechart widget, so i am done the following.

  1. Add chartId on your chart widget.(Optional)

protected static string $chartId = "XXXXX"; \\ if you have multiple chart widget, then this will help you only changes

  1. Once you published the view, goto the chart.blade.php file.
  2. Slightly change the options by overriding the options config by following.
    @if($chartId === 'XXXXX')
      console.log('rendered Options',   options);
      let tmpOptions = options;
      tmpOptions.yaxis = {
          labels: {
              formatter: (value) => {
                  if (typeof value !== 'undefined') {
                  let USDollar = new Intl.NumberFormat('en-US', {
                      style: 'currency',
                      currency: 'USD',
                  });
                      return USDollar.format(value);
                  } else {
                      return null;
                  }
              }
          }
      };
      this.chart = new ApexCharts(document.querySelector('#{{ $chartId }}'), tmpOptions)
    @else
      this.chart = new ApexCharts(document.querySelector('#{{ $chartId }}'), options)
    @endif
  3. If you used any filters on the widget, you can listen the emit event like the following.
    $wire.on('updateOptions', async ({ options }) => {
         @if($chartId === 'XXXXX')
                  console.log('updateOptions', JSON.parse(options));
                  let tmpOptions = JSON.parse(options);
                  tmpOptions.yaxis = {
                      labels: {
                          formatter: (value) => {
                              if (typeof value !== 'undefined') {
                              let USDollar = new Intl.NumberFormat('en-US', {
                                  style: 'currency',
                                  currency: 'USD',
                              });
                                  return USDollar.format(value);
                              } else {
                                  return null;
                              }
                          }
                      }
                  };
                  this.chart.updateOptions(tmpOptions, true, true, true);
          @else
                  this.chart.updateOptions(options, false, true, true);
          @endif
    });

    I hope someone need this!

KostasKostogloy commented 9 months ago

My fix for latest version goes like this.

  1. Publish the package's views: php artisan vendor:publish --tag="filament-apex-charts-views"
  2. Edit chart.blade.php
  3. Change init():

    init() {
    this.$wire.$on('updateOptions', ({ options }) => {
        if (options.dataLabels?.formatter) {
            options.dataLabels.formatter = eval(options.dataLabels.formatter)
        }
    
        if (options.yaxis?.labels?.formatter) {
            options.yaxis.labels.formatter = eval(options.yaxis.labels.formatter)
        }
    
        if (options.xaxis?.labels?.formatter) {
            options.xaxis.labels.formatter = eval(options.xaxis.labels.formatter)
        }
        this.chart.updateOptions(options, false, true, true);
    });
    
    this.options.theme = { mode: this.theme };
    this.options.chart.background = 'inherit';
    if (this.options.dataLabels?.formatter) {
        this.options.dataLabels.formatter = eval(this.options.dataLabels.formatter)
    }
    
    if (this.options.yaxis?.labels?.formatter) {
        this.options.yaxis.labels.formatter = eval(this.options.yaxis.labels.formatter)
    }
    
    if (this.options.xaxis?.labels?.formatter) {
        this.options.xaxis.labels.formatter = eval(this.options.xaxis.labels.formatter)
    }
    
    this.chart = new ApexCharts($refs.{{ $chartId }}, this.options);
    this.chart.render();
    }
flolanger commented 8 months ago

Since the latest version, the fix from @KostasKostogloy doesn't work anymore, because the init() is gone now from the views...

Any updates, when the formatter will be supported or what workaround is suggested now?

aldesrahim commented 8 months ago

Since the latest version, the fix from @KostasKostogloy doesn't work anymore, because the init() is gone now from the views...

Any updates, when the formatter will be supported or what workaround is suggested now?

I've similar issue, just publish all blade files using the old ones (before last update), and manually load apexchart asset inside AppServiceProvider using this command

FilamentAsset::register([
    Js::make('apexcharts', __DIR__.'/../../resources/js/apexcharts.min.js'),
], package: 'leandrocfe/filament-apex-charts');

blade files that i've published (using the old ones) image

And with the old blade files, you can try the old workaround for Datalabel formatter by @KostasKostogloy

glennjacobs commented 7 months ago

I've submitted a PR for review which adds this functionality. See #55

If you want to use it now, you can simply put the view in resources/views/vendor/filament-apex-charts/widgets/components/chart.blade.php.

flolanger commented 7 months ago

I've submitted a PR for review which adds this functionality. See #55

If you want to use it now, you can simply put the view in resources/views/vendor/filament-apex-charts/widgets/components/chart.blade.php.

Thank you so much! ❤️

glennjacobs commented 7 months ago

My PR was incorrect. I've taken a different approach, which leaves the view intact and instead updates the distributed JS.

To use before being merged you can copy the built JS file to your public/js/app/components/apexcharts.js.

leandrocfe commented 7 months ago

Hey,

@RosiersRobin, @flolanger, @VictorCano, @webtamizhan, @aldesrahim

Could you try the new version please? https://github.com/leandrocfe/filament-apex-charts/tree/3.1.0

Formatter is available here https://github.com/leandrocfe/filament-apex-charts?tab=readme-ov-file#extra-options-and-formatters