79557652

Date: 2025-04-05 23:49:58
Score: 1
Natty:
Report link

If you want to set the min value explicitly, you have to set the options:

chart.options.scales.y.min = -100;
chart.update('none');

The call to chart.update is reading the data and options and sets the dynamic values like chart.scales.y.min according to these. Thus, values like chart.scales.y.min are only useful for reading the state of the chart objects (in this case 'y' axis), but can't be used to change that state.

If you want to leave it to the standard chart.js algorithm to find the nice limits to the axis, you may try disabling y panning (by setting mode: 'x', as it's already set for zoom). A slight vertical change while panning will interfere with the way the limits are computed, and might then be amplified by a subsequent zoom operation.

My testing with x-mode panning seemed to always produce good limits, but if there are still cases when it's not working, please let me know. Here's the snippet (I also set options.scales.y.ticks.includeBounds = true):

const PI = Math.PI;

function daysIntoYear(date) {
    return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}

function secondsToDhms(seconds) {
    seconds = Number(seconds);
    var d = Math.floor(seconds / (3600 * 24));
    var h = Math.floor(seconds % (3600 * 24) / 3600);
    var m = Math.floor(seconds % 3600 / 60);
    var s = Math.floor(seconds % 60);

    var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
    var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
    var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
    var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
    return dDisplay + hDisplay + mDisplay + sDisplay;
}

function dataSimulation(from, to, grouping) {
    const timeDiff = (new Date(to) - new Date(from)) / 1000;
    //console.log("fromDate=" + from + " toDate=" + to + " diff=" + secondsToDhms(timeDiff) + " group=" + secondsToDhms(grouping));
    datamapped = [];
    dataEvery = 60 * 20; // Data get every 20mn
    min = 999;
    max = -999;
    i = 0;
    sum = 0;
    for (x = new Date(from).getTime(); x <= new Date(to).getTime(); x = x + 1000 * dataEvery) {
        date = new Date(x);
        H = date.getHours();
        M = date.getMinutes();
        month = date.getMonth();
        day = date.getDate();
        nday = daysIntoYear(date);

        value = day + (H / 100) + (M / 10000); // simple simulation
        value = 20 + (10 * Math.sin(nday * (PI / 180))) + 3 * Math.sin(H * (360 / 24) * (PI / 180)); // more complex

        sum = sum + value;
        if (value > max)
            max = value;
        if (value < min)
            min = value;
        if ((i * dataEvery) > grouping) {
            datamapped.push({
                x: new Date(x).toISOString(),
                min: min,
                max: max,
                avg: sum / i
            });
            i = 0;
            sum = 0;
            min = 999;
            max = -999;
        }
        i = i + 1;
    }
    return datamapped;
}

async function fetchData(from, to, group) {

    /**
        const response = await fetch(`data.php?from=${from}&to=${to}&sensor=OWM&grouptime=86400`);
        const data = await response.json();
        datamapped =  data.map(item => ({
              x: item[0],
            min: item[1],
            max: item[2],
            avg: item[3]
        }));
     **/
    datamapped = dataSimulation(from, to, group);
    return datamapped;
}

var LASTUPDATETIME;
LASTUPDATETIME = new Date();
var LOCK;
LOCK = false;
async function updateData(chart) {
    difftime = (new Date().getTime() - LASTUPDATETIME.getTime());
    //console.log("LOCK=" + LOCK + " difftime=" + difftime);
    if (LOCK == true) {
        if (difftime < 1000)
            return;
    }
    LOCK = true;
    //if (  difftime < 500)
    //{ // debounce
    //    console.log("too soon");
    //    return;
    //}
    const xmin = chart.scales.x.min;
    const xmax = chart.scales.x.max;
    const fromDate = new Date(xmin).toISOString();
    const toDate = new Date(xmax).toISOString();
    const timeDiff = (xmax - xmin) / 1000;
    group = 31 * 24 * 3600;
    if (timeDiff < 1 * 24 * 3600) { // <1 days, display per every minute
        group = 60;
    } else if (timeDiff < 4 * 24 * 3600) { // <4 days, display per every hours
        group = 3600;
    } else if (timeDiff < 33 * 24 * 3600) { // <1.1month, display per 4xday
        group = 4 * 3600;
    } else if (timeDiff < 4 * 31 * 24 * 3600) { // <4month, display per day
        group = 24 * 3600;
    }
    /**
        response = await fetch(`data.php?fmt=json&from=${fromDate}&to=${toDate}&sensor=OWM&grouptime=${group}`);
        data = await response.json();
        datamapped = data.map(item => ({
              x: item[0],
            min: item[1],
            max: item[2],
            avg: item[3]
        }));
     **/
    datamapped = dataSimulation(fromDate, toDate, group);
    chart.data.datasets[0].data = datamapped;
    chart.data.datasets[1].data = datamapped;
    chart.data.datasets[2].data = datamapped;
    const yDataMax = Math.max(...datamapped.map(({max}) => max)),
        yDataMin = Math.min(...datamapped.map(({min}) => min));

    //chart.scales.options.y.min = -100; // as a test, the Y axis should be at -100, but not working
    chart.update('none'); // with 'none' it's synchronous, so we can get the results immediately after:
    console.clear(); // to preserve snippet space
    console.log(`after .update, data:, [${yDataMin}, ${yDataMax}], scale: [${chart.scales.y.min}, ${chart.scales.y.max}]`);
    LASTUPDATETIME = new Date();
    LOCK = false;
}

async function createChart(from, to, group) {
    const data = await fetchData(from, to, group);
    const ctx = document.getElementById('temperatureChart').getContext('2d');
    const temperatureChart = new Chart(ctx, {
        type: 'line',
        data: {
            datasets: [{
                data: data, // The three values are on the same data ? strange
                parsing: {
                    yAxisKey: 'min'
                },
                fill: '+1',
                borderWidth: 0
            },
                {
                    data: data, // this is strange to have the same data than the previous
                    parsing: {
                        yAxisKey: 'max'
                    },
                    borderWidth: 0
                },
                {
                    data: data,
                    parsing: {
                        yAxisKey: 'avg'
                    },
                    borderColor: 'green',
                    fill: false,
                    borderWidth: 1
                }
            ]
        },
        options: {
            responsive: true,
            animation: false,
            elements: {
                point: {
                    radius: 1
                }
            },
            scales: {
                x: {
                    type: 'time',
                    time: {
                        tooltipFormat: 'yyyy-MM-dd HH:mm'
                    },
                    title: {
                        display: true,
                        text: 'Date/Time'
                    },

                },
                y: {
                    beginAtZero: false,
                    ticks: {
                        includeBounds: false
                    },
                    title: {
                        display: true,
                        text: 'Temperature (°C)'
                    },

                }
            },
            plugins: {
                legend: {
                    display: true,
                    position: 'top'
                },

                zoom: {
                    pan: {
                        // pan options and/or events
                        enabled: true,
                        mode: "x",
                        onPanComplete: function({
                                                    chart
                                                }) {
                            updateData(chart);
                        }
                    },
                    zoom: {
                        wheel: {
                            enabled: true,
                        },
                        pinch: {
                            enabled: true
                        },
                        mode: 'x',
                        onZoomComplete: function({
                                                     chart
                                                 }) {
                            updateData(chart);
                        }
                    }
                }
            }
        }
    });
}

// Example usage
createChart('2024-01-01', '2024-12-31', 31 * 24 * 3600);
<div style="width: 100%; margin: auto;">
    <canvas id="temperatureChart"></canvas>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom"></script>

Reasons:
  • Blacklisted phrase (1): but not working
  • RegEx Blacklisted phrase (2.5): please let me know
  • Long answer (-1):
  • Has code block (-0.5):
  • High reputation (-1):
Posted by: kikon