Srinath Baride
Srinath Baride

Reputation: 11

Chartjs is adding values which is not there in data

This is my code

import "chartjs-adapter-moment";
import LoacalLoader from "@components/Loaders/LocalLoader";
import Text from "@components/Text";
import {
  CategoryScale,
  Chart as ChartJS,
  Filler,
  Legend,
  LineElement,
  LinearScale,
  PointElement,
  TimeScale,
  TimeSeriesScale,
  Title,
  Tooltip,
} from "chart.js";
import zoom from "chartjs-plugin-zoom";
import { useRef } from "react";
import { Line } from "react-chartjs-2";
import styles from "./styles.module.scss";
import PropTypes from "prop-types";
import useTranslations from "@hooks/useTranslations";

ChartJS.register(
  CategoryScale,
  LinearScale,
  LineElement,
  PointElement,
  TimeScale,
  TimeSeriesScale,
  Title,
  Tooltip,
  Legend,
  Filler,
  zoom
);

const zoomOptions = {
  pan: {
    enabled: true,
    limits: {
      x: { max: "original", min: "original" },
      y: { max: "original", min: "original" },
    },
    mode: "x",
    modifierKey: "shift",
    speed: 10,
    threshold: 10,
  },
  zoom: {
    drag: {
      enabled: true,
    },
    limits: {
      x: { max: "original", min: "original" },
      y: { max: "original", min: "original" },
    },
    mode: "x",
    pinch: {
      enabled: true,
    },
    sensitivity: 3,
    speed: 0.1,
  },
};

const dateFormat = (value) => {
  if ([0, "0"].includes(value)) {
    return "0";
  }
  const dt = new Date(value);
  const date = dt.getDate();
  const month = dt.getMonth() + 1;
  const year = dt.getFullYear();
  return `${date}/${month}/${year}`;
};

const formatValue = (value) => {
  if (typeof value === "number") {
    return `${value.toLocaleString()}`;
  }
  return value;
};

const createData = (data = [], xLabel = "", yLabel = "", label = "") => {
  const values = [];
  const labels = [];
  data.forEach((item) => {
    labels.push(item[xLabel]);
    values.push(item[yLabel]);
  });
  const datasets = [
    {
      backgroundColor: (context) => {
        const ctx = context.chart.ctx;
        const gradient = ctx.createLinearGradient(0, 0, 0, 240);
        gradient.addColorStop(0.24, "#0156FC");
        gradient.addColorStop(0.994, "rgba(0, 30, 104, 0)");

        return gradient;
      },
      borderColor: "#0156FC",
      data: values,
      fill: true,
      label,
      pointBackgroundColor: "#ffffff",
    },
  ];
  return { datasets, labels };
};

const createConfig = ({ yValueFormatter = formatValue, unit = "day" }) => ({
  elements: {
    line: {
      tension: 0.2,
    },
    point: {
      radius: 0,
    },
    tooltips: {
      intersect: false,
    },
  },
  interaction: {
    axis: "x",
    intersect: false,
    mode: "index",
  },
  maintainAspectRatio: false,
  plugins: {
    legend: {
      display: false,
    },
    tooltip: {
      callbacks: {
        label: (yDatapoint) => {
          return `${yDatapoint.dataset.label}: ${yValueFormatter(
            yDatapoint.raw
          )}`;
        },
        title: (xDatapoint) => {
          return dateFormat(xDatapoint[0].label);
        },
      },
      displayColors: false,
    },
    zoom: zoomOptions,
  },
  responsive: true,

  scales: {
    x: {
      bounds: "ticks",
      grid: {
        display: false,
      },
      ticks: {
        auto: false,
        autoSkip: true,
        maxTicksLimit: 10,
        source: "data",
      },
      time: {
        day: "DD",
        isoWeekday: true,
        month: "MMM",
        round: "day",
        unit,
        unitStepSize: 1000,
        week: "DD MMM",
        year: "YYYY",
      },
      type: "timeseries",
    },
    y: {
      beginAtZero: true,
      grid: {
        display: false,
      },
      ticks: {
        callback: function (val) {
          if (typeof val === "number") {
            if (Number.isInteger(val)) {
              return yValueFormatter(val);
            }
            return;
          }
          return yValueFormatter(val);
        },
        maxTicksLimit: 10,
      },
    },
  },
});

const AreaGraph = ({
  data = [],
  xValueFormatter = formatValue,
  yValueFormatter = formatValue,
  loading = true,
  xLabel = "timestamp",
  yLabel = "value",
  title = "",
  unit = "day",
}) => {
  const { translate } = useTranslations();
  const chartRef = useRef();

  if (loading) {
    return (
      <section className={`${styles.loader}`}>
        <LoacalLoader />
      </section>
    );
  }
  if (!loading && data.length > 0) {
    const values = createData(data, xLabel, yLabel, translate(title));

    const handleResetZoom = () => {
      if (chartRef && chartRef.current) {
        chartRef.current.resetZoom();
      }
    };
    return (
      <section className={styles.chart}>
        <section className={styles["reset-zoom"]}>
          <Text text={"reset_zoom"} onClick={handleResetZoom} />
        </section>
        <Line
          ref={chartRef}
          options={createConfig({
            unit,
            values,
            xValueFormatter,
            yValueFormatter,
          })}
          data={values}
          className={styles.graph}
        />
      </section>
    );
  }
  return <section className={`${styles.chart}`}></section>;
};

AreaGraph.propTypes = {
  data: PropTypes.any,
  loading: PropTypes.any,
  title: PropTypes.any,
  unit: PropTypes.string,
  xLabel: PropTypes.any,
  xValueFormatter: PropTypes.any,
  yLabel: PropTypes.any,
  yValueFormatter: PropTypes.any,
};

export default AreaGraph;

When I send some data and change the unit its showing ticks which are not there in data. The same happening when I zoom in.

I am expecting it should not show any data or ticks which are not there in the source data.

I am sending date in ISOString format. starting from 2023-01-01. Also, some of the dates in the series are missing, But the graph is showing them also, when I zoom in.

Also, I want to restrict how much user can zoom in, like +2 or +3

Also, if possible is there any way to show dates like this. enter image description here

Upvotes: 0

Views: 49

Answers (0)

Related Questions