Chart js doesn’t update properly for custom filter

I’m having issues with creating filters for a chart. When I click one of the filters, it doesn’t seem to be correctly processing. Any ideas?

const ctx = document.getElementById('earningsChart');
const earningDates = ['2023-12-14', '2023-12-15', '2023-12-16', '2023-12-17', '2023-12-18', '2023-12-19', '2023-12-20', '2023-12-21', '2023-12-22', '2023-12-23', '2023-12-24', '2023-12-25', '2023-12-26', '2023-12-27', '2023-12-28'];
const earningDatesConverted = earningDates.map(earningDate => new Date(earningDate).setHours(0, 0, 0, 0));

const earningsData = [
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 
[, , , , , , , , , , , , 1.0, 1.0, 1.0], 
[, , , , , , , , , , , , 1.0, 1.0, 1.0], 
[, , , , , , , , , , , , 1.0, 1.0, 1.0], 
[, , , , , , , , , , , , 1.5, 1.5, 1.5], 
[, , , , , , , , , , , , 2.0, 2.0, 2.0]];

const earningsChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: earningDates, 
        datasets: [
                {
                    label: 'Merchant 1',
                    data: earningsData[0],
                    fill: false,
                    borderColor: '#6FA1C1',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 2',
                    data: earningsData[1],
                    fill: false,
                    borderColor: '#FFEB8C',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 3',
                    data: earningsData[2],
                    fill: false,
                    borderColor: '#E3F687',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 4',
                    data: earningsData[3],
                    fill: false,
                    borderColor: '#81D374',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 5',
                    data: earningsData[4],
                    fill: false,
                    borderColor: '#7A6AB0',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 6',
                    data: earningsData[5],
                    fill: false,
                    borderColor: '#D073A4',
                    tension: 0.5,
                    spanGaps: true
                },              {
                    label: 'Merchant 7',
                    data: earningsData[6],
                    fill: false,
                    borderColor: '#FFCE8C',
                    tension: 0.5,
                    spanGaps: true
                }
        ]
    },
    options: {
        spanGaps: true,
        scales: {
            x: {
                type: 'time',
                time: {
                    unit: 'day'
                }
            },
            y: {
                beginAtZero: true
            }
        },
        plugins: {
            legend: {
                display: true,
                position: 'bottom'
            },
            tooltip: {
                callbacks: {
                    title: function(tooltipItem, data) {
                        if( tooltipItem[0].parsed.x ) {
                            let dt = new Date(tooltipItem[0].parsed.x);
                            let dtMonth = dt.getMonth() + 1;
                            return dtMonth + "https://stackoverflow.com/" + dt.getDate() + "https://stackoverflow.com/" + dt.getFullYear();
                        }

                        return '';
                    },
                    label: function(context) {
                        let earn_rate = context.parsed.y;
                        let merchant_name = context.dataset.label;

                        return merchant_name + ': ' + earn_rate.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                    }
                },
                titleFont: {
                    size: 18
                },
                bodyFont: {
                    size: 16
                }
            }
        }
    }
});

function filterDate() {
    const filterDateStartObj = new Date(document.getElementById('filterDateStart').value);
    filterDateStart = filterDateStartObj.setHours(0, 0, 0, 0);

    const filterDateEndObj = new Date(document.getElementById('filterDateEnd').value);
    filterDateEnd = filterDateEndObj.setHours(0, 0, 0, 0);

    const filterDates = earningDatesConverted.filter(date => date >= filterDateStart && date <= filterDateEnd);
    earningsChart.config.data.labels = filterDates;

    const startArray = earningDatesConverted.indexOf(filterDates[0]);
    const endArray = earningDatesConverted.indexOf(filterDates[filterDates.length - 1]);
    const copyEarningsData = [...earningsData];
    copyEarningsData.splice(endArray + 1, filterDates.length);
    copyEarningsData.splice(0, startArray);
    earningsChart.config.data.datasets[0].data = copyEarningsData;
    earningsChart.update();
}

function filterDateReset() {
    earningsChart.config.data.labels = earningDatesConverted;
    earningsChart.config.data.datasets[0].data = earningsData;

    document.getElementById('filterDateStart').value="2023-12-14";
    document.getElementById('filterDateEnd').value="2023-12-28";

    earningsChart.update();
}

function filterDateAll() {
    filterDateReset();
}

function filterDate90() {
    document.getElementById('filterDateStart').value="2023-09-29";
    document.getElementById('filterDateEnd').value="2023-12-28";
    filterDate();
}

function filterDate30() {
    document.getElementById('filterDateStart').value="2023-11-28";
    document.getElementById('filterDateEnd').value="2023-12-28";
    filterDate();
}

function filterDate7() {
    document.getElementById('filterDateStart').value="2023-12-21";
    document.getElementById('filterDateEnd').value="2023-12-28";
    filterDate();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.js" integrity="sha512-d6nObkPJgV791iTGuBoVC9Aa2iecqzJRE0Jiqvk85BhLHAPhWqkuBiQb1xz2jvuHNqHLYoN3ymPfpiB1o+Zgpw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<div>
    <canvas id="earningsChart"></canvas>
</div><div class="container">
    <div class="row">
        <div class="col">
            <label>Last</label>
            <button onclick="filterDateAll()">All</button>
            <button onclick="filterDate90()">90</button>
            <button onclick="filterDate30()">30</button>
            <button onclick="filterDate7()">7</button>
            <label>Days</label>
        </div>
        <div class="col">
            <label for="filterDateStart">Start</label>
            <input class="lph input" type="date" id="filterDateStart" min="2023-12-14" max="2023-12-27" value="2023-12-14">
            <label for="filterDateEnd" class="lph">End</label>
            <input class="lph input" type="date" id="filterDateEnd" min="2023-12-15" max="2023-12-28" value="2023-12-28">
            <button onclick="filterDate()">Filter</button>
            <button onclick="filterDateReset()">Reset</button>
        </div>
    </div>
</div>

  • you mean, when you filter by dates, only one line showed instead of showing all lines?

    – 




If you have a problem that shows only one line instead of all lines, here’s an answer.

As far as I think, there are some mistakes in filterDate function.
you just update dataset as below.

  earningsChart.config.data.datasets[0].data = copyEarningsData;

but this means that you only update one dataset.

correct code is here.

earningsChart.config.data.labels = filterDates;
for (let i = 0; i < filteredDatasets.length; i++) {
    earningsChart.config.data.datasets[i].data = filteredDatasets[i];
}

so filterDate function must be like this.

function filterDate() {
    const filterDateStartObj = new Date(document.getElementById('filterDateStart').value);
    filterDateStart = filterDateStartObj.setHours(0, 0, 0, 0);

    const filterDateEndObj = new Date(document.getElementById('filterDateEnd').value);
    filterDateEnd = filterDateEndObj.setHours(0, 0, 0, 0);

    const filterDates = earningDatesConverted.filter(date => date >= filterDateStart && date <= filterDateEnd);
      const startArray = earningDatesConverted.indexOf(filterDates[0]);
    const endArray = earningDatesConverted.indexOf(filterDates[filterDates.length - 1]);

    const filteredDatasets = earningsData.map(dataset => dataset.slice(startArray, endArray + 1));

    // Update the labels and datasets' data in the chart configuration
    earningsChart.config.data.labels = filterDates;
    for (let i = 0; i < filteredDatasets.length; i++) {
        earningsChart.config.data.datasets[i].data = filteredDatasets[i];
    }

    // Update the chart
    earningsChart.update();
}

I think this answer will help you.

Leave a Comment