0

How can I move my labels on my x axes in between another x axes label. Nothing seems to work and I was unable to find anything on the docs. Is there a workaround? I'm using line chart time series. https://www.chartjs.org/samples/latest/scales/time/financial.html

Currently, with the code I have its generating the figure below:

var cfg = {
            elements:{
                point: {
                    radius: 4
                }
            },
            data: {
                datasets: [
                    {
                        label: 'vsy',
                        backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
                        borderColor: window.chartColors.red,
                        data: firstData,
                        type: 'line',
                        pointRadius: 2,
                        fill: false,
                        lineTension: 0,
                        borderWidth: 2
                    },
                    {
                        label: 'de vsy',
                        backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
                        borderColor: window.chartColors.blue,
                        data: dataMaker(15),
                        type: 'line',
                        pointRadius: 2,
                        fill: false,
                        lineTension: 0,
                        borderWidth: 2
                    }
                ],

            },
            options: {

                animation: {
                    duration: 0
                },
                scales: {
                    xAxes: [{
                        type: 'time',
                        distribution: 'series',
                        offset: true,

                        time: {
                            unit: 'month',
                            displayFormats: {                                
                                month: 'MMM'
                            }
                        },

                        ticks: {

                            autoSkip: true,
                            autoSkipPadding: 75,

                            sampleSize: 100
                        },

                    }],
                    yAxes: [{
                        gridLines: {
                            drawBorder: false
                        }

                    }]
                },
                tooltips: {
                    intersect: false,
                    mode: 'index',

                }
            }
        };

This is what I have now: Original

I want the labels on the x-axis to be on center instead of below the y axis grid line. Expected

Thanks to uminder, with his comment it solves the issue but now I have a conflicting tooltip which lie on a same grid. When I hover to april line first point it shows me mar 30 which lies just above it and vice versa. enter image description here

I fixed it by changing the mode to nearest but why is it activating the another point? enter image description here

rakesh shrestha
  • 1,335
  • 19
  • 37

2 Answers2

4

The option you're looking for is offsetGridLines.

If true, grid lines will be shifted to be between labels.

xAxes: [{
  ... 
  gridLines: {
    offsetGridLines: true
  }

In most cases, this produces the expected result. Unfortunately it doesn't work for time axes as documented in Chart.js issue #403. Thanks to Antti Hukkanen, there exists a workaround.

Please have a look at below runnable code snippet to see how it works.

function generateData() {
  var unit = 'day';
  function randomNumber(min, max) {
    return Math.random() * (max - min) + min;
  }

  function randomPoint(date, lastClose) {
    var open = randomNumber(lastClose * 0.95, lastClose * 1.05).toFixed(2);
    var close = randomNumber(open * 0.95, open * 1.05).toFixed(2);
    return {
      t: date.valueOf(),
      y: close
    };
  }
    
  var date = moment().subtract(1, 'years');
  var now = moment();
  var data = [];
  for (; data.length < 600 && date.isBefore(now); date = date.clone().add(1, unit).startOf(unit)) {    
    data.push(randomPoint(date, data.length > 0 ? data[data.length - 1].y : 30));
  }
  return data;
}

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;
  },
});
// Register the scale type
var defaults = Chart.scaleService.getScaleDefaults('time');
Chart.scaleService.registerScaleType('timecenter', TimeCenterScale, defaults);

var cfg = {
  data: {
    datasets: [{
      label: 'CHRT - Chart.js Corporation',
      backgroundColor: 'red',
      borderColor: 'red',
      data: generateData(),
      type: 'line',
      pointRadius: 0,
      fill: false,
      lineTension: 0,
      borderWidth: 2
    }]
  },
  options: {
    animation: {
      duration: 0
    },
    scales: {
      xAxes: [{
        type: 'timecenter',
        time: {
          unit: 'month',
          stepSize: 1,
          displayFormats: {
            month: 'MMM'
          }
        },
        gridLines: {
          offsetGridLines: true
        }
      }],
      yAxes: [{
        gridLines: {
          drawBorder: false
        }
      }]
    },
    tooltips: {
      intersect: false,
      mode: 'index'
    }
  }
};
var chart = new Chart('chart1', cfg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart1" height="90"></canvas>
uminder
  • 23,831
  • 5
  • 37
  • 72
  • hey Thanks bunch. I have updated my question a bit. I ran into a problem and I wondered if it's occuring with what we changed. – rakesh shrestha May 17 '20 at 16:29
  • @Rey Young: My answer describes a work around for an existing bug in the Chart.js library. This workaround really only addresses the labels offset and it's perfectly possible that the new tooltip issue is related to it. I'm glad, using `mode: 'nearest'` solved this tooltip problem. – uminder May 18 '20 at 03:36
0

For chartJs v3 you can use offset property:

scales: {
  x: {
    grid: {
        offset: true
    }
  },
...
}
Yassin Mokni
  • 354
  • 1
  • 6
  • 16