[Chartjs]-Skip chartjs tick label if they overlap

1👍

Well As far as I know, you can prevent the overlap with the config (more than you already did), BUT you could do it yourself just calculating the diff between the ticks. You would have to eyeball die minDiff, and in the tick generation return null if the ticks are too close.

I tried it in the following example:
(It is not prefect, because if there are many after each other, that are too short, "too many" ticks might be skipped)

In this example 11:29 could/should be shown, because 11:00 was not displayed.

const d0 = moment.duration('08:50:00').asMinutes();
const d1 = moment.duration('09:00:00').asMinutes();
const d2 = moment.duration('10:45:00').asMinutes();
const d22 = moment.duration('11:00:00').asMinutes();
const d23 = moment.duration('11:29:00').asMinutes();
const d3 = moment.duration('17:35:00').asMinutes();
const d4 = moment.duration('19:00:00').asMinutes();
let values = [d0, d1, d2, d22, d23, d3, d4];

let data = {
    labels: [''],
    datasets: [{
      label: 'up',
      axis: 'y',
      data: [d1],
      backgroundColor: 'red',
    },{
      label: 'down',
      axis: 'y',
      data: [d2],
      backgroundColor: 'yellow',
    },{
      label: 'uppsy',
      axis: 'y',
      data: [d22],
      backgroundColor: 'green',
    },{
      label: 'uppsy1',
      axis: 'y',
      data: [d23],
      backgroundColor: 'red',
    },{
      label: 'out',
      axis: 'y',
      data: [d3],
      backgroundColor: 'yellow',
    },{
      label: 'up',
      axis: 'y',
      data: [d4],
      backgroundColor: 'red',
    }
  ]
  };

const config = {
data,
type: 'bar',
    options:{
       plugins: {
        tooltip: {
           mode: 'dataset',
           callbacks: {
            label: function(item){
               return moment().startOf('day').add({ minute: item.raw}).format('HH:mm');
            }
          }
        },
        legend: {
          display: false,
        },
        title: {
          display: false,
        },
    },
    indexAxis: 'y',
    responsive: true,
    maintainAspectRatio: false,
    scales: {
      x: {
        min: d0,
        border: { display: false },
        ticks: {
            source: 'auto',
            maxRotation: 80,
            minRotation: 60,
            autoSkip: false, 
            callback: function(value, index, ticks) {
                let minDiff = 30;
                if(index > 0 && value - ticks[index-1].value < minDiff){
                console.info(ticks[index-1].value  - value )
                    return null;
                }
                return moment().startOf('day').add({ minute: value}).format('HH:mm');
            }
        },
        afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
      },
      y: {
        stacked: true,
        grid: { display: false },
      },
    }
  }};
  
  new Chart(document.getElementById("chart"), config);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>    
<script src="//cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>   
<div class="chart" style="height:84px; width:350px;">
    <canvas  id="chart" ></canvas>
</div>

Update –maybe better solution:

You could filter the possible ticks before drawing the ticks, this makes it easier to see, if the minDiff is applied in the correct manner.

values = values.reduce( (pre, curr, index) => {
    if(index == 0 || (curr - pre[pre.length-1] > minDiff )){
        pre.push(curr);
    } 
    return pre;
}, [])

Here the full working demo:

const d0 = moment.duration('08:50:00').asMinutes();
const d1 = moment.duration('09:00:00').asMinutes();
const d2 = moment.duration('10:45:00').asMinutes();
const d22 = moment.duration('11:00:00').asMinutes();
const d23 = moment.duration('11:29:00').asMinutes();
const d3 = moment.duration('17:35:00').asMinutes();
const d4 = moment.duration('19:00:00').asMinutes();

let minDiff = 30;
let values = [d0, d1, d2, d22, d23, d3, d4];

/* prepare the ticks */
values = values.reduce( (pre, curr, index) => {
    if(index == 0 || (curr - pre[pre.length-1] > minDiff )){
        pre.push(curr);
    } 
    return pre;
}, [])

let data = {
    labels: [''],
    datasets: [{
      label: 'up',
      axis: 'y',
      data: [d1],
      backgroundColor: 'red',
    },{
      label: 'down',
      axis: 'y',
      data: [d2],
      backgroundColor: 'yellow',
    },{
      label: 'uppsy',
      axis: 'y',
      data: [d22],
      backgroundColor: 'green',
    },{
      label: 'uppsy1',
      axis: 'y',
      data: [d23],
      backgroundColor: 'red',
    },{
      label: 'out',
      axis: 'y',
      data: [d3],
      backgroundColor: 'yellow',
    },{
      label: 'up',
      axis: 'y',
      data: [d4],
      backgroundColor: 'red',
    }
  ]
  };

const config = {
data,
type: 'bar',
    options:{
       plugins: {
        tooltip: {
           mode: 'dataset',
           callbacks: {
            label: function(item){
               return moment().startOf('day').add({ minute: item.raw}).format('HH:mm');
            }
          }
        },
        legend: {
          display: false,
        },
        title: {
          display: false,
        },
    },
    indexAxis: 'y',
    responsive: true,
    maintainAspectRatio: false,
    scales: {
      x: {
        min: d0,
        border: { display: false },
        ticks: {
            source: 'auto',
            maxRotation: 80,
            minRotation: 60,
            autoSkip: false, 
            callback: function(value, index, ticks) {
                return moment().startOf('day').add({ minute: value}).format('HH:mm');
            }
        },
        afterBuildTicks: axis => axis.ticks = values.map(v => ({ value: v }))
      },
      y: {
        stacked: true,
        grid: { display: false },
      },
    }
  }};
  
  new Chart(document.getElementById("chart"), config);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>    
<script src="//cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>   
<div class="chart" style="height:84px; width:350px;">
    <canvas  id="chart" ></canvas>
</div>

Leave a comment