[Chartjs]-Is it possible to create context menu with chart.js?

3👍

AFAIK there is no native support for context menu from Chart.js, but you can create it using HTML and handle it.

This is an example:

var timestamp = [],
    speed = [10, 100, 20, 30, 40, 100, 40, 60];
for (var k = speed.length; k--; k>0) {
	timestamp.push(new Date().getTime()-60*60*1000*k);
}

var canvas = document.getElementById('chart');
var BB = canvas.getBoundingClientRect(),
  offsetX = BB.left,
  offsetY = BB.top; 
var ctx = canvas.getContext("2d");
var data = {
  labels: timestamp,
  datasets: [{
      data: speed,
      label: "speed",
      backgroundColor: ['rgba(0, 9, 132, 0.2)'],
      borderColor: ['rgba(0, 0, 192, 1)'],
      borderWidth: 1,
    }
  ]
};
var options = {
  scales: {
    yAxes: [{
      ticks: {
        beginAtZero: true,
      }
    }],
    xAxes: [{
      type: 'time',
    }]
  }
};

var chart = new Chart(ctx, {
  type: 'line',
  data: data,
  options: options
});

var $menu = $('#contextMenu');
canvas.addEventListener('contextmenu', handleContextMenu, false);
canvas.addEventListener('mousedown', handleMouseDown, false);

function handleContextMenu(e){
  e.preventDefault();
  e.stopPropagation();
  var x = parseInt(e.clientX-offsetX);
  var y = parseInt(e.clientY-offsetY);
  $menu.css({left:x,top:y});
  $menu.show();
  return(false);
}

function handleMouseDown(e){
  $menu.hide();
}

menu = function(n){
  console.log("select menu "+n);
  $menu.hide();
}
#chart {
  width: 100%;
  height: 100%;
}
#contextMenu{
  position:absolute;
  border:1px solid red;
  background:white;
  list-style:none;
  padding:3px;
}
.menu-item:hover {
  background: #dddddd;
  text-decoration: underline;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id=canvasContainer>
  <canvas id="chart"></canvas>
  <ul id="contextMenu" style="display:none;">
    <li class="menu-item" onclick="menu(1)">Menu 1</li>
    <li class="menu-item" onclick="menu(2)">Menu 2</li>
  </ul>
</div>

1👍

For anyone looking for this, @beaver’s answer does not have access to the clicked item (data point), you can save the state in onHover and use it in contextmenu.

    options: {
        events: ['click', 'mousemove'],
        onHover: function(e, fields){
            const lx = e.layerX;
            const bars = fields.filter(({_view: {x,width}}) => (x - width/2) <= lx && lx <= (x + width/2));
            const data = bars.map(({_index, _datasetIndex}) => this.data.datasets[_datasetIndex].data[_index]);
            this.hoveredItem = {bars, data, fields};
        },
    },
    plugins: [
        {
            afterInit: (chart) =>
            {
                var menu = document.getElementById("contextMenu");
                chart.canvas.addEventListener('contextmenu', handleContextMenu, false);
                chart.canvas.addEventListener('mousedown', handleMouseDown, false);

                function handleContextMenu(e){
                    e.preventDefault();
                    e.stopPropagation();
                    menu.style.left = e.clientX + "px";
                    menu.style.top = e.clientY + "px";
                    menu.style.display = "block";
                    console.log(chart.hoveredItem);
                    return(false);
                }

                function handleMouseDown(e){
                    menu.style.display = "none";
                }
            }
        }
    ],

https://codepen.io/elizzk/pen/xxZjQvJ

Leave a comment