Search code examples
javascripthtmlchartschart.jsline

How to create Black Border for Every Y Scale's X Axis with Line Chart in Chartjs


Line Chart

I want to have black border in every border of X axises of Y scales. How can I do it and have a border that starts with 0 in x axises. So I want to have black border for every x axis and that borders should have value 0. (I just shared y1 and y2, but there is actually y3 and y4 too in my code) Here is my code of my scales:

            scales: {
                x: {
                    type: "linear",
                    position: "left",
                    max: this.res.maxs[0],
                    min: 0,
                    gridLines: {
                        display: true,
                    },
                },

                y1: {
                    type: "linear",
                    position: "left",
                    stack: "demo",
                    stackWeight: 1,
                    max: this.res.maxs[4],
                    min: 0,
                    title: {
                        display: true,
                        text: this.axisLabels[3],
                        font: {
                            size: 11,
                        },
                    },
                },
                y2: {
                    type: "linear",
                    position: "left",
                    stack: "demo",
                    stackWeight: 1,
                    grid: {
                        borderColor: "blue",
                    },
                    max: this.res.maxs[2],
                    min: -10,
                    title: {
                        display: true,
                        text: this.axisLabels[1],
                        font: {
                            size: 11,
                        },
                    },
                    ticks: {
                        callback: (value, index, values) =>
                            index == 0 ? undefined : value.toFixed(1),
                    },
                },

               
            }

Solution

  • A safe solution is to use the plugin chartjs-plugin-annotation that has a line annotation.

    A line at the bottom of the axis y2 can be obtained by using the options:

    options:{
        // other options .....
        plugins: {
            // other plugins .... 
            annotation: {
                annotations: {
                    line_y2_bottom: {
                        type: 'line',
                        scaleID: 'y2',
                        value: function({chart}, props){
                            const scale = chart.scales[props.scaleID];
                            return scale.getValueForPixel(scale.bottom - 1) || scale.min;
                        },
                        borderColor: 'black',
                        borderWidth: 3,
                    },
                }
            }
        }
    }
    

    If known apriori, the value can be set to a fixed numeric value. However, the fact that value, as well as most other properties, is scriptable is a great advantage in this context, when the axes have offset: true, so the actual minimal value (as well as maximal one) are not dictated exclusively by the data, but also by the objective of making all axes fit in the available space.

    The line id, in the example above, line_y2_bottom is arbitrary, I chose it to be meaningful for humans, the only requirement is that each annotation has a different id.

    A minimal snippet example that draws a line at the bottom of each chart:

    const x = Array.from({length: 101}, (_, i)=>({x: i/100}));
    const data = {
        datasets: [
            {
                data: x.map(({x})=>({x, y: Math.exp(x+1)})),
                borderColor: 'red',
                yAxisID: 'y1'
            },
            {
                data: x.map(({x})=>({x, y: Math.exp(-x+1)})),
                borderColor: 'blue',
                yAxisID: 'y2',
            },
            {
                data: x.map(({x})=>({x, y: Math.sin(x+1)})),
                borderColor: 'green',
                yAxisID: 'y3',
            }
        ]
    };
    const config = {
        type: 'line',
        data: data,
        options: {
            responsive: true,
            aspectRatio: 1,
            plugins: {
                legend: {
                    display: false,
                },
                annotation: {
                    annotations: Object.fromEntries(['y1', 'y2', 'y3'].map(
                        scaleID => [
                            `line_${scaleID}_bottom`,
                            {
                                type: 'line',
                                scaleID,
                                value: function({chart}, props){
                                    const scale = chart.scales[props.scaleID];
                                    return scale.getValueForPixel(scale.bottom-1) || scale.min;
                                },
                                borderColor: 'black',
                                borderWidth: 3,
                            }
                        ])
                    )
                }
            },
    
            scales: {
                x: {
                    type: 'linear',
                },
                y1: {
                    stack: 'demo',
                    offset: true,
                    stackWeight: 1,
                },
                y2: {
                    stack: 'demo',
                    stackWeight: 2,
                    border:{
                        color: 'black',
                        width: 2
                    },
                    offset: true
                },
                y3: {
                    stack: 'demo',
                    offset: true,
                    stackWeight: 1
                }
            }
        },
    };
    new Chart(document.querySelector('#chart1'), config);
    <div style="width: 95vw">
       <canvas id="chart1"></canvas>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.3.0/chart.umd.js" integrity="sha512-CMF3tQtjOoOJoOKlsS7/2loJlkyctwzSoDK/S40iAB+MqWSaf50uObGQSk5Ny/gfRhRCjNLvoxuCvdnERU4WGg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/3.0.1/chartjs-plugin-annotation.min.js" integrity="sha512-Hn1w6YiiFw6p6S2lXv6yKeqTk0PLVzeCwWY9n32beuPjQ5HLcvz5l2QsP+KilEr1ws37rCTw3bZpvfvVIeTh0Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>