Chartjs-Prevent zoom after drag

2👍

It’s a bit hacky but if you’re wanting to have the drag functionality without zoom why not just set the threshold? The docs don’t explicitly describe it, but setting the threshold to 1px wider than the canvas worked for me.

< EDIT >
Updated code after Tigran provided input. Added an eventListener on the Chart object for pointerdown and pointerup. Doing so we are able to grab the xAxes label and y value on nearest event position.
</ EDIT >

Working Codepen: https://codepen.io/vpolston/pen/KKRmOeO

JS

const data = [22,52,23,66,12,62,86,94,23,52,22,52];
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul","Aug", "Sep", "Oct", "Nov", "Dec"];

const ctx = document.getElementById('myChart').getContext('2d');

const myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: labels,
    datasets: [{
      label: 'myData',
      data: data
    }]
  },
  options: {
    plugins: {
      zoom: {
        zoom: {
          drag: {
            enabled: true,
            threshold: 801, // set threshold as described in docs: https://www.chartjs.org/chartjs-plugin-zoom/latest/guide/options.html#drag-options
          },
          mode: 'x',
        }
      }
    }
  }
});

/* 

add event listeners for pointerdown and pounterup
using if statements to ensure only events within chartArea are valid
const start_label/end_label = the value of the xAxes label
const start_y_value/end_y_value = the value of the y cordinate for that event

*/
myChart.canvas.addEventListener('pointerdown', event => {
  
  if(event.offsetX >= myChart.chartArea.left){
    
    const datas = myChart.getElementsAtEventForMode(event, 'index', {
    
    intersect: false
    
  });
  
  const start_y_value = datas[0].element.$context.parsed.y;
  const x_index = myChart.scales.x.getValueForPixel(event.offsetX);
  const start_label = myChart.data.labels[x_index];
    
  document.getElementById("startVals").innerHTML = start_label + ' ' + start_y_value;
    
  }
  
});

myChart.canvas.addEventListener('pointerup', event => {
  
  if(event.offsetX <= myChart.chartArea.right){
    
    const datas = myChart.getElementsAtEventForMode(event, 'index', {
    
    intersect: false
    
  });
  
  const end_y_value = datas[0].element.$context.parsed.y;
  const x_index = myChart.scales.x.getValueForPixel(event.offsetX);
  const end_label = myChart.data.labels[x_index];
  
  document.getElementById("endVals").innerHTML = end_label + ' ' + end_y_value;
    
  }

});


HTML

<!-- Canvas -->
<div class="chartContainer">
  <canvas id="myChart"></canvas>
</div>
<p><strong>Start axes label & value: </strong><span id="startVals"></span></p>
<p><strong>End axes label & value: </strong><span id="endVals"></span></p>

<!-- include Chart.js 3.9.1  -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.js" integrity="sha512-d6nObkPJgV791iTGuBoVC9Aa2iecqzJRE0Jiqvk85BhLHAPhWqkuBiQb1xz2jvuHNqHLYoN3ymPfpiB1o+Zgpw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<!-- include chartjs-plugin-zoom -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.2.1/chartjs-plugin-zoom.js" integrity="sha512-7X7B4dUsqfSxUe5m8NELendyUKx+xwZg4wSFECgBIPGaMSLS6e6oDGkxfJsFOlPADqIwkrP/pI9PihypuWFbEw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

CSS

.chartContainer {
  width: 800px;
  height: 400px;
}

Alternatively you go a bit more advanced by not using the plugin and doing a custom overlay canvas like Jony outlined here https://stackoverflow.com/a/46282218/9306152.

Hopefully that helps. If so please mark answered 🙂

Leave a comment