graphchart.jslinegraph

Make a parallelogram from the line graph


I'm using vanilla JS with Chart.js. I want to make this line graph into something parallelogram.

Currently looks like this Want something like this
enter image description here enter image description here

And my code is this:

var chart = function () {
    var ctx = document.getElementById('kt_chartjs_1');

    // Define colors
    var primaryColor = KTUtil.getCssVariableValue('--kt-primary');
    var dangerColor = KTUtil.getCssVariableValue('--kt-danger');
    var successColor = KTUtil.getCssVariableValue('--kt-success');
    
    // Define fonts
    var fontFamily = KTUtil.getCssVariableValue('--bs-font-sans-serif');
    
    // Chart labels
    const labels = Array.from({ length: 34 }, (_, i) => `${i + 1}`);
    
    // Chart data
    const data = {
        labels: labels,
        datasets: [
            {
                label: 'Dataset 1',
                data: [
                    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
                    20, 21, 22, 23, 24, 25, 26, 10, 11, 12, 
                    13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 
                ],
                backgroundColor: ['#fff'] // Bar color
            },
            {
                label: 'Line Dataset',
                data: [
                    11, 12, 13, 14, 15, 16, 17, 18, 19, 
                    20, 21, 22, 23, 24, 25, 26, 27, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
                    20, 21, 22, 23, 24, 25, 26, 27,  
                ],
                borderColor: ['#eee'], // Line color
                backgroundColor: ['#eee'], // No fill
                borderWidth: 2,
                fill: false, // Do not fill under the line
                type: 'line' // Specify this dataset as a line
            }
        ]
    };
    
    // Chart config
    const config = {
        type: 'bar', // Base type is bar
        data: data,
        options: {
            plugins: {
                title: {
                    display: false,
                }
            },
            responsive: true,
            interaction: {
                intersect: false,
            },
            scales: {
                x: {
                    stacked: true,
                },
                y: {
                    stacked: true
                }
            }
        },
        defaults:{
            global: {
                defaultFont: fontFamily
            }
        }
    };
    
    // Init ChartJS
    var myChart = new Chart(ctx, config);
}

Can you guys help me, I think I'm stuck. Thanks guys :)


Solution

  • You could just add a new dataset with the vertices of the parallelogram. Since this dataset will not use labels sequentially, you have to define its data points as objects, {x: ..., y: ...}; if you know the indices of the line data points that will be the vertices of the parallelogram (0, 16, 34, 17), it will be just:

    const lineData = data.datasets[1].data;
    const P1 = {x: labels[0], y: lineData[0]},
      P2 = {x: labels[16], y: lineData[16]},
      P3 = {x: labels[34], y: lineData[34]},
      P4 = {x: labels[17], y: lineData[17]};
    const parallelogram = {
      type: 'line',
      data: [P1, P2, P3, P4, {...P1}],
      borderColor: 'red',
      borderWidth: 4,
      label: 'Parallelogram'
    };
    data.datasets.push(parallelogram);
    

    Or you can identify dynamically the "break" point of the original data, where's a drop in value, as in the following snippet:

    const labels = Array.from({ length: 34 }, (_, i) => `${i + 1}`);
    
    // Chart data
    const data = {
        labels: labels,
        datasets: [
            {
                label: 'Dataset 1',
                data: [
                    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
                    20, 21, 22, 23, 24, 25, 26, 10, 11, 12,
                    13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
                ],
                backgroundColor: ['rgba(242, 242, 242, 0.5)'], // Bar color
            },
            {
                label: 'Line Dataset',
                data: [
                    11, 12, 13, 14, 15, 16, 17, 18, 19,
                    20, 21, 22, 23, 24, 25, 26, 27, 11, 12, 13, 14, 15, 16, 17, 18, 19,
                    20, 21, 22, 23, 24, 25, 26, 27,
                ],
                borderColor: ['#eee'], // Line color
                backgroundColor: ['#eee'], // No fill
                borderWidth: 2,
                fill: false, // Do not fill under the line
                type: 'line', // Specify this dataset as a line
            }
        ]
    };
    
    const lineData = data.datasets[1].data;
    let iBreak = 0, yPrevious = -1/0;
    while(iBreak < lineData.length){
        if(lineData[iBreak] < yPrevious){
            break;
        }
        yPrevious = lineData[iBreak];
        iBreak++;
    }
    const P1 = {x: labels[0], y: lineData[0]},
        P2 = {x: labels[iBreak-1], y: lineData[iBreak-1]},
        P3 = {x: labels[lineData.length - 1], y: lineData[lineData.length-1]},
        P4 = {x: labels[iBreak], y: lineData[iBreak]};
    
    const parallelogram = {
        type: 'line',
        data: [P1, P2, P3, P4, {...P1}],
        borderColor: 'red',
        borderWidth: 4,
        label: 'Parallelogram'
    };
    data.datasets.push(parallelogram);
    
    // Chart config
    const config = {
        type: 'bar', // Base type is bar
        data: data,
        options: {
            plugins: {
                title: {
                    display: false,
                },
                filler:{
                    drawTime: "beforeDraw"
                }
            },
            responsive: true,
            interaction: {
                intersect: false,
            },
            scales: {
                x: { // not stacked
                    //stacked: true,
                },
                y: { // not stacked
                    //stacked: true
                }
            }
        },
        defaults:{
            global: {
                //defaultFont: fontFamily
            }
        }
    };
    
    // Init ChartJS
    new Chart('chart', config);
    <div style="min-width: 600px; height: 350px; background-color: black">
    <canvas id="chart"></canvas>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>