2

I have a datetime series along the x axis of a chart in Chart.js but have changed the position of the tick / labels to be between the bars according to the method here:

Chart.js : How I change the x axes ticks labels alignment in any sizes?

This resulted in the datetimes moving to the right of the bar they related to, whereas I needed them on the left. So I changed the return calculation to subtract the amount instead of add:

var TimeCenterScale = Chart.scaleService.getScaleConstructor('time').extend({
    getPixelForTick: function(index) {
        var ticks = this.getTicks();
        if (index < 0 || index >= ticks.length) {
            return null;
        }
        // Get the pixel value for the current tick.
        var px = this.getPixelForOffset(ticks[index].value);

        // Get the next tick's pixel value.
        var nextPx = this.right;
        var nextTick = ticks[index + 1];
        if (nextTick) {
            nextPx = this.getPixelForOffset(nextTick.value);
        }

        // Align the labels in the middle of the current and next tick.
        return px - (nextPx - px) / 2;
    },
});

This mostly works except for the last column. How can I align this last column correctly?

enter image description here

James
  • 103
  • 2
  • 9

3 Answers3

2

I think the problem is at these lines

    var nextPx = this.right;
    var nextTick = ticks[index + 1];
    if (nextTick) {
       nextPx = this.getPixelForOffset(nextTick.value);
       return px - (nextPx - px) / 2;
    }
    else{
       var prevTick = ticks[index - 1];
       prevPx = this.getPixelForOffset(prevTick .value);
       return px - (px - prevPx ) / 2;
//       return px + (px - prevPx ) / 2;   if the above statement don't work

    }

When nextTick is null, nextPx takes the value of this.right which creates problem. You have to add an else block for nextTick to handle the rightmost label. I updated the code for else block. Its just an idea, you may find a better way.

DevLoverUmar
  • 11,809
  • 11
  • 68
  • 98
  • I think you're right. I think I have a solution now, although it seems like a bit of a hack! I'll post a reply – James Jun 23 '20 at 20:30
0

You could simply define offset: true on your x-axes as follows:

options: {
  scales: {
    xAxes: [{
      offset: true,
      ...

Please have a look at below runnable code snippet.

new Chart("chart", {
  type: 'bar',
  data: {
    labels: ["2020-05-13", "2020-05-11", "2020-05-12", "2020-05-14", "2020-05-09", "2020-05-10"],
    datasets: [{
      label: "My Dataset",
      backgroundColor: "#02a499",
      borderColor: "#ffffff",
      borderWidth: 1,
      hoverBackgroundColor: "#02a499",
      hoverBorderColor: "#02a499",
      data: [20, 11, 9, 22, 11, 9]
    }]
  },
  options: {
    scales: {
      xAxes: [{
        offset: true,
        type: 'time',
        time: {
          unit: 'day',
          source: 'data',
          tooltipFormat: 'MMM DD'
        },
        gridLines: {
          display: false
        }
      }],
      yAxes: [{
        ticks: {
          beginAtZero: true
        },
        gridLines: {
          display: false
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="chart" height="120"></canvas>
uminder
  • 23,831
  • 5
  • 37
  • 72
  • I already have `offset: true` in the options for the x axis. Without this the bars are not contained in the graph on either end, but the ticks are in the correct position! – James Jun 23 '20 at 20:05
0

Based on @MuhammadUmarFarooq answer I implemented the following code to check for the previous tick if there isn't a next one. I am using distribution: 'series' so all the ticks on the x axis should be the same distance so I just to calculate the distance between any two.

// Get the next tick's pixel value.
        var nextPx = this.right;
        var nextTick = ticks[index + 1];
        if (nextTick) {
            nextPx = this.getPixelForOffset(nextTick.value);
        } else {
            var previousPx = this.left;
            var previousTick = ticks[index - 1];
            previousPx = this.getPixelForOffset(previousTick.value);
            return previousPx + (px - previousPx) / 2;
        }
James
  • 103
  • 2
  • 9
  • I want to upvote your answer but this last statement doesn't make sense to me return previousPx + (px - previousPx) / 2; – DevLoverUmar Jun 24 '20 at 10:54
  • 1
    The problem is that there is no next tick, so I can't re-align the last tick on the x-axis using the nextPx value. Because the distance between each tick is the the same, I can use the previous ticks value, but instead of subtracting half of the difference between the current and next tick value, I add half the difference between the previous and current tick value, which amounts to the same thing (if there had been a next tick). Hope that makes sense! – James Jun 29 '20 at 17:22