Search code examples
reactjsreact-hooksreact-domtradingview-apilightweight-charts

React-DOM: Unable to append Trading-view canvas from 'lightweight-charts' to body


Trading-view for react comes with document.body and I want to impend the canvas within the parent div. But it gets append to the end of the body. Tried quite a few possible solutions, but nothing has worked.

ElementsWant to move graph within orange background

The Graph code is as follows:

import { createChart } from "lightweight-charts";  

function Graph() {
      var chart = createChart(document.body, {
        width: 600,
        height: 300,
        crosshair: {
          mode: "normal"
        }
      });

      var candleSeries = chart.addCandlestickSeries();

      var data = [
        { time: "2018-10-19", open: 54.62, high: 55.5, low: 54.52, close: 54.9 },
        { time: "2018-10-22", open: 55.08, high: 55.27, low: 54.61, close: 54.98 },
        { time: "2018-10-23", open: 56.09, high: 57.47, low: 56.09, close: 57.21 },
        { time: "2018-10-24", open: 57.0, high: 58.44, low: 56.41, close: 57.42 },
        { time: "2018-10-25", open: 57.46, high: 57.63, low: 56.17, close: 56.43 },
        { time: "2018-10-26", open: 56.26, high: 56.62, low: 55.19, close: 55.51 },
        { time: "2018-10-29", open: 55.81, high: 57.15, low: 55.72, close: 56.48 },
        { time: "2018-10-30", open: 56.92, high: 58.8, low: 56.92, close: 58.18 },
        { time: "2018-10-31", open: 58.32, high: 58.32, low: 56.76, close: 57.09 },
        { time: "2018-11-01", open: 56.98, high: 57.28, low: 55.55, close: 56.05 },
        { time: "2018-11-02", open: 56.34, high: 57.08, low: 55.92, close: 56.63 },
        { time: "2018-11-05", open: 56.51, high: 57.45, low: 56.51, close: 57.21 },
        { time: "2018-11-06", open: 57.02, high: 57.35, low: 56.65, close: 57.21 },
        { time: "2018-11-07", open: 57.55, high: 57.78, low: 57.03, close: 57.65 },
        { time: "2018-11-08", open: 57.7, high: 58.44, low: 57.66, close: 58.27 },
      ];

      candleSeries.setData(data);

      var lastClose = data[data.length - 1].close;
      var lastIndex = data.length - 1;

      var targetIndex = lastIndex + 105 + Math.round(Math.random() + 30);
      var targetPrice = getRandomPrice();

      var currentIndex = lastIndex + 1;
      var currentBusinessDay = { day: 29, month: 5, year: 2019 };
      var ticksInCurrentBar = 0;
      var currentBar = {
        open: null,
        high: null,
        low: null,
        close: null,
        time: currentBusinessDay
      };

    function mergeTickToBar(price) {
        if (currentBar.open === null) {
          currentBar.open = price;
          currentBar.high = price;
          currentBar.low = price;
          currentBar.close = price;
        } else {
          currentBar.close = price;
          currentBar.high = Math.max(currentBar.high, price);
          currentBar.low = Math.min(currentBar.low, price);
        }
        candleSeries.update(currentBar);
      }

      function reset() {
        candleSeries.setData(data);
        lastClose = data[data.length - 1].close;
        lastIndex = data.length - 1;

        targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
        targetPrice = getRandomPrice();

        currentIndex = lastIndex + 1;
        currentBusinessDay = { day: 29, month: 5, year: 2019 };
        ticksInCurrentBar = 0;
      }

      function getRandomPrice() {
        return 10 + Math.round(Math.random() * 10000) / 100;
      }

      function nextBusinessDay(time) {
        var d = new Date();
        d.setUTCFullYear(time.year);
        d.setUTCMonth(time.month - 1);
        d.setUTCDate(time.day + 1);
        d.setUTCHours(0, 0, 0, 0);
        return {
          year: d.getUTCFullYear(),
          month: d.getUTCMonth() + 1,
          day: d.getUTCDate()
        };
      }

      setInterval(function() {
        var deltaY = targetPrice - lastClose;
        var deltaX = targetIndex - lastIndex;
        var angle = deltaY / deltaX;
        var basePrice = lastClose + (currentIndex - lastIndex) * angle;
        var noise = 0.1 - Math.random() * 0.2 + 1.0;
        var noisedPrice = basePrice * noise;
        mergeTickToBar(noisedPrice);
        if (++ticksInCurrentBar === 5) {
          // move to next bar
          currentIndex++;
          currentBusinessDay = nextBusinessDay(currentBusinessDay);
          currentBar = {
            open: null,
            high: null,
            low: null,
            close: null,
            time: currentBusinessDay
          };
          ticksInCurrentBar = 0;
          if (currentIndex === 5000) {
            reset();
            return;
          }
          if (currentIndex === targetIndex) {
            // change trend
            lastClose = noisedPrice;
            lastIndex = currentIndex;
            targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
            targetPrice = getRandomPrice();
          }
        }
      }, 200);
      return null;
    }

    export default Graph;

The parent component:

import React from "react";
import Graph from "./Graph";

function App() {
  return (
    <div
      style={{
        flex: 1,
        flexDirection: "column",
        background: "orange",
        justifyContent: "center",
        alignItems: "center"
      }}
    >
      <Graph />
      <h1>It is to append graph into body</h1>
    </div>
  );
}

export default App;

I have tried refs, different DOM manipulation methods, but nothing has worked. It would be great if someone can help me get to the solution.


Solution

  • I was using useRef with wrong logic and got it working with these changes, for someone who might run into same kind of problem:

    import { createChart } from "lightweight-charts";
    import React from 'react';
    
    const  Graph = () => {
      const chartRef = React.useRef(null);
    
      React.useEffect(()=> {
        if(chartRef.current){
          const chart = createChart(chartRef.current, {
            width: 600,
            height: 300,
            crosshair: {
              mode: "normal"
            }
          });
    
          prepareChart(chart);
        }
      }, [])
    
      function prepareChart(chart) {
    
      var candleSeries = chart.addCandlestickSeries();
    
      var data = [
        { time: "2018-10-19", open: 54.62, high: 55.5, low: 54.52, close: 54.9 },
        { time: "2018-10-22", open: 55.08, high: 55.27, low: 54.61, close: 54.98 },
        { time: "2018-10-23", open: 56.09, high: 57.47, low: 56.09, close: 57.21 },
        { time: "2018-10-24", open: 57.0, high: 58.44, low: 56.41, close: 57.42 },
        { time: "2018-10-25", open: 57.46, high: 57.63, low: 56.17, close: 56.43 },
      ];
    
      candleSeries.setData(data);
    
      var lastClose = data[data.length - 1].close;
      var lastIndex = data.length - 1;
    
      var targetIndex = lastIndex + 105 + Math.round(Math.random() + 30);
      var targetPrice = getRandomPrice();
    
      var currentIndex = lastIndex + 1;
      var currentBusinessDay = { day: 29, month: 5, year: 2019 };
      var ticksInCurrentBar = 0;
      var currentBar = {
        open: null,
        high: null,
        low: null,
        close: null,
        time: currentBusinessDay
      };
    
      function mergeTickToBar(price) {
        if (currentBar.open === null) {
          currentBar.open = price;
          currentBar.high = price;
          currentBar.low = price;
          currentBar.close = price;
        } else {
          currentBar.close = price;
          currentBar.high = Math.max(currentBar.high, price);
          currentBar.low = Math.min(currentBar.low, price);
        }
        candleSeries.update(currentBar);
      }
    
      function reset() {
        candleSeries.setData(data);
        lastClose = data[data.length - 1].close;
        lastIndex = data.length - 1;
    
        targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
        targetPrice = getRandomPrice();
    
        currentIndex = lastIndex + 1;
        currentBusinessDay = { day: 29, month: 5, year: 2019 };
        ticksInCurrentBar = 0;
      }
    
      function getRandomPrice() {
        return 10 + Math.round(Math.random() * 10000) / 100;
      }
    
      function nextBusinessDay(time) {
        var d = new Date();
        d.setUTCFullYear(time.year);
        d.setUTCMonth(time.month - 1);
        d.setUTCDate(time.day + 1);
        d.setUTCHours(0, 0, 0, 0);
        return {
          year: d.getUTCFullYear(),
          month: d.getUTCMonth() + 1,
          day: d.getUTCDate()
        };
      }
    
      setInterval(function() {
        var deltaY = targetPrice - lastClose;
        var deltaX = targetIndex - lastIndex;
        var angle = deltaY / deltaX;
        var basePrice = lastClose + (currentIndex - lastIndex) * angle;
        var noise = 0.1 - Math.random() * 0.2 + 1.0;
        var noisedPrice = basePrice * noise;
        mergeTickToBar(noisedPrice);
        if (++ticksInCurrentBar === 5) {
          // move to next bar
          currentIndex++;
          currentBusinessDay = nextBusinessDay(currentBusinessDay);
          currentBar = {
            open: null,
            high: null,
            low: null,
            close: null,
            time: currentBusinessDay
          };
          ticksInCurrentBar = 0;
          if (currentIndex === 5000) {
            reset();
            return;
          }
          if (currentIndex === targetIndex) {
            // change trend
            lastClose = noisedPrice;
            lastIndex = currentIndex;
            targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
            targetPrice = getRandomPrice();
          }
        }
      }, 200);
    
    }
      return <div ref={chartRef} />;
    }
    
    export default Graph;