Search code examples
javascripthtmlangularchart.jschartjs-2.6.0

Make y-axis sticky when having horizontal scroll on chartJS and Angular


I would like to fix y-axis position when scrolling horizontally.

Here's an example that works but without using Angular

$(document).ready(function () {

    function generateLabels() {
        var chartLabels = [];
        for (x = 0; x < 100; x++) {
            chartLabels.push("Label" + x);
        }
        return chartLabels;
    }

    function generateData() {
        var chartData = [];
        for (x = 0; x < 100; x++) {
            chartData.push(Math.floor((Math.random() * 100) + 1));
        }
        return chartData;
    }

    function addData(numData, chart) {
        for (var i = 0; i < numData; i++) {
            chart.data.datasets[0].data.push(Math.random() * 100);
            chart.data.labels.push("Label" + i);
            var newwidth = $('.chartAreaWrapper2').width() + 60;
            $('.chartAreaWrapper2').width(newwidth);
        }
    }

    var chartData = {
        labels: generateLabels(),
        datasets: [{
            label: "Test Data Set",
            data: generateData()
        }]
    };



    $(function () {
        var rectangleSet = false;

        var canvasTest = $('#chart-Test');
        var chartTest = new Chart(canvasTest, {
            type: 'bar',
            data: chartData,
            maintainAspectRatio: false,
            responsive: true,
            options: {
                tooltips: {
                    titleFontSize: 0,
                    titleMarginBottom: 0,
                    bodyFontSize: 12
                },
                legend: {
                    display: false
                },
                scales: {
                    xAxes: [{
                        ticks: {
                            fontSize: 12,
                            display: false
                        }
                    }],
                    yAxes: [{
                        ticks: {
                            fontSize: 12,
                            beginAtZero: true
                        }
                    }]
                },
                animation: {
                    onComplete: function () {
                        if (!rectangleSet) {
                            var sourceCanvas = chartTest.chart.canvas;
                            var copyWidth = chartTest.scales['y-axis-0'].width;
                            var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
                            var targetCtx = document.getElementById("axis-Test").getContext("2d");
                            targetCtx.canvas.width = copyWidth;
                            targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);

                            var sourceCtx = sourceCanvas.getContext('2d');
                            sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
                            rectangleSet = true;
                        }
                    },
                    onProgress: function () {
                        if (rectangleSet === true) {
                            var copyWidth = chartTest.scales['y-axis-0'].width;
                            var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;

                            var sourceCtx = chartTest.chart.canvas.getContext('2d');
                            sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
                        }
                    }
                }
            }
        });
        addData(5, chartTest);
    });
});
.chartWrapper {
  position: relative;
}

.chartWrapper > canvas {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}

.chartAreaWrapper {
  width: 600px;
  overflow-x: scroll;
}
<script src="https://github.com/chartjs/Chart.js/releases/download/v2.6.0/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chartWrapper">
  <div class="chartAreaWrapper">
  <div class="chartAreaWrapper2">
      <canvas id="chart-Test" height="300" width="1200"></canvas>
  </div>
  </div>
  <canvas id="axis-Test" height="300" width="0"></canvas>
</div>

When I use this in my angular example , it does not work anymore, the axis does not follow the scroll

Here's a stackblitz reproduction


Solution

  • In your StackBlitz, the section (rectanlge) of the y-axis is correctly created on the target canvas and removed from the source canvas. The problem is that the wrong div is horizontally scrolled. This can be fixed by changing the template and corresponding css.

    Please have a look at the following StackBlitz.

    UPDATE (dynamic data)

    In cases where the chart component receives dynamically changing data through an @Input() property, your component needs to implement the OnChange lifecycle hook.

    See the following StackBlitz.

    Please note that this code is far from being optimized. Instead of creating the chart from scratch on every data change, you should simply update the data and options on the existing chart.