1

I have a highcharts chart in place using v11.
There are two series in two panes: candlestick on the upper / column with volumes on the lower pane.

I want to display the full day, so I've been using datetime type for the x series and defined a tick interval with 5 minutes. So far so good, everything is working appropriate except the scrolling behavior:

  • Once I scroll outside of the area where I actually have data and come back in, there is that weird sticky behavior

  • Mouse wheel scrolling is not working

  • Panning is not working (as it's outside of the data area)


Bug Fiddle (https://jsfiddle.net/8g745vxr/0/)

js:

// config
const currentDate = new Date();
const dayStart = new Date(currentDate).setHours(0, 0, 0, 0);
const dayEnd = new Date(currentDate).setHours(23, 59, 59, 999);
const tradingDayStart = new Date(currentDate).setHours(9, 25);
const tradingDayEnd = new Date(currentDate).setHours(16, 5);
const increaseMin = 5;
const xTickInterval = increaseMin * 60 * 1000;

let yVolumeTickInterval = 100;
let minTimeWithValue,
    maxTimeWithValue,
    minPriceValue,
    maxPriceValue,
    maxVolumeValue = null;

// config END

// simulation
console.clear();
const data = createData(
    new Date(currentDate).setHours(9, 30),
    new Date(currentDate).setHours(11, 30));

function createData(startTime, endTime) {
    let time = dayStart;
    let rangeStart = null;
    let rangeEnd = null;

    let price = {
        open: 100,
        high: 120,
        low: 90,
        close: 110
    };

    let volume = 500;
    let result = [[], [], []];
    let upDownSwitch = false;

    let i = 0;
    while (time <= dayEnd) {
        if (time < startTime || time > endTime) {
            // ------------- DATA FOR EACH TIME POINT
            // result[0].push([time, null, null, null, null]);
            // result[1].push([time, null]);
            // ------------- DATA FOR EACH TIME POINT
            time = time + increaseMin * 60 * 1000;
        } else {
            if (i % 5 === 0) {
                upDownSwitch = !upDownSwitch;
            }

            result[0].push([time, price.open, price.high, price.low, price.close]);
            result[1].push([time, volume]);

            time = time + increaseMin * 60 * 1000;
            volume = upDownSwitch ? volume + 100 : volume - 100;

            price.open = price.close;
            price.high = upDownSwitch ? price.close + 20 : price.close + 10;
            price.low = upDownSwitch ? price.open - 10 : price.close - 20;
            price.close = upDownSwitch ? price.close + 10 : price.close - 10;

            if (rangeStart == null) { rangeStart = result[0].length - 1; }
            i++;
        }
    }

    if (rangeEnd == null) { rangeEnd = rangeStart + i - 1; }

    return result;
}
// simulation END


// data preparation
if (data) {
    if (data[0]) {
        minTimeWithValue = Math.min(...data[0].filter(x => x[1]).map(x => x[0]));
        maxTimeWithValue = Math.max(...data[0].filter(x => x[1]).map(x => x[0]));

        minPriceValue = Math.min(...data[0].filter(x => x[1]).map(x => Math.min(...[x[1], x[2], x[3], x[4]])));
        maxPriceValue = Math.max(...data[0].filter(x => x[1]).map(x => Math.max(...[x[1], x[2], x[3], x[4]])));
    }

    if (data[1]) {
        maxVolumeValue = Math.max(...data[1].filter(x => x[1]).map(x => x[1]));

        if (maxVolumeValue > 1000000) { yVolumeTickInterval = 100000; }
        else if (maxVolumeValue > 1000) { yVolumeTickInterval = 1000; }
    }
}
// data preparation END


var chart = Highcharts.stockChart('container', {
    chart: {
        height: null,
        marginRight: 50,
        panning: { type: 'xy' },
        events: {
            load: function () {
                console.log('loaded');
                this.xAxis[0].setExtremes(tradingDayStart, tradingDayEnd);
            }
        }
    },

    xAxis: {
        type: 'datetime',
        tickInterval: xTickInterval,
        minRange: xTickInterval * 5,
        min: dayStart,
        max: dayEnd,
        labels: { format: '{value:%H:%M}' }
    },

    yAxis: [
        {
            height: '80%',
            gridLineWidth: 0.5,
            min: minPriceValue * 0.9,
            max: maxPriceValue * 1.1,
            showLastLabel: true,
            labels: {
                x: 0,
                y: 4,
                align: 'left',
                format: '{value:.2f}',
                style: { fontSize: '9pt' }
            }
        },
        {
            top: '80%',
            height: '20%',
            min: 0,
            max: maxVolumeValue * 1.2
        }
    ],

    series: [
        {
            yAxis: 0,
            type: 'candlestick',
            data: data[0],
            color: '#ed454a',
            upColor: '#8cc176',
            lineWidth: 1,
            lineColor: '#3e3e3e'
        },
        {
            yAxis: 1,
            type: 'column',
            data: data[1]
        }
    ]
});

css:

#container {
  width: 100%;
  height: 100vh;
}

html:

<div id="container"></div>
<script src="https://code.highcharts.com/stock/highstock.js" type="text/javascript"></script>
<script src="https://code.highcharts.com/modules/no-data-to-display.js" type="text/javascript"></script>

It is working appropriately if I have data for each time point (with null values for the yAxis).
But I guess that's not what the datetime type for the xAxis was added for -> having a timerange without adding data points for each time:

Null Datapoint Fiddle (https://jsfiddle.net/8g745vxr/1/) (see JS line 45/46)

So is there a way to achieve this behavior without having data for each datapoint on the xAxis like on the 2nd fiddle? Really appreciate any help!

EDIT: this is already a noted issue: https://github.com/highcharts/highcharts/issues/19475

1

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.