在Charts.Js v2.9.4中的对数图中添加次要网格线

hwamh0ep  于 2023-10-18  发布在  Chart.js
关注(0)|答案(1)|浏览(126)

我想在下面绘制的图表中绘制次要网格线,以获得类似于下图中x轴的结果(除了以简单数字而不是幂显示的刻度值,即而不是10^0,它应该显示1,而不是10^1,它应该显示10等等。图像是os意味着只显示x轴上的网格线):

<!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>

类似的解决方案也在帖子**linked here**中讨论过,但在那篇帖子中使用的代码非常复杂,我无法理解并使其在我的代码中工作,因为我不太了解JavaScript。只是想把这个图表应用到我的电脑上。如果这里有人可以修改我的代码或帮助我修改代码,以获得像图像或上面链接的帖子中的小网格线,我将不胜感激(除了在帖子中为y轴创建的小网格线,但我想为x轴创建)。
问候

t8e9dugd

t8e9dugd1#

与OP linked post(专为最新的chart.js v4设计)中的情况一样,如果ticks.callback返回空字符串而不是nullundefined(或者如果没有ticks.callback),则创建次要网格线对于chart.js v2+仍然有效。
但是,为将次要轴网线与主要轴网线区分开来而设置次要轴网线样式的方式存在差异。在chart.js v2.9.4中,scales的gridLines选项是 * 不可脚本化的 *。这需要一种不同的方法,在某些情况下可能对较新的版本有用:使用可索引选项,这意味着必须为每个项目创建一个(不同)值的数组-在这种情况下为每个网格线。由于节拍只在运行时才知道,因此可以在轴回调中创建该数组,例如在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
}

不幸的是,这种方法似乎不适用于borderDash
我将给予一些关于这个函数究竟如何工作的细节:使用一个可索引的选项,比如gridLines.lineWidth,意味着我们将它的值设置为一个数组:

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

问题是,tick是由chart.js从数据中构建的,我们事先不知道总共有多少个tick,以及有多少个和哪里是主要的tick。因此,我们必须等待chart.js构建这些tick,然后在构建tick后立即自动调用的处理程序afterBuildTicks中,我们根据实际的tick值设置网格线属性。这是有意义的,因为网格线是在构建刻度之后绘制的。
函数afterBuildTicks接收scale对象作为参数,从中提取刻度作为scale.ticks。然后我们决定哪些刻度是“主要的”--用粗线画出来--我使用的定义是字符串表示是1 fallowed by 0 s。另一种数学公式可以用Math.log10来设计。
现在,我们知道了有多少个刻度,以及主要刻度在哪里,因此我们可以为gridLines.lineWidth构建上面介绍的数组。使用函数Array.from;或者,我们可以使用具有相同功能的isMajor.map
代码片段:

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>

根据请求,应在Internet Explorer和旧浏览器中工作的版本:

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
}

jsFiddle中的完整代码

相关问题