Chartjs-Chart.js customization, two Y-Axis overlay, chart area padding, odd tick padding

0👍

After a huge amount of ideas, attempts and errors, I found a solution for the full customization of the scale.

For this I

  1. Disabled the display of gridlines and ticks using property
    display:false,
  1. Wrote a plugin that draw gridlines and ticks in accordance with the design.
    That’s what happened
var AikGridLinePlugin = {
    beforeDraw: function(chartInstance) {
        var yScaleLeft = chartInstance.scales["left-y-axis"];
        var yScaleRight = chartInstance.scales["right-y-axis"];
        var canvas = chartInstance.chart;
        var ctx = canvas.ctx;

        //left axis
        var left_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "left-y-axis"});
        var left_side_list_data = [].concat(...Object.keys(left_side_list).map(e => left_side_list[e].data));
        let left_side_list_max = Math.max.apply(Math,left_side_list_data);
        let left_side_list_min = Math.min.apply(Math,left_side_list_data);
        let left_iterval = (left_side_list_max - left_side_list_min) / 8;

        // right axis
        var right_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
        var right_side_list_data = [].concat(...Object.keys(right_side_list).map(e => right_side_list[e].data));
        let right_side_list_max = Math.max.apply(Math,right_side_list_data);
        let right_side_list_min = Math.min.apply(Math,right_side_list_data);
        let right_iterval = (right_side_list_max - right_side_list_min) / 8;

        var current_value_left = left_side_list_min,
            current_value_right = right_side_list_min,
            current_value_right_text=0;
        for(var i=1;i<10;i++) {
            ctx.lineWidth = 1;
            ctx.font = "13px Roboto";
            ctx.fillStyle = "#666666";
            ctx.beginPath();
            if(i%2==0) {
                ctx.moveTo(47, yScaleLeft.getPixelForValue(current_value_left));
                ctx.lineTo((canvas.width-47), yScaleLeft.getPixelForValue(current_value_left));
                ctx.fillText((current_value_left>1)?current_value_left.toFixed(0):current_value_left.toFixed(1), 5, yScaleLeft.getPixelForValue(current_value_left)+5);
                current_value_right_text=(current_value_right>1 || current_value_right<-1)?current_value_right.toFixed(0):current_value_right.toFixed(1);
                ctx.fillText(current_value_right_text, (canvas.width-5-ctx.measureText(current_value_right_text).width), yScaleLeft.getPixelForValue(current_value_left)+5);
            } else {
                ctx.moveTo(15, yScaleLeft.getPixelForValue(current_value_left));
                ctx.lineTo((canvas.width-15), yScaleLeft.getPixelForValue(current_value_left));
            }
            ctx.strokeStyle = "#91979F";
            ctx.stroke();
            current_value_left = current_value_left+left_iterval;
            current_value_right = current_value_right+right_iterval;
        }
        return;


    }
};
Chart.pluginService.register(AikGridLinePlugin);

function data_generation(values_obj) {
        let max_val=-900;
        let min_val=0;
    Object.keys(values_obj).forEach(function(key) {
        chart_object={};
        chart_object.label= values_obj[key].name;
        chart_object.data= Object.values(values_obj[key].data);
        chart_object.backgroundColor= values_obj[key].color;
        if(key == 'TempOutdoor') {
            chart_object.yAxisID = 'right-y-axis';
            chart_object.backgroundColor= "transparent";
            chart_object.pointRadius= 4;
            chart_object.lineTension= 0;
            chart_object.pointBackgroundColor="#FFF";
            chart_object.pointBorderColor= "#60AD5E";
            chart_object.borderColor= "#60AD5E";
            chart_object.pointBorderWidth= 2;
            chart_object.type= 'line';
        } else {
            chart_object.yAxisID = 'left-y-axis';
            chart_object.lineTension= 0;
        }       
        config.data.datasets.push(chart_object);
        //find common min and max values        
        //min
        if(min_val>parseFloat(values_obj[key].min)) {
            min_val = parseFloat(values_obj[key].min);
        }
        //max
        if(max_val < parseFloat(values_obj[key].max)) {
            max_val = parseFloat(values_obj[key].max);
        }
    });   
}
var config = {
    drawTicks:false,
    type: 'bar',
    data: {
        datasets: [   ],
        labels: ''
    },

    options:  {

        animation: {
            duration: 0
        },
        'legend':false,
        responsive:true,
        maintainAspectRatio: false,
        scales: {
            xAxes: [{
                id: 'x-axis',
                stacked: true,
                barThickness: ($(window).width()<991.99)?14:24,
                ticks: {
                    fontSize: ($(window).width()<991.99)?10:14,

                },
                gridLines : {
                    display : false
                }
            }],
            yAxes: [
                {
                    id: 'left-y-axis',
                    type: 'linear',
                    position: 'left',
                    ticks: {
                        display:false,
                    },
                    gridLines: {
                        display : false,
                        drawBorder: false,
                        tickMarkLength:  ($(window).width()<991.99)?34:84,
                    }

                },
                {
                    id: 'right-y-axis',
                    type: 'linear',
                    position: 'right',
                    ticks: {
                        display : false,
                        beginAtZero: false,
                        fontSize: ($(window).width()<991.99)?10:14,

                    },
                    gridLines: {
                        display : false,
                        drawBorder: false,
                        tickMarkLength:  ($(window).width()<991.99)?34:84,
                    }
                }
            ]
        }
    }
};


window.onload = function() {

var data_string='{"success":true,"axis":["Пн","Вт","Ср","Чт","Пт","Сб","Вс"],"data":{"TempOutdoor":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":-4.9787234042553195,"Вт":-2.9166666666666665,"Ср":-3.3125,"Чт":2.5208333333333335,"Пт":6.84375,"Сб":0,"Вс":0},"min":"-4.98","max":"6.84","avg":"-0.26","sum":"-1.84","name":"Температура на улице","color":"#60AD5E","value_type":"instant"},"MotoHW":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":11,"Вт":15,"Ср":13,"Чт":12,"Пт":9,"Сб":0,"Вс":0},"min":"0.00","max":"15.00","avg":"8.57","sum":"60.00","name":"Мотогодини: Гаряча вода","color":"#29819D","value_type":"counter"}},"closestPeriods":{"previous":{"2021-05-03 00:00:00":"03.05 - 09.05"},"current":{"2021-05-10 00:00:00":"10.05 - 16.05"},"next":null}}';
  var data = JSON.parse(data_string);    

                config.data.labels = data.axis;
                var values_obj = data.data;
                data_generation(values_obj);
                //console.log(JSON.stringify(config));
                var ctx = document.getElementById('StatisticsChartCanvas').getContext('2d');
                window.StatisticsChart = new Chart(ctx,config); 

};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrapper" style="width:548px; height:265px;">
  <canvas id="StatisticsChartCanvas"></canvas>
</div>

Leave a comment