apexcharts / apexcharts.js

📊 Interactive JavaScript Charts built on SVG
https://apexcharts.com
MIT License
14.41k stars 1.31k forks source link

Selection event produce error -> Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null #1790

Closed pacocom closed 3 years ago

pacocom commented 4 years ago

Bug report

Selection event produce error -> When mouseover a line or marker --> Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null

"apexcharts": "3.19.3",
"gatsby": "2.23.3",
"react": "16.13.1",
"react-apexcharts": "1.3.7",
"react-loadable": "5.5.0",
const ReactApexChart = Loadable({
  loader: () => import('react-apexcharts'),
});
ReactApexChart.preload();
  const now = Date.now();
  const chartGroup = `latency-group-${now}`;
  const targetChartId = `latency-chart-${now}`;
  const brushChartId = `navigator-chart-${now}`;

  // data is { x: number, y: number|null }[]; // x is Date in milliseconds
  const series: ApexAxisChartSeries = [
    {
      name,
      type: 'line',
      data: data,
    },
  ];

  const day = 24 * 60 * 60 * 1000;
  const defaultBrushSelection = {
    min: new Date(data[data.length - 1].date).getTime() - day,
    max: new Date(data[data.length - 1].date).getTime(),
  };

  const targetChartOptions: ApexCharts.ApexOptions = {
    chart: {
      id: targetChartId,
      group: chartGroup,
      type: 'line',
      animations: {
        enabled: false,
        animateGradually: {
          enabled: false,
        },
        dynamicAnimation: {
          enabled: false,
        },
      },
    },
    colors: [color],
    stroke: {
      width: 1,
      curve: 'smooth',
    },
    dataLabels: {
      enabled: false,
    },
    fill: {
      opacity: 1,
      type: 'solid',
    },
    markers: {
      size: 0,
      colors: [color],
      strokeColors: [color],
      strokeWidth: 0,
      hover: {
        size: 4,
      },
    },
    xaxis: {
      type: 'datetime',
    },
    yaxis: {
      floating: false,
      opposite: true,
      showForNullSeries: false,
      forceNiceScale: true,
      tickAmount: 5,
      labels: {
        minWidth: 50,
        maxWidth: 200,
        formatter: function (val: number, options: any) {
          if (val > 0 && val < 1000) {
            return `${val} ms`;
          }

          return `${val / 1000} s`;
        },
      },
    },
    tooltip: {
      marker: {
        show: false,
      },
      x: {
        show: false,
        format: 'dddd, MMM dd, HH:mm',
      },
      y: {
        title: {
          formatter: (seriesName: string) => '',
        },
        formatter: (val: number, options: any) => {
          let suffix = 's';

          if (val > 0 && val < 1000) {
            suffix = 'ms';
          }

          return `<span style="color: #008FFB;"> ● </span><b><span>${val} ${suffix}</span></b>`;
        },
      },
    },
  };

  const brushChartOptions: ApexCharts.ApexOptions = {
    chart: {
      id: brushChartId,
      group: chartGroup,
      type: 'line',
      animations: {
        enabled: false,
        animateGradually: {
          enabled: false,
        },
        dynamicAnimation: {
          enabled: false,
        },
      },
      events: {
        // selection event produce error -> When mouseover on a line or marker
        // --> Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null
        selection: function (chartContext: any, { xaxis, yaxis }: any) {
          console.log(chartContext, xaxis, yaxis);
        },
      },
      brush: {
        target: targetChartId,
        enabled: true,
        autoScaleYaxis: true,
      },
      selection: {
        enabled: true,
        type: 'x',
        xaxis: defaultBrushSelection,
      },
    },
    colors: [color],
    stroke: {
      width: 1,
      curve: 'smooth',
    },
    dataLabels: {
      enabled: false,
    },
    fill: {
      opacity: 1,
      type: 'solid',
    },
    xaxis: {
      type: 'datetime',
      tooltip: {
        enabled: false,
      },
    },
    yaxis: {
      // show: false; yaxis opposite doesn't work
      // Using labels.formatter to remove yaxis label (or .apexcharts-yaxis { display: none; })
      show: true,
      opposite: true,
      tickAmount: 0,
      showForNullSeries: false,
      forceNiceScale: true,
      labels: {
        minWidth: 50,
        maxWidth: 200,
        formatter: function (val: number, options: any) {
          return '';
        },
      },
    },
  };

<>
      <div className="metric-latency__chart">
        <ReactApexChart
          options={targetChartOptions}
          series={series}
          type="line"
          height="100%"
          width="100%"
        />
      </div>

      <div className="metric-navigator__chart">
        <ReactApexChart
          options={brushChartOptions}
          series={series}
          type="line"
          height="100%"
          width="100%"
        />
      </div>
    </>

Codepen

Modify this codepen to demonstrate the problem clearly, just fork it and paste the resulting codepen in your issue. Please make sure this is a minimal example, containing only the minimum necessary code to help us troubleshoot your problem. Issues/bug reports without reproducible example will be given least priority, so make sure you include one.

If you are using vue-apexcharts, and want to create a demo in Vue environment, use CodeSandbox Vue template If you are using react-apexcharts, and want to create a demo in React environment, use CodeSandbox React template

Explanation

CleAurora commented 4 years ago

+1

CleAurora commented 4 years ago

Did you find some solution for it @pacocom ?

nakedfool commented 4 years ago

+1

matheusgrieger commented 3 years ago

This is happening with synchronized charts, when one of them has the tooltip disabled. If you enable the tooltip (at least, in our case), the error goes away. But this error doesn't break the app, or the charts themselves in any way, it's just annoying to have this error popping up in the console while developing.

github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

RIckyBan commented 2 years ago

FYI

Hi, I'm using apexcharts on Next.js, and got this error with dataPointSelection event of timeline chart. I found a workaround.

In my case, this error seems to occur when I use setState in the dataPointSelection event callback. So I use setTimeout to change the execution timing, and the error disappears.

example

      events: {
        dataPointSelection: (event, chartContext, config) => {
          const data = chartSeries[0].data[config.dataPointIndex];
          setTimeout(() => {
            setItemId(data.id);
          }, 10);
        },
      },

Hope this helps.

Invictus-Munish commented 2 years ago

FYI

Hi, I'm using apexcharts on Next.js, and got this error with dataPointSelection event of timeline chart. I found a workaround.

In my case, this error seems to occur when I use setState in the dataPointSelection event callback. So I use setTimeout to change the execution timing, and the error disappears.

example

      events: {
        dataPointSelection: (event, chartContext, config) => {
          const data = chartSeries[0].data[config.dataPointIndex];
          setTimeout(() => {
            setItemId(data.id);
          }, 10);
        },
      },

Hope this helps.

Thanks that helped me.

kcvdk3101 commented 2 years ago

FYI

Hi, I'm using apexcharts on Next.js, and got this error with dataPointSelection event of timeline chart. I found a workaround.

In my case, this error seems to occur when I use setState in the dataPointSelection event callback. So I use setTimeout to change the execution timing, and the error disappears.

example

      events: {
        dataPointSelection: (event, chartContext, config) => {
          const data = chartSeries[0].data[config.dataPointIndex];
          setTimeout(() => {
            setItemId(data.id);
          }, 10);
        },
      },

Hope this helps.

This workaround just helped me handle certain data. But in case bunches of data, it won't.

hadarose commented 2 years ago

Hi, same issue here. I'm using: "react": "^17.0.2", "react-apexcharts": "^1.4.0", "apexcharts": "^3.33.2" and selection event produces error -> When mouseover a line or marker --> TypeError: null is not an object (evaluating 'a.gridRect.getBoundingClientRect')

It happens only on Safari, Version 16.1. Was this issue solved somehow?

Thanks!

abdulrahimiliasu commented 1 year ago

Hi, same issue here. I'm using: "react": "^17.0.2", "react-apexcharts": "^1.4.0", "apexcharts": "^3.33.2" and selection event produces error -> When mouseover a line or marker --> TypeError: null is not an object (evaluating 'a.gridRect.getBoundingClientRect')

It happens only on Safari, Version 16.1. Was this issue solved somehow?

Thanks!

Same here any help ?

hadarose commented 1 year ago

Hi, after deep investigation I found out that it was breaking because of an outside monitoring app -> either Sentry or Fullstory. When uninstalled -> the crash never happened again.

t3warchest commented 4 months ago

Hi, after deep investigation I found out that it was breaking because of an outside monitoring app -> either Sentry or Fullstory. When uninstalled -> the crash never happened again.

Hi, new to coding, i also tried doing a deep investigation but failed miserably. I get the error a.getRect.getBoundingClient but i dont have sentry or fullstory open/running/installed?/monitoring how do i figure this out. thanks!

Nikkitory commented 3 months ago

More information...this bug is consistently reproduceable in Safari 17.5 if you have a line or bar chart with an x axis of type 'datetime' and you move the mouse back and forth over the chart while it is loading. The bug does not appear in Chrome or Firefox. I think this bug might be fixable by adding a null check as commented in the apexcharts js code below:

if (("mousemove" === e.type && 1 === e.which || "touchmove" === e.type) && (a.dragged = !0, i.globals.panEnabled ? (i.globals.selection = null, a.w.globals.mousedown && a.panDragging({
              context: a,
              zoomtype: r,
              xyRatios: t
            })) : (a.w.globals.mousedown && i.globals.zoomEnabled || a.w.globals.mousedown && i.globals.selectionEnabled) && (a.selection = a.selectionDrawing({
              context: a,
              zoomtype: r
            }))), "mouseup" === e.type || "touchend" === e.type || "mouseleave" === e.type) {
              // COULD RETURN EARLY HERE IF a.gridRect IS NULL
              var c = a.gridRect.getBoundingClientRect();
              a.w.globals.mousedown && (a.endX = a.clientX - c.left, a.endY = a.clientY - c.top, a.dragX = Math.abs(a.endX - a.startX), a.dragY = Math.abs(a.endY - a.startY), (i.globals.zoomEnabled || i.globals.selectionEnabled) && a.selectionDrawn({
                context: a,
                zoomtype: r
              }), i.globals.panEnabled && i.config.xaxis.convertedCatToNumeric && a.delayedPanScrolled()), i.globals.zoomEnabled && a.hideSelectionRect(this.selectionRect), a.dragged = !1, a.w.globals.mousedown = !1;
            }