Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create a space on leftOffset and rightOffset in fixes pixels #1622

Closed
Harishreddylv opened this issue Jun 24, 2024 · 5 comments
Closed

Comments

@Harishreddylv
Copy link

Lightweight Charts™ Version: 4.1.3

Steps/code to reproduce: I would like to leave some padding left side and right side of the chart (inside the axes). So that we found rightOffset from documentation, if we follow the same it adjusts the space in terms of "The margin space in bars" instead of fixed space like 10px on both sides. Below is my code snippet

chart.timeScale().applyOptions({                
                    fixRightEdge: false,
                    rightOffset: 1
                });

Actual behavior:

Actually We have time Interval selection based on that chart datapoints will be varry. Based on chart points barspacing and width of bar is adjusting(as per doc we are understanding). based on that bars, rightOffset spacing is adjusting. So the space is chaging whenever we are changing time interval.

Expected behavior:

We need fixed leftOffSet and rightOffset in terms of px not bars size.

Screenshots:
Below image is for 15 min
image

Below image is for 30 min
image

Below image is for 5 min
image

Below image is for 1 min
image

Expectation should be same fixed space on both ends. Its show stopper for our client

Thanks in advance!!!

@SlicedSilver
Copy link
Contributor

You can't directly set the rightOffset in pixels because the library uses the number of bars for this property. However, you can achieve the desired result by using the barSpacing to convert between pixels and the number of bars.

Here’s how you can do it:

Conversion with barSpacing

  1. Get Current barSpacing: This value indicates the width, in pixels, that each bar takes. You can get this value directly using the chart's time scale options.

    // Get the current bar spacing
    const barSpacing = chart.timeScale().options().barSpacing;
  2. Calculate rightOffset: Use the barSpacing to convert the desired pixel offset into the number of bars.

    const offsetInPixels = 50;
    const rightOffset = offsetInPixels / barSpacing;
    
    // Apply the right offset
    chart.timeScale().applyOptions({ rightOffset: rightOffset });

Adjusting with Dynamic Spacing

Since chart.timeScale().options().barSpacing always gives you the latest bar spacing, you don't need to manually calculate it even if you adjust the zoom level by scrolling.

Example Usage

Whenever you need to set the rightOffset in pixels, simply get the current bar spacing and perform the conversion.

  1. Initial Setup: Set the right offset initially.

    const chart = LightweightCharts.createChart(document.body, { width: 600, height: 300 });
    const lineSeries = chart.addLineSeries();
    lineSeries.setData([
        { time: '2019-04-11', value: 80.01 },
        { time: '2019-04-12', value: 96.63 },
        // more data...
    ]);
    
    function setRightOffsetInPixels(chart, pixels) {
       const barSpacing = chart.timeScale().options().barSpacing;
       const rightOffset = pixels / barSpacing;
    
       chart.timeScale().applyOptions({ rightOffset: rightOffset });
    }
    
    // Initial set
    setRightOffsetInPixels(chart, 50);
  2. Update on Resize: Adjust the right offset when the window resizes.

    window.addEventListener('resize', () => {
        setRightOffsetInPixels(chart, 50);
    });
  3. Handle Data Interval Change: Reset the right offset when changing the interval (resolution) of data using setData.

    function changeDataResolution(series, newData) {
        series.setData(newData);
        // Restore the right offset in pixels
        setRightOffsetInPixels(chart, 50);
    }
    
    // Example usage when changing data resolution
    const newData = [ 
        { time: '2019-05-11', value: 85.01 },
        { time: '2019-05-12', value: 92.63 },
        // more new data...
    ];
    changeDataResolution(lineSeries, newData);

Summary

By utilizing the barSpacing from chart.timeScale().options().barSpacing, you can easily convert a desired pixel offset into the corresponding rightOffset in terms of bars. This ensures that your chart maintains a consistent margin regardless of zoom level, chart resizing, or data resolution changes.

@Harishreddylv
Copy link
Author

@SlicedSilver - I have followed the above solution, Its working when am not using chart.timeScale().fitContent();

Expectation:
It should be fitToContent along with some fixed space on right and left edges.

Actual Behaviour
When am applying above code which you provided without fitToContent fixed white space is coming during chnages on interval also.
But when we add fitToContent and above code, the fitTocontent is working but fixed white space is not working

Below is my code

function setRightOffsetInPixels(chart: any) {
        const barSpacing = chart.timeScale().options().barSpacing;
        const rightOffset = 40 / barSpacing;
        
        chart.timeScale().applyOptions({ 
            fixRightEdge: false,
            rightOffset: rightOffset });        
    }
    
    useEffect(() => {
        containers.forEach((contId: string, index: number) => {
            const container = document.getElementById(contId) as HTMLElement;

            if (container) {
                const chart = createChart(container, chartOptions());
                chartsRef.current[ contId ] = chart;
                seriesRef.current[ contId ] = [
                ];

                chartDataSetsRef.current[ index ].forEach((series, idx: number) => {
                    series.containerId = contId;
                    if (series.type === LIVE_OPTIONS_SERIES_TYPE.LINE) {
                        setLineSeries(chart, series, contId, idx);
                    } else if (series.type === LIVE_OPTIONS_SERIES_TYPE.AREA) {
                        setAreaSeries(chart, series, contId, idx);
                    } else if (series.type === LIVE_OPTIONS_SERIES_TYPE.BAR) {
                        setBarSeries(chart, series, contId, idx);
                    }
                });

                setRightOffsetInPixels(chart);
                chart.timeScale().fitContent();
                handleDbClickOnTimeScale(chart);
            }
        });

        window.addEventListener("resize", chartResizer);
        toCalculateRange();
        setCharts(chartsRef.current);
        adjustPriceScaleMargins();

        return () => {
            window.removeEventListener("resize", chartResizer);
            resetCache();
        };
    }, [
        containers, chartDataSets
    ]);

@SlicedSilver
Copy link
Contributor

You could try something like this if you need to use it with fitContent:

function setPixelOffsetAfterFitContent(chart, offsetInPixels) {
    // Temporarily set the right offset to zero to ensure fitContent works correctly
    chart.timeScale().applyOptions({ rightOffset: 0 });
    
    // Apply fitContent to fit all data within the chart
    chart.timeScale().fitContent();
    
    // Get the current time scale width
    const timeScaleWidth = chart.timeScale().width();
    
    // The width of the chart that we want the data to be placed within
    const chartPortionWidth = timeScaleWidth - offsetInPixels;
    
    // Get the visible range of bars
    const visibleBarsRange = chart.timeScale().getVisibleLogicalRange();
    
    // Ensure the visibleBarsRange is valid
    if (visibleBarsRange !== null) {
        const numberOfVisibleBars = visibleBarsRange.to - visibleBarsRange.from;

        // Calculate desired bar spacing
        const desiredBarSpacing = chartPortionWidth / numberOfVisibleBars;
        
        // Calculate right offset in bars
        const rightOffsetInBars = offsetInPixels / desiredBarSpacing;
        
        // Apply the determined right offset
        chart.timeScale().applyOptions({ rightOffset: rightOffsetInBars });

        console.log(`
            timeScaleWidth: ${timeScaleWidth}, 
            chartPortionWidth: ${chartPortionWidth}, 
            numberOfVisibleBars: ${numberOfVisibleBars}, 
            desiredBarSpacing: ${desiredBarSpacing}, 
            rightOffsetInBars: ${rightOffsetInBars}
        `);
    } else {
        console.warn("No visible bars range available to calculate offsets.");
    }
}

@Harishreddylv
Copy link
Author

@SlicedSilver - From the above script, we will not met our expectations. the logs are here
timeScaleWidth: 912,
chartPortionWidth: 882,
numberOfVisibleBars: 151,
desiredBarSpacing: 5.841059602649007,
rightOffsetInBars: 5.136054421768708

when changing intervals no of data Points also varry. For example if i select 30 min => 13 points (point to point time range diff is 30 min), 1min => 374 points (diff is 1 min) , 5min => 76 points(diff is 5 mins b/w the points) and so on. TimeRange should be common for all the intervals 09.15 to 15:30 But, observed from the log numberOfVisibleBars always shows as 151.

Hope these information will be useful.

Thanks in advance!

@SlicedSilver
Copy link
Contributor

I don't know all the specifics of your implementation and requirements, however I think there is enough information to figure out a solution to your problem. The provided code samples are just illustrative examples and, as you can see, might require some tweaking on your side to make it work for your use case.

The current behaviour of rightOffset being defined by number of bars is the expected behaviour for the library and we don't have any plans to add a different option for specifying it in pixels since it is possible to implement this behaviour using the existing API.

If you would like to add this functionality then you would welcome a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants