apexcharts / react-apexcharts

šŸ“Š React Component for ApexCharts
https://apexcharts.com
MIT License
1.3k stars 152 forks source link

Candlestick Chart | Render issue | On render the chart does not render until I apply selection to volume #593

Open Charlvdm1 opened 5 months ago

Charlvdm1 commented 5 months ago

Candlestick Chart | Render issue | On render the chart does not render until I apply selection to volume

Summary

As mentioned above when my candlestick chart is loaded it is not yet displayed until I make a selection on the volume bar chart it is linked to. So far I presume this has to do with the fact that I am not creating an instance of ApexCharts and then firing the render function. However, that wouldn't be possible (as far as I know) as I am using functional components.

I have created a code sample below which is based off of your demo of the candlestick bar chart combo where this issue also occurs.

The chart is being used inside a NextJS application.

Code Example

// Options separated into its own file for readability
import { ApexOptions } from 'apexcharts';

export const optionsBar: ApexOptions = {
  chart: {
    height: 160,
    type: 'bar',
    brush: {
      enabled: true,
      target: 'candles',
    },
    selection: {
      enabled: true,
      xaxis: {
        min: new Date('20 Jan 2017').getTime(),
        max: new Date('10 Dec 2017').getTime(),
      },
      fill: {
        color: '#ccc',
        opacity: 0.4,
      },
      stroke: {
        color: '#0D47A1',
      },
    },
  },
  dataLabels: {
    enabled: false,
  },
  plotOptions: {
    bar: {
      columnWidth: '80%',
      colors: {
        ranges: [
          {
            from: 0,
            to: 50,
            color: '#FF5C5C',
          },
          {
            from: 51,
            to: 100,
            color: '#34D1A6',
          },
        ],
      },
    },
  },
  stroke: {
    width: 0,
  },
  xaxis: {
    type: 'datetime',
    axisBorder: {
      offsetX: 13,
    },
  },
  yaxis: {
    labels: {
      show: true,
      style: {
        colors: '#9b9eab', // Color for x-axis labels
      },
    },
  },
};

export const optionsCandlestick: ApexOptions = {
  chart: {
    type: 'candlestick',
    height: 290,
    width: 500,
    id: 'candles',
    toolbar: {
      autoSelected: 'pan',
      show: false,
    },
    zoom: {
      enabled: false,
    },
  },
  plotOptions: {
    candlestick: {
      colors: {
        upward: '#34D1A6',
        downward: '#FF5C5C',
      },
    },
  },
  xaxis: {
    type: 'datetime',
    axisTicks: {
      show: false,
    },
    labels: {
      show: false,
    },
    axisBorder: {
      show: false,
    },
    tooltip: {
      enabled: false,
    },
  },
  grid: {
    borderColor: '#303030',
  },
  yaxis: {
    decimalsInFloat: 0,
    labels: {
      style: {
        colors: '#9b9eab',
      },
    },
  },
  tooltip: {
    enabled: true,
    shared: true,
    followCursor: true,
    intersect: false,
    inverseOrder: false,
    theme: 'dark',
    style: {
      fontSize: '14px',
      fontFamily: 'inherit',
    },
    x: {
      show: true,
      format: 'dd MMM yyyy',
    },
    marker: {
      show: true,
    },
    fixed: {
      enabled: false,
    },
  },
};
// I am using NextJS
'use client';
import React, { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import { optionsBar, optionsCandlestick } from './options/options';
import { Box, Flex, Select, Text } from '@chakra-ui/react';
import { BsChevronDown } from 'react-icons/bs';

const ApexChart = dynamic(() => import('react-apexcharts'), { ssr: false });

interface CandlestickData {
  name: string;
  data: { x: number; y: [number, number, number, number] }[];
}

interface VolumeData {
  name: string;
  data: { x: number; y: number }[];
}

const CandleStickChart: React.FC = () => {
  const [ohlcData, setOhlcData] = useState<CandlestickData[]>([]);
  const [volume, setVolume] = useState<VolumeData[]>([]);

// generating some random data for the example
  const generateRandomData = (count: number, minValue: number, maxValue: number): number[] => {
    const data: number[] = [];
    for (let i = 0; i < count; i++) {
      const randomValue = parseFloat((Math.random() * (maxValue - minValue) + minValue).toFixed(2));
      data.push(randomValue);
    }
    return data;
  };

  const generateCandlestickData = (
    count: number
  ): { x: number; y: [number, number, number, number] }[] => {
    const data: { x: number; y: [number, number, number, number] }[] = [];
    const startDate = new Date('2024-01-01').getTime();
    const interval = 24 * 60 * 60 * 1000;

    for (let i = 0; i < count; i++) {
      const timestamp = startDate + i * interval;
      const randomValues = generateRandomData(12, 1, 100);
      data.push({ x: timestamp, y: randomValues });
    }

    return data;
  };

  const generateBarChartData = (count: number): { x: number; y: number }[] => {
    const data: { x: number; y: number }[] = [];
    const startDate = new Date('2024-01-01').getTime(); // Start date for the data
    const interval = 24 * 60 * 60 * 1000; // 1 day interval in milliseconds

    for (let i = 0; i < count; i++) {
      const timestamp = startDate + i * interval;
      const randomValue = Math.floor(Math.random() * 100); // Generate a random value for the bar chart
      data.push({ x: timestamp, y: parseFloat(randomValue.toFixed(2)) }); // Round to 2 decimal places
    }

    return data;
  };

  useEffect(() => {
    const seriesCandlestick = [
      {
        name: 'series-1',
        data: generateCandlestickData(30),
      },
    ];

    const seriesBar = [
      {
        name: 'volume',
        data: generateBarChartData(30),
      },
    ];
    setOhlcData(seriesCandlestick);
    setVolume(seriesBar);
  }, []);

  return (
    <Box bg='tertiaryBackground' w={'xl'} p={4}>
      <Flex justify='space-between' mb={4}>
        <Flex direction='column'>
          <Flex justify='flex-end' align='baseline'>
            <Text fontSize='18px' color='#9b9eab' mr={2}>
              APPL
            </Text>
            <Text fontSize='32px' color='white'>
              119.00
            </Text>
          </Flex>
          <Flex direction='row'>
            <Text color='green' mr={2}>
              +16.87
            </Text>
            <Text color='green'>(8.12%)</Text>
          </Flex>
        </Flex>
        <Flex>
          <Select
            bg='tertiaryBorderGrey'
            py={2}
            borderRadius='md'
            icon={<BsChevronDown />}
            iconColor='white'
            width={112}
            mr={2}
          >
            <option value='1M'>1M</option>
            <option value='3M'>3M</option>
            <option value='1Y'>1Y</option>
            <option value='3Y'>3Y</option>
            <option value='YTD'>YTD</option>
          </Select>
          <Select
            bg='tertiaryBorderGrey'
            py={2}
            icon={<BsChevronDown />}
            iconColor='white'
            width={112}
          >
            <option value='1M'>Settings</option>
            <option value='3M'>3M</option>
            <option value='1Y'>1Y</option>
            <option value='3Y'>3Y</option>
            <option value='YTD'>YTD</option>
          </Select>
        </Flex>
      </Flex>
      <Box id='chart-candlestick'>
        <ApexChart
          options={optionsCandlestick}
          series={ohlcData}
          type='candlestick'
          height={248}
          width={500}
        />
      </Box>
      <Box id='chart-bar'>
        <ApexChart options={optionsBar} series={volume} type='bar' height={100} width={500} />
      </Box>
    </Box>
  );
};

export default CandleStickChart;

On the plus side - the connection between the two charts is alive and well šŸ˜… It re-renders and then draws the chart data when I select some data from the volume bar chart.

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