1

I want to draw minor gridlines in the chart drawn by the following below to get the result similar to x-axis in following image (except instead of tick value shown in simple number instead of power i.e. instead 10^0 it should show 1 and instead of 10^1 it should show 10 and so on. Image is os meant to show just the gridlines on x-axis):

Log Gridline Image

<!DOCTYPE html>
<!-- saved from url=(0014)about:internet -->
<html>
<head>
    <title>Chart</title>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=Edge'>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-colorschemes"></script>
    <style>
        body { margin: 0; padding: 0; }
        #container { width: 100%; }
    </style>
</head>
<body>
<div id='container'>
    <canvas id='myChart'></canvas>
</div>
<script>
    Chart.defaults.global.animation.duration = 1000;
    Chart.defaults.global.animation.easing = 'linear';
    var ctx = document.getElementById('myChart').getContext('2d');
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ['10','2000','30000','50000','60000','700000',],
            datasets: [
               {label: 'ABC' ,
                fill: true ,
                data: [ 
                  { x: '10', y: 2 },
                  { x: '2000', y: 4 },
                  { x: '30000', y: 7 },
                  { x: '50000', y: 8 },
                  { x: '60000', y: 8.5 },
                  { x: '700000', y: 9 }
                  ],
                borderWidth: 1},
             ]
        },
        options: {
            aspectRatio:  1.6,
            title: {
                display: true,
                position: 'top',
                text: 'Ref Data'
            },
            legend: {
                display: true,
                position: 'right',
            },
            scales: {
                yAxes: [{
                    id: 'first-y-Axis',
                    display: true,
                    scaleLabel: {
                       display: true,
                       labelString: 'Demo y-axis'
                    }
                    }],
                xAxes: [{
                    id: 'first-x-Axis',
                    display: true,
                    type: 'logarithmic',
                    scaleLabel: {
                       display: true,
                       labelString: 'Demo x-axis'
                    },
                    ticks: {
                       //min:  0 ,
                       //max:  700000
                       callback: function (value, index, values) {
                       if (Math.log10(value) % 1 === 0) { return value; }
                       }
                    }
                    }]
            },
            plugins: {
                colorschemes: {
                    scheme: 'brewer.Paired12'
                    }
                }
        }
    });
</script>
</body>
</html>

Similar solution is also discussed in the post linked here but the code used in that post is very complex and I am unable to understand and make it work in my code as I don't know much about JavaScript. Just trying to make this graph for ine application. I'll thankful if someone here can modify my code or help me modify the code to get minor gridlines like the image or in the post linked above (except minor gridlines are created for y-axis in the post but I want for x-axis).

Best Regards

2
  • As stated at very beginning of the post you linked to, you don't have to do anything to have minor grid lines other than make sure your ticks callback returns "" (an empty string), for those ticks that don't have a label. The code in that post was about styling the minor lines and filtering the occasional unwanted grid line at such values as 15 or 150.
    – kikon
    Commented Sep 10, 2023 at 12:52
  • I also want to make to make minute gridlines thinner (and dashed) than the major one. I didn't lot of time we to copy paste the code from the linked post and tried to adjust it at various locations in my code but none worked. Can you help me in that too.
    – Pacman
    Commented Sep 10, 2023 at 14:20

1 Answer 1

1

As was the case in the OP linked post (which was designed for the latest chart.js v4), it is still valid for chart.js v2+ that minor grid lines are created if ticks.callback returns an empty string instead of null or undefined (or if there's no ticks.callback).

However, there are differences in the way one may style the minor grid lines to differentiate them from major ones. In chart.js v2.9.4 scales' gridLines options are not scriptable. This calls for a different approach, one that might in some cases be useful for newer versions: using indexable options, which means that one has to create an array with a (different) value for each item - in this case for each grid line. Since the ticks are only known at runtime, one can create that array in an axis callback, e.g., in afterBuildTicks:

afterBuildTicks(scale){
    const nTicks = scale.ticks.length,
        isMajor = scale.ticks.map(value => ('' + value).replace(/0+$/, '') === '1');
    scale.options.gridLines.lineWidth = 
        Array.from({length: nTicks}, (_, i) => isMajor[i] ? 1.2 : 0.5);
    scale.options.gridLines.color = 
        Array.from({length: nTicks}, (_, i) => isMajor[i] ? '#000' : '#ddd');
    //scale.options.gridLines.borderDash - can't be set as an array of arrays
}

Unfortunately, this approach doesn't seem to work for borderDash.


I'll give some details about what exactly how this function works: using an indexable option, let's say gridLines.lineWidth, means we set its value as an array:

gridLines:{
    lineWidth: [1.2, 0.5, 0.5, 0.5, 0.5, 1.2, 0.5, .......]
}

The problem is that the ticks are built by chart.js from the data, we don't know beforehand how many ticks there are in total and how many and where are the major ones. So we have to wait for chart.js to build those ticks and then, in the handler automatically called immediately after the ticks are built, afterBuildTicks, we set the grid line properties, based on the actual tick values. This makes sense, since the gridlines are drawn after the ticks were built.

The function afterBuildTicks receives as an argument the scale object, from which we extract the ticks as scale.ticks. Then we decide which ticks will be "major" - to be drawn with a thicker line - the definition I used is that the string representation is a 1 fallowed by 0s. An alternative, mathematical formulation can be devised, using Math.log10.

Now, we know how many ticks there are and where are the major ones so we can build the array introduced above for gridLines.lineWidth. The function Array.from is used; alternatively, we could have used isMajor.map with the same functions.


Code snippet:

Chart.defaults.global.animation.duration = 1000;
Chart.defaults.global.animation.easing = 'linear';
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, {
    type: 'line',
    data: {
        labels: ['10', '2000', '30000', '50000', '60000', '700000',],
        datasets: [{
            label: 'ABC',
            fill: true,
            data: [{
                x: '10',
                y: 2
                },
                {
                    x: '2000',
                    y: 4
                },
                {
                    x: '30000',
                    y: 7
                },
                {
                    x: '50000',
                    y: 8
                },
                {
                    x: '60000',
                    y: 8.5
                },
                {
                    x: '700000',
                    y: 9
                }
            ],
            borderWidth: 1
        },]
    },
    options: {
        aspectRatio: 1.6,
        title: {
            display: true,
            position: 'top',
            text: 'Ref Data'
        },
        legend: {
            display: true,
            position: 'right',
        },
        scales: {
            yAxes: [{
                id: 'first-y-Axis',
                display: true,
                scaleLabel: {
                    display: true,
                    labelString: 'Demo y-axis'
                }
            }],
            xAxes: [{
                id: 'first-x-Axis',
                display: true,
                type: 'logarithmic',
                scaleLabel: {
                    display: true,
                    labelString: 'Demo x-axis'
                },
                gridLines: {
                    borderDash: [10, 3],
                    drawTicks: false,
                    drawBorder: false
                },
                afterBuildTicks(scale){
                    const nTicks = scale.ticks.length,
                        isMajor = scale.ticks.map(value => ('' + value).charAt(0) === '1');
                    scale.options.gridLines.lineWidth = Array.from({length: nTicks}, (_, i) => isMajor[i] ? 1.2 : 0.5);
                    scale.options.gridLines.color = Array.from({length: nTicks}, (_, i) => isMajor[i] ? '#000' : '#ddd');
                    //scale.options.gridLines.borderDash - can't be set as an array of arrays
                },
                ticks: {
                    padding: 5,
                    autoSkip: false,
                    maxRotation: 0,
                    callback: function(value, index, values){
                        if(Math.log10(value) % 1 === 0){
                            return value;
                        }
                        return '';
                    }
                }
            }]
        },
        plugins: {
            colorschemes: {
                scheme: 'brewer.Paired12'
            }
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"
        integrity="sha512-SuxO9djzjML6b9w9/I07IWnLnQhgyYVSpHZx0JV97kGBfTIsUYlWflyuW4ypnvhBrslz1yJ3R+S14fdCWmSmSA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-colorschemes"></script>        
<div style="min-height: 60vh">
    <canvas id="myChart">
    </canvas>
</div>


Per request, a version that should work in Internet Explorer and older browsers:

afterBuildTicks: function(scale){
    var nTicks = scale.ticks.length,
        isMajor = scale.ticks.map(function(value){return ('' + value).replace(/0+$/, '') === '1';});
    scale.options.gridLines.lineWidth =
        isMajor.map(function(_, i){return isMajor[i] ? 1.2 : 0.5;})
    scale.options.gridLines.color =
        isMajor.map(function(_, i){return isMajor[i] ? '#000' : '#ddd';});
    //scale.options.gridLines.borderDash - can't be set as an array of arrays
}

and the full code in jsFiddle

7
  • if want to do the same then xScale will be changed to yScale in the above code? Can you share some guide link on which I can understand how this code is functioning to make think/thin major/minor grids so that I can learn it?
    – Pacman
    Commented Sep 11, 2023 at 12:21
  • 1
    Yes, it should work the same, just use the afterBuildTicks function for the other axis. I'll try to write another paragraph explaining what it's doing.
    – kikon
    Commented Sep 11, 2023 at 14:44
  • The code above was working fine in run code snippet but when I made html file of this code and run in internet explorer, it don't run and in the debugging, it says expected ':' line xx:colxx (ie. right after word afterBuildTicks. I need it for internet explorer because I am using this code to generate chart in Microsoft Access webBrowser control that actually IE11. Can you help me make this compatible with IE11. Sorry for sharing this info late because I didn't know that time that would make any difference.
    – Pacman
    Commented Sep 12, 2023 at 3:32
  • I was using newer syntax for functions inside objects; to cover IE and other browsers replace afterBuildTicks(scale){ with afterBuildTicks: function(scale){. Also, Array.from and arrow functions might not work. I added a version for IE and older browsers, please let me know if it works, I don't have a windows machine to test it in IE.
    – kikon
    Commented Sep 13, 2023 at 9:08
  • 1
    I have tried now and it is working. It was my mistake, I left Math.log10 function that was not supported by IE too there which was causing issue. I used the code from jsfiddle and replace Math.log10 function with my custom function and now it is working fine. Thanks a lot.
    – Pacman
    Commented Sep 15, 2023 at 3:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.