6

I would like to have custom context menu appearing when I right click on an svg circle. For now I have found this answer that helps me to handle the right click with the following code:

.on("contextmenu", function(data, index) {
   //handle right click

   //stop showing browser menu
   d3.event.preventDefault()
});

Now I would like to know how I can show a box containing some HTML.

Thanks in advance.

Community
  • 1
  • 1
Christopher Chiche
  • 15,075
  • 9
  • 59
  • 98

2 Answers2

14
d3.select('#stock_details .sym').on("contextmenu", function(data, index) {
    var position = d3.mouse(this);
    d3.select('#my_custom_menu')
      .style('position', 'absolute')
      .style('left', position[0] + "px")
      .style('top', position[1] + "px")
      .style('display', 'block');

    d3.event.preventDefault();
});
meetamit
  • 24,727
  • 9
  • 57
  • 68
  • Thanks for your answer. However I really don't see how it would help me know how to have a context menu appearing on right click. – Christopher Chiche Oct 26 '12 at 17:44
  • Ok, somehow I mis-read that you wanted to custom-build a context menu, using svg. Now I see that's not the case. – meetamit Oct 26 '12 at 18:55
  • Assuming the html element you want to show is created already, and is just hidden (via css `display:none`) and has an attribute `id="my_custom_menu"` then, inside the "contextmenu" handler you put something like `d3.select('#my_custom_menu').style('display', 'block')` and it would show up. – meetamit Oct 26 '12 at 19:01
  • The problem is that when you write click, you want the menu to appear where you right click. – Christopher Chiche Oct 27 '12 at 13:34
  • I fixed the positioning by using the mouse but had to zero down padding/margin of my context-menu item var position = d3.mouse(this); d3.select('#context-menu') .style('left', position[0] + "px") .style('top', position[1] + "px") – Clemens Tolboom Sep 23 '13 at 08:59
  • @ClemensTolboom Agreed! Apparently it's too late for me to approve the edit you submitted, so I modified the answer to match your suggestion. – meetamit Sep 27 '13 at 19:48
  • I've created an [example on github / blocks](http://bl.ocks.org/clemens-tolboom/7229863). The positioning is still puzzling me. How will it be on a tablet or phone. – Clemens Tolboom Oct 30 '13 at 10:12
  • @ClemensTolboom The question is how would you expect the user to invoke the context menu on a mobile device? The assumption here was that this code will run on a device with support for contextmenu events. Maybe tablets do support this event ([see here](https://discussions.apple.com/thread/3127522)). I don't know bc I've never tried. Alternatively, you'd have to come up with another gesture for triggering your `context` method on mobile. Could be as simple as a click (tap) event. – meetamit Oct 30 '13 at 21:53
3

Just a comment on the accepted answer (don't have enough points to comment directly). But it seems like the newest version of d3 requires d3.event.pageX and d3.event.pageY instead of just x and y. Per the documentation here.

So my code is (with some IE help from this site):

.on('contextmenu', function(data, index) {
      if (d3.event.pageX || d3.event.pageY) {
          var x = d3.event.pageX;
          var y = d3.event.pageY;
      } else if (d3.event.clientX || d3.event.clientY) {
          var x = d3.event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
          var y = d3.event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
      }

      d3.select('#action_div')
        .style('position', 'absolute')
        .style('left', x + 'px')
        .style('top', y + 'px')
        .style('display', 'block');

      d3.event.preventDefault();
  })
user
  • 4,651
  • 5
  • 32
  • 60
  • Reading on https://github.com/mbostock/d3/wiki/Selections#wiki-d3_event it suggest to use either "d3.mouse();" or d3.touch()" and not to use pageX. I did "var position = d3.mouse(this);" which works fine afaik. – Clemens Tolboom Sep 17 '13 at 15:22