单击D3简单下拉菜单

时间:2016-03-05 10:50:44

标签: d3.js

我无法在任何地方找到直接的答案。如何在单击svg圈时显示下拉菜单?在点击形状之前我不希望它显示。有谁可以帮助我吗?

2 个答案:

答案 0 :(得分:6)

下载此内容并加入您的html:https://github.com/patorjk/d3-context-menu

点击一个圆圈即可使用

circle.on('contextmenu', d3.contextMenu(menu)); // attach menu to element

如果你想要插件,那就是:)

修改

没有插件

如果您不想要插件只需创建要显示的内容列表,请阻止默认行为,右键单击显示创建的列表,然后单击其他任何位置隐藏它。

这是一个小提琴(不是我的):http://jsfiddle.net/thatoneguy/u2kJq/727/

他创建的列表:

<ul class='custom-menu'>
  <li data-action = "first">First thing</li>
  <li data-action = "second">Second thing</li>
  <li data-action = "third">Third thing</li>
</ul>

这将在右键单击时显示。现在要使用D3实现此功能,您可以像上面的小提琴一样使用event.preventDefault();,您必须使用d3.event.preventDefault();。您还必须定位菜单,因此将css顶部和左侧更改为鼠标位置的位置:

 css({
      top: d3.event.pageY + "px",
      left: d3.event.pageX + "px"
    });

以下是我所描述的简单实现:

var w = 500;
var h = 50;

var dataset = [5, 10, 15, 20, 25];

var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var circles = svg.selectAll("circle")
  .data(dataset)
  .enter()
  .append("circle");

circles.attr("cx", function(d, i) {
    return (i * 50) + 25;
  })
  .attr("cy", h / 2)
  .attr("r", function(d) {
    return d;
  })
  .on("contextmenu", function(event) {

    // Avoid the real one
   d3.event.preventDefault();

    // Show contextmenu
    $(".custom-menu").finish().toggle(100).

    // In the right position (the mouse)
    css({
      top: d3.event.pageY + "px",
      left: d3.event.pageX + "px"
    });
  });;




//$(document).bind


// If the document is clicked somewhere
$(document).bind("mousedown", function(e) {

  // If the clicked element is not the menu
  if (!$(e.target).parents(".custom-menu").length > 0) {

    // Hide it
    $(".custom-menu").hide(100);
  }
});


// If the menu element is clicked
$(".custom-menu li").click(function() {

  // This is the triggered action name
  switch ($(this).attr("data-action")) {

    // A case for each action. Your actions here
    case "first":
      alert("first");
      break;
    case "second":
      alert("second");
      break;
    case "third":
      alert("third");
      break;
  }

  // Hide it AFTER the action was triggered
  $(".custom-menu").hide(100);
});
.custom-menu {
    display: none;
    z-index: 1000;
    position: absolute;
    overflow: hidden;
    border: 1px solid #CCC;
    white-space: nowrap;
    font-family: sans-serif;
    background: #FFF;
    color: #333;
    border-radius: 5px;
}

.custom-menu li {
    padding: 8px 12px;
    cursor: pointer;
}

.custom-menu li:hover {
    background-color: #DEF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<ul class='custom-menu'>
  <li data-action = "first">First thing</li>
  <li data-action = "second">Second thing</li>
  <li data-action = "third">Third thing</li>
</ul>
</body>

如果您想在点击其中一个菜单项时执行某些操作,可以在html中使用onclick,如下所示:

<li onclick='doSomething()' data-action = "third">Third thing</li>

或者你可以给个别项目一个这样的id:

<li id='listItemOne' data-action = "third">Third thing</li>

然后添加事件监听器:

document.getElementById('listItemOne').addEventListener('click', doSomething)

答案 1 :(得分:5)

@thisOneGuy给出了一个很好的答案,但是因为我已经编码了,所以这是一个用svg构建上下文菜单的解决方案:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.4.6" data-semver="3.4.6" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
  <style>
    svg {
      font: 12px sans-serif;
    }
  </style>
</head>

<body>

  <script>
    var menu = [{
      title: 'A really, really long item',
      action: function(elem, d, i) {
        console.log('Item #1 clicked!');
        console.log('The data for this circle is: ' + d);
      }
    }, {
      title: 'Item #2',
      action: function(elem, d, i) {
        console.log('You have clicked the second item!');
        console.log('The data for this circle is: ' + d);
      }
    }]

    var data = [1, 2, 3];

    var g = d3.select('body').append('svg')
      .on('click', function(){
        m.style('display', 'none');
      })
      .attr('width', 500)
      .attr('height', 400)
      .append('g');

    g.selectAll('circles')
      .data(data)
      .enter()
      .append('circle')
      .attr('r', 30)
      .attr('fill', 'steelblue')
      .attr('cx', function(d) {
        return 100;
      })
      .attr('cy', function(d) {
        return d * 100;
      })
      .on('contextmenu', function(d) {
        var coors = d3.mouse(this);

        m.attr('transform', 'translate(' + coors[0] + ',' + coors[1] + ')');
        m.style('display', 'block');
        m.datum(d);

        d3.event.preventDefault();
      });
    
    /* build context menu */
    var m = g.append("g")
      m.style('display', 'none');

    var r = m.append('rect')
      .attr('height', menu.length * 25)
      .style('fill', "#eee");

    var t = m.selectAll('menu_item')
      .data(menu)
      .enter()
      .append('g')
      .attr('transform', function(d, i) {
        return 'translate(' + 10 + ',' + ((i + 1) * 20) + ')';
      })
      .on('mouseover', function(d){
        d3.select(this).style('fill', 'steelblue');
      })
      .on('mouseout', function(d){
        d3.select(this).style('fill', 'black');
      })
      .on('click', function(d,i){
        d.action(d, d3.select(this.parentNode).datum(), i);
      })
      .append('text')
      .text(function(d) {
        return d.title;
      });
    
    var w = 0;
    t.each(function(d){
      var l = this.getComputedTextLength();
      if (l > w) w = l;
    })
    r.attr('width', w + 20);  
  
  </script>
</body>

</html>