reactjstypescriptnext.jsapexcharts

want to make custom toolbar work using apexcharts


I have added apexcharts in my next app. The chart is working fine. But the problem is I want to add custom toolbar like sidebar with charts. So I added the UI for it. But now I want to make the icons functional. They are actually showing in toolbar in side. the image showing toolbar in left side vertically

this is the code:

interface IState {
  series: Array<{
    data: Array<{
      x: Date,
      y: number[]
    }>
  }>,
  options: {
    chart: {
      type: string,
      toolbar: {
        show: boolean,
      },
    },
    xaxis: {
      type: string,
      show: boolean,
      labels: {
        show: boolean,
        style: {
          colors: string,
        },
      },
      axisBorder: {
        show: boolean,
      },
      axisTicks: {
        show: boolean,
      },
    },
    yaxis: {
      opposite: boolean,
      show: boolean,
      labels: {
        show: boolean,
        style: {
          colors: string,
        },
      },
      axisBorder: {
        show: boolean,
      },
      axisTicks: {
        show: boolean,
      },
    },
    grid: {
      show: boolean,
      borderColor: string,
      strokeDashArray: number,
      xaxis: {
        lines: {
          show: boolean,
          color: string,
        },
      },
      yaxis: {
        axisBorder: {
          show: boolean,
        },
        lines: {
          show: boolean,
        },
      },
    },
    plotOptions: {
      candlestick: {
        colors: {
          upward: string,
          downward: string,
        },
      },
    },
  },
}

const BodyChart: React.FC = () => {
  const chartRef = useRef<ReactApexChart | any>(ReactApexChart);

  const [state] = React.useState<IState>({
    series: [{
                data: [
                // my data
                ]
              }],
    options: {
      chart: {
        type: 'candlestick',
        toolbar: {
          show: false, // Hide the default toolbar
          
        },
        
      },
      xaxis: {
        type: 'datetime',
        show: true,
        labels: {
          show: true,
          style: {
            colors: '#969AA4',
          },
        },
        axisBorder: {
          show: false,
        },
        axisTicks: {
          show: false,
        },
      },
      yaxis: {
        opposite: true,
        show: true,
        labels: {
          show: true,
          style: {
            colors: '#969AA4',
          },
        },
        axisBorder: {
          show: false,
        },
        axisTicks: {
          show: false,
        },
      },
      grid: {
        show: true,
        borderColor: '#202530',
        strokeDashArray: 0,
        xaxis: {
          lines: {
            show: true,
            color: '#FF5733',
          },
        },
        yaxis: {
          axisBorder: {
            show: false,
          },
          lines: {
            show: true,
          },
        },
      },
      plotOptions: {
        candlestick: {
          colors: {
            upward: '#009B84',
            downward: '#FF1230',
          },
        },
      },
    },
  });

  useEffect(() => {
    const chart = chartRef.current.charts;
      document.getElementById('zoom-in')?.addEventListener('click', () => {
        // chart.zoomIn();
      });

      document.getElementById('zoom-out')?.addEventListener('click', () => {
        chart.zoomOut();
      });

      document.getElementById('reset')?.addEventListener('click', () => {
        chart.reset();
      });

  }, []);

  return (
    <div className="container">
      <div className="sidebar">
        <button id="zoom-in"><FontAwesomeIcon icon={faSearchPlus} color='#969AA4' /></button>
        <button id="zoom-out"><FontAwesomeIcon icon={faSearchMinus} color='#969AA4' /></button>
        <button id="reset"><FontAwesomeIcon icon={faUndo} color='#969AA4' /></button>
        <button id="home"><FontAwesomeIcon icon={faHome} color='#969AA4' /></button>
        <button id="menu"><FontAwesomeIcon icon={faBars} color='#969AA4' /></button>
        <button id="download"><FontAwesomeIcon icon={faDownload} color='#969AA4' /></button>
        <button id="selection"><FontAwesomeIcon icon={faMousePointer} color='#969AA4' /></button>
        <button id="zoom"><FontAwesomeIcon icon={faSearch} color='#969AA4' /></button>
        <button id="pan"><FontAwesomeIcon icon={faArrows} color='#969AA4' /></button>
      </div>
      <div className="chart-wrapper">
        <div id="chart">
          <ReactApexChart ref={chartRef} options={state.options} series={state.series} type="candlestick" height={535} />
        </div>
        <div id="html-dist"></div>
      </div>
    </div>
  );
}

note: I have tried using chartRef but it did not worked


Solution

  • The useRef hook might be the issue here. From the docs #caveats,

    When you change the ref.current property, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object.
    

    The chart should be created by defining a unique ID, and later methods can be invoked in useEffect or button events (from react-apexcharts).

    Apex Charts provides zoomX(start, end) method, where start and end can be x-axis value, or timestamp. To reset the zoom resetSeries(updateChart, resetZoom) method can be used.

    For instance to zoom-in the chart by 5-minute window around current time:

      ...
    
    
      const [state] = React.useState<IState>({
        series: [{
                    data: [
                    // my data
                    ]
                  }],
        options: {
          chart: {
            id: 'myChart' // <=== THIS
            type: 'candlestick',
            toolbar: {
              show: false, // Hide the default toolbar
              
            },
            
          },
        ...
    
    
    
        const _getZoomInDuration = () => {
            now = new Date();
            startTimestamp = new Date(new Date(now.getTime() - minutes*60000));
            endTimestamp = new Date(new Date(now.getTime() + minutes*60000));
            return { start:startTimestamp, end:endTimestamp  }
        }
    
    
        useEffect(() => {
        duration = _getZoomInDuration();
        
        const chart = ApexCharts.getChartByID('myChart')  // <== THIS
          document.getElementById('zoom-in')?.addEventListener('click', () => {
            chart.zoomIn(duration.start, duration.end);
          });
    
          document.getElementById('zoom-out')?.addEventListener('click', () => {
            chart.zoomIn(<larger.start>, <larger.end>);
          });
    
          document.getElementById('reset')?.addEventListener('click', () => {
            chart.resetSeries(true, true);
          });
    
        }, []);
    
    
        return (
          ...
          <div className="chart-wrapper">
            <div id="chart">
              <ReactApexChart options={state.options} series={state.series} type="candlestick" height={535} />
            </div>
            <div id="html-dist"></div>
          </div>
        )
    
    

    Also, callbacks can be attached to react to chart events.