apexcharts / react-apexcharts

📊 React Component for ApexCharts
https://apexcharts.com
MIT License
1.3k stars 151 forks source link

More elegant way to reset series to avoid memory leaks? #132

Open hkennyv opened 4 years ago

hkennyv commented 4 years ago

Hey there, I was wondering if anyone knows a more graceful way to reset the series prop to avoid memory leaks.

Currently, the realtime example suggests setting all points except the last 10 points (assuming you want a fixed window of 10 points) to 0, however this doesn't prevent the data array from growing to be very large.

  function getNewSeries(baseval, yrange) {
      var newDate = baseval + TICKINTERVAL;
      lastDate = newDate

      for(var i = 0; i< data.length - 10; i++) {
          // IMPORTANT
          // we reset the x and y of the data which is out of drawing area
          // to prevent memory leaks
          data[i].x = newDate - XAXISRANGE - TICKINTERVAL
          data[i].y = 0
      }

      data.push({
          x: newDate,
          y: Math.floor(Math.random() * (yrange.max - yrange.min + 1)) + yrange.min
      })

  }

I added a check to slice the data array when it gets too large in my wrapper component and it works, however it triggers a weird looking re-render that I'd like to avoid if possible. My component is below:

GraphWrapper.js

import React, { Component } from "react";
import Chart from "react-apexcharts";
import ApexCharts from "apexcharts";

class GraphWrapper extends Component {
  constructor(props) {
    super(props);

    this.state = {
      options: {
        chart: {
          id: "realtime",
          animations: {
            enabled: true,
            easing: "linear",
            dynamicAnimation: {
              speed: 1000
            }
          },
          toolbar: {
            show: false
          },
          zoom: {
            enabled: false
          }
        },
        dataLabels: {
          enabled: false
        },
        stroke: {
          curve: "smooth"
        },
        title: {
          text: "dynamic updating chart",
          align: "left"
        },
        markers: {
          size: 0
        },
        xaxis: {
          type: "datetime",
          range: 10
        },
        yaxis: {
          max: 15,
          min: 0
        },
        legend: {
          show: false
        }
      },
      series: [{ data: [] }]
    };
  }

  componentDidMount() {
    this.updateInterval = setInterval(() => this.updateData(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.updateInterval);
  }

  resetData = () => {
    const { data } = this.state.series[0];

    this.setState({
      series: [{ data: data.slice(data.length - 10, data.length) }]
    });
  };

  updateData = () => {
    const x = Math.floor(new Date().getTime() / 1000);
    const y = Math.floor(Math.random() * 10);

    let { data } = this.state.series[0];
    data.push({ x, y });

    this.setState({ series: [{ data }] }, () =>
      ApexCharts.exec("realtime", "updateSeries", this.state.series)
    );

    // stop data array from leaking memory and growing too big
    if (data.length > 100) this.resetData();
  };

  render() {
    const { options, series } = this.state;

    return (
      <div className="mixed-chart">
        <Chart options={options} series={series} type="line" height="350" />
        <button onClick={this.resetData}>RESET</button>
      </div>
    );
  }
}

export default GraphWrapper;
Dreemsuncho commented 3 years ago

I am wondering is there a solution already?

hkennyv commented 3 years ago

@Dreemsuncho i haven't found a good solution to this yet, unfortunately.

i did post my temporary solution here though

Rao-Mudasir commented 1 year ago

facing the same issue @hkennyv did you find any solution

github-actions[bot] commented 1 week 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.