[Chartjs]-Using zoom/pan with ChartJS

1👍

Ok, in the end I changed back to ChartJS and used the chartjs-plugin-zoom plugin to do the same thing I was doing with ApexChart, I’m placing my code in this answer in case that anyone faces the same problem.
React Bar Component:

import React from "react";
import { Bar, Chart } from "react-chartjs-2";
import ChartDataLabels from "chartjs-plugin-datalabels";
import Zoom from "chartjs-plugin-zoom";

const ChartBar = ({
  data,
  text,
  noLabel,
  stacked,
  newPlugin,
  labelPosition,
  // test,
}) => {
  Chart.register(Zoom);
  return (
    <div
      className="graphics"
      style={{
        display: "flex",
        alignItems: "center",
        flexDirection: "column",
      }}
    >
      {/* <h1>Gráficos</h1> */}
      <div style={{ width: "65%", height: "350px" }}>
        <Bar
          data={data}
          plugins={[
            ChartDataLabels,
            newPlugin ? newPlugin : "",
            // test ? test : "",
          ]}
          options={{
            categoryPercentage: stacked ? 1.0 : 0.9,
            barPercentage: 1.0,
            // layout: {
            //   padding: {
            //   left: 0,
            //   right: 0,
            // top: 60,
            //   bottom: 0,
            //   },
            // },
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
              zoom: {
                // limits: { y: { min: "original", max: "original" } },
                // pan: { enabled: true, mode: "xy", threshold: 10 },
                // zoom: {
                //   wheel: {
                //     enabled: true,
                //     mode: "xy",
                //   },
                // },
                limits: { y: { min: "original", max: "original" } },
                pan: { enabled: true, mode: "x", threshold: 10 },
                zoom: {
                  mode: "x",
                  drag: {
                    enabled: true,
                    backgroundColor: "rgba(225,0,225,0.3)",
                  },
                  wheel: {
                    enabled: true,
                    modifierKey: "alt",
                  },
                },
              },
              tooltip: { enabled: false },
              legend: {
                display: noLabel ? false : true,
                position: labelPosition ? labelPosition : "bottom",
                title: { padding: 40 },
              },
              title: { text: text, display: true, padding: 30 },
            },
            scales: {
              // scaleLabel: { display: true },
              x: {
                stacked: stacked ? true : false,
                // ticks: {
                // display: false,
                // autoSkip: true,
                // maxTicksLimit: 10,
                // beginAtZero: true,
                // },
                // gridLines: {
                //   display: false,
                // },
              },

              y: { stacked: stacked ? true : false, ticks: { display: false } },
              // xAxes: [{ scaleLabel: { display: true } }],
            },
          }}
        />
      </div>
    </div>
  );
};

export default ChartBar;

One data object that is being used with this component(eg. the one in the main question):

{
          customPlugin: {
            id: "customValue",
            afterDraw: (chart, args, opts) => {
              const {
                ctx,
                data: { datasets },
                _metasets,
              } = chart;

              datasets[1].data.forEach((dp, i) => {
                let increasePercent =
                  (dp * 100) / datasets[0].data[i] >= 100
                    ? Math.round(
                        ((dp * 100) / datasets[0].data[i] - 100) * 100
                      ) / 100
                    : (Math.round(
                        (100 - (dp * 100) / datasets[0].data[i]) * 100
                      ) /
                        100) *
                      -1;
                let barValue = `${increasePercent}%`;
                const lineHeight = ctx.measureText("M").width;
                const offset = opts.offset || 0;
                const dash = opts.dash || [];

                ctx.textAlign = "center";

                ctx.fillText(
                  barValue,
                  _metasets[1].data[i].x,
                  _metasets[1].data[i].y - lineHeight * 1.5,
                  _metasets[1].data[i].width
                );

                if (_metasets[0].data[i].y >= _metasets[1].data[i].y) {
                  ctx.beginPath();
                  ctx.setLineDash(dash);

                  ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y);
                  ctx.lineTo(
                    _metasets[0].data[i].x,
                    _metasets[1].data[i].y - offset
                  );
                  ctx.lineTo(
                    _metasets[1].data[i].x,
                    _metasets[1].data[i].y - offset
                  );
                  ctx.stroke();
                } else {
                  ctx.beginPath();
                  ctx.setLineDash(dash);

                  ctx.moveTo(
                    _metasets[0].data[i].x,
                    _metasets[0].data[i].y - offset
                  );
                  ctx.lineTo(
                    _metasets[1].data[i].x,
                    _metasets[0].data[i].y - offset
                  );
                  ctx.lineTo(
                    _metasets[1].data[i].x,
                    _metasets[1].data[i].y - offset - lineHeight * 2
                  );
                  ctx.stroke();
                }
              });
            },
          },
          text: "Evolução da Receita Líquida por Produto",
          type: "bar",
          // labels: values?.estimatedProducts?.map((v, i) => {
          //   return `Rec Líq - Prod ${++i}`;
          // }),
          labels: addNewArrayValue(values?.estimatedProducts, true),
          datasets: [
            {
              type: "bar",
              label: values?.monthsLabels?.mesBaseLabel,
              data: values?.productsValues?.receitaLiquidaBase,
              backgroundColor: ["rgba(42,62,176, 1)"],

              datalabels: {
                font: {
                  size: 10,
                },
                rotation: -90,
                color: "white",
                formatter: (value, context) => {
                  if (value !== 0) {
                    return value
                      ?.toFixed()
                      .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                    // ?.toFixed(0)
                    // .replace(/\d(?=(\d{3})+\.)/g, "$&,");
                  } else {
                    return 0;
                  }
                },
              },
            },
            {
              type: "bar",
              label: values?.monthsLabels?.mesOrcadoLabel,
              data: values?.productsValues?.receitaLiquidaOrcado,
              backgroundColor: "orange",

              datalabels: {
                font: {
                  size: 10,
                },
                rotation: -90,
                color: "black",
                formatter: (value, context) => {
                  if (value !== 0) {
                    return value
                      ?.toFixed()
                      .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                  } else {
                    return 0;
                  }
                },
              },
            },
          ],
        },

Yeah, it’s not the best code, but it’s a starter, I’ve been struggling for 1h30m just because there’s little to no actual examples/doc on this case.

Leave a comment