3

I would like to resize the columns width when the user zoom on my chart. Could you suggest any method or option? I searched through the documentation but I didn't find any solution. Until now I tried by changing the bar width percentage, the responsive option and the stroke width. The stroke has the side effect of overlapping the bars but I need them separate

Before Zoom

Before Zoom

After Zoom actual behaviour

enter image description here

After Zoom desired behaviour

enter image description here

Code used until now

<!DOCTYPE html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Bar with Custom DataLabels</title>

    <link href="../../assets/styles.css" rel="stylesheet" />

    <style>
      #chart {
        max-width: 650px;
        margin: 35px auto;
      }
    </style>

    <script>
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"><\/script>'
        );
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill@1.2.20171210/classList.min.js"><\/script>'
        );
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
        );
    </script>

    <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

    <script>
      // Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
      // Based on https://gist.github.com/blixt/f17b47c62508be59987b
      var _seed = 42;
      Math.random = function () {
        _seed = (_seed * 16807) % 2147483647;
        return (_seed - 1) / 2147483646;
      };
    </script>
  </head>

  <body>
    <div id="chart"></div>

    <script>
      var options = {
        series: [
          {
            name: 'Net Profit',
            data: [
              95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
              5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
              75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
              48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
              11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
              34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
            ],
          },
          {
            name: 'Revenue',
            data: [
              97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
              40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
              29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
              22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
              25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
              36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
              35, 11,
            ],
          },
          {
            name: 'Free Cash Flow',
            data: [
              20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
              12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
              48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
              25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
              93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
              28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
            ],
          },
        ],
        annotations: {
          points: [
            {
              x: 'Bananas',
              seriesIndex: 0,
              label: {
                borderColor: '#775DD0',
                offsetY: 0,
                style: {
                  color: '#fff',
                  background: '#775DD0',
                },
                text: 'Bananas are good',
              },
            },
          ],
        },
        chart: {
          height: 350,
          type: 'bar',
        },
        plotOptions: {
          bar: {
            columnWidth: '100%',
          },
        },
        dataLabels: {
          enabled: false,
        },
        stroke: {
          width: 2,
        },

        grid: {
          row: {
            colors: ['#fff', '#f2f2f2'],
          },
        },
        xaxis: {
          labels: {
            rotate: -45,
          },
          categories: [
            31, 48, 33, 88, 5, 91, 76,
          ],
          tickPlacement: 'on',
        },
        yaxis: {
          title: {
            text: 'Servings',
          },
        },
        fill: {
          type: 'gradient',
          gradient: {
            shade: 'light',
            type: 'horizontal',
            shadeIntensity: 0.25,
            gradientToColors: undefined,
            inverseColors: true,
            opacityFrom: 0.85,
            opacityTo: 0.85,
            stops: [50, 0, 100],
          },
        }
      };

      var chart = new ApexCharts(document.querySelector('#chart'), options);
      chart.render();
    </script>
  </body>

1 Answers1

1

this is not a complete answer but wanted to share my findings.
IMO the functionality the OP requests should be the default behavior.

regardless, I found that by using the zoomed event, we can find the x-axis range of the zoom.
then remove the data points from the series that are outside of that range and re-draw the chart.
which results in exactly the desired behavior.
however, this kills the ability to zoom out to original series.

to make this work, I think you would need to implement custom zoom buttons,
to allow keeping track of which action occurred, zoom in or out.
this would allow you to know which data points to include when the chart is re-drawn.
you can use the zoomX method to manually set the zoom level.

see following working snippet for zoom-in only functionality.

<!DOCTYPE html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Bar with Custom DataLabels</title>

    <link href="../../assets/styles.css" rel="stylesheet" />

    <style>
      #chart {
        max-width: 650px;
        margin: 35px auto;
      }
    </style>

    <script>
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"><\/script>'
        );
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill@1.2.20171210/classList.min.js"><\/script>'
        );
      window.Promise ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
        );
    </script>

    <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

    <script>
      // Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
      // Based on https://gist.github.com/blixt/f17b47c62508be59987b
      var _seed = 42;
      Math.random = function () {
        _seed = (_seed * 16807) % 2147483647;
        return (_seed - 1) / 2147483646;
      };
    </script>
  </head>

  <body>
    <div id="chart"></div>

    <script>
      var data = [
        {
          name: 'Net Profit',
          data: [
            95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
            5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
            75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
            48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
            11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
            34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
          ],
        },
        {
          name: 'Revenue',
          data: [
            97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
            40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
            29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
            22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
            25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
            36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
            35, 11,
          ],
        },
        {
          name: 'Free Cash Flow',
          data: [
            20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
            12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
            48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
            25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
            93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
            28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
          ],
        },
      ];
      var options = {
        series: data,
        annotations: {
          points: [
            {
              x: 'Bananas',
              seriesIndex: 0,
              label: {
                borderColor: '#775DD0',
                offsetY: 0,
                style: {
                  color: '#fff',
                  background: '#775DD0',
                },
                text: 'Bananas are good',
              },
            },
          ],
        },
        chart: {
          height: 350,
          id: 'thisChart',
          type: 'bar',
          events: {
            zoomed: function(chartContext, {xaxis, yaxis}) {
              console.log('zoom', xaxis);
              
              var newSeries = data.map(function (series) {
                var newData = [];
                series.data.forEach(function (row, index) {
                  if ((index >= xaxis.min) && (index <= xaxis.max)) {
                    newData.push(row);
                  }
                });
                return {
                  name: series.name,
                  data: newData
                };
              });
              ApexCharts.exec('thisChart', 'updateSeries', newSeries, true);              
            }
          }
        },
        plotOptions: {
          bar: {
            columnWidth: '100%',
          },
        },
        dataLabels: {
          enabled: false,
        },
        stroke: {
          width: 2,
        },

        grid: {
          row: {
            colors: ['#fff', '#f2f2f2'],
          },
        },
        xaxis: {
          labels: {
            rotate: -45,
          },
          categories: [
            31, 48, 33, 88, 5, 91, 76,
          ],
          tickPlacement: 'on',
        },
        yaxis: {
          title: {
            text: 'Servings',
          },
        },
        fill: {
          type: 'gradient',
          gradient: {
            shade: 'light',
            type: 'horizontal',
            shadeIntensity: 0.25,
            gradientToColors: undefined,
            inverseColors: true,
            opacityFrom: 0.85,
            opacityTo: 0.85,
            stops: [50, 0, 100],
          },
        }
      };

      var chart = new ApexCharts(document.querySelector('#chart'), options);
      chart.render();
    </script>
  </body>
WhiteHat
  • 59,912
  • 7
  • 51
  • 133
  • Thank you for the answer, actually I need to preserve the ability for the user to zoom in and out, maybe following your suggestion by re-rendering the chart each time the zoom event is triggered I can obtain this behaviour, but then I'm worried about the performances. Probably it's better to visualize the bar chart only when data points are not too many – Davide Bulbarelli Nov 04 '21 at 14:00