带有子菜单的D3上下文菜单

时间:2015-11-25 10:11:37

标签: javascript css d3.js contextmenu

我正在创建基于具有回调函数的javascript数组的上下文菜单,但是有两个问题

    当鼠标移动到没有子节点的元素时,
  1. 无法隐藏子菜单(在删除部分上)。

  2. 无法在适当的层次结构中显示子菜单(移动到Sibling Section后无法返回子部分的子菜单)。

    我的代码:

  3. 
    
    d3.contextMenu = function (menu, openCallback) {
    
    	// create the div element that will hold the context menu
    	d3.selectAll('.d3-context-menu').data([1])
    		.enter()
    		.append('div')
    		.attr('class', 'd3-context-menu');
    
    	// close menu
    	d3.select('body').on('click.d3-context-menu', function() {
    		d3.select('.d3-context-menu').style('display', 'none');
    	});
    
    	// this gets executed when a contextmenu event occurs
    	return function(data, index) {	
    		var elm = this;
    
    		d3.selectAll('.d3-context-menu').html('');
    		var list = d3.selectAll('.d3-context-menu').append('ul');
    	       	list.selectAll('li').data(menu).enter()
    			.append('li')
    			.html(function(d) {
    				return d.title;
    			})
    			.on('click', function(d, i) {
    				d.onMouseClick(elm, data, index);
    			})
                .on('mouseover',function(d,i){
                    d.onMouseOver(elm,data,index);
                    if(d.chidernItems.length>0 )
                         {
                          d3.select(this).selectAll("ul").remove(); 
                          d3.select(this)
                            .append("ul")
                            .selectAll("li")
                               .data(d.chidernItems)
                                .enter().append("li")
                                  .text(function(d) { return d.title; })
                             .on("mouseover", function(d,i){
                                    d.onMouseOver(elm,data,index);
                                })
                             .on('click',  function(d, i) {
                                    d.onMouseClick(elm, data, index);
                                })
                             .on('mouseout',function(d,i){
                                d3.select(this).remove(); 
                                });
                         }
                     else
                         return false;
                  
                   
                })
                .on('mouseout',function(d,i){
                if(d.chidernItems.length==0 )
                    {
                       d3.select(this).selectAll("ul").remove(); 
                    }
                                      
                });
            
              
    
    		// the openCallback allows an action to fire before the menu is displayed
    		// an example usage would be closing a tooltip
    		if (openCallback) openCallback(data, index);
    
    		// display context menu
    		d3.select('.d3-context-menu')
    			.style('left', (d3.event.pageX - 2) + 'px')
    			.style('top', (d3.event.pageY - 2) + 'px')
    			.style('display', 'block');
    
    		d3.event.preventDefault();
    	};
    };
    
    var menu = [
        {
          title: 'Create Child Section',
          // Exceute Action 
          onMouseClick: function(elm, d, i) {
            console.log('Create Child Section clicked!');
            console.log('The data for this circle is: ' + d);
          },
          onMouseOver: function(elm,d,i){
              console.log('Create Child mouseover  data = ' +d );
          },
          chidernItems: [
               {
                  title: 'Vertical',
                  // Exceute Action 
                  onMouseClick: function(elm, d, i) {
                    console.log('Vertical Create Child clicked!');
                    console.log('The data for this circle is: ' + d);
                  },
                  onMouseOver: function(elm,d,i){
                      console.log('Vertical Create Child mouseover  data = ' +d );
                  }
               },
               {
                  title: 'Horizontal',
                  // Exceute Action 
                  onMouseClick: function(elm, d, i) {
                    console.log('Horizontal Create Child clicked!');
                    console.log('The data for this circle is: ' + d);
                  },
                  onMouseOver: function(elm,d,i){
                      console.log('Horizontal Create Child mouseover  data = ' +d );
                  }
               }
          ]
        }, 
        {
          title: 'Create Sibling Section',
           // Exceute Action 
          onMouseClick: function(elm, d, i) {
            console.log('Create Sibling Section clicked!');
            console.log('The data for this circle is: ' + d);
          },
          onMouseOver: function(elm,d,i){
              console.log('Sibling Section mouseover  data = ' +d );
          },
             chidernItems: [
               {
                  title: 'Vertical',
                  // Exceute Action 
                  onMouseClick: function(elm, d, i) {
                    console.log('Sibling Vertical clicked!');
                    console.log('The data for this circle is: ' + d);
                  },
                  onMouseOver: function(elm,d,i){
                      console.log('Sibling Vertical mouseover  data = ' +d );
                  }
               },
                {
                  title: 'Horizontal',
                  // Exceute Action 
                  onMouseClick: function(elm, d, i) {
                    console.log('Horizontal clicked!');
                    console.log('The data for this circle is: ' + d);
                  },
                  onMouseOver: function(elm,d,i){
                      console.log('Horizontal mouseover  data = ' +d );
                  }
               }
          ]
            
        },
        {
          title: 'Delete Section',
            
           // Exceute Action 
          onMouseClick: function(elm, d, i) {
            console.log('Delete Section Section clicked!');
            console.log('The data for this circle is: ' + d);
          },
          onMouseOver: function(elm,d,i){
              console.log('Delete Section mouseover  data = ' +d );
          },
               chidernItems: []
        }]
    
        var data = [1];
    
        var g = d3.select('body').append('svg')
          .attr('width', 200)
          .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', d3.contextMenu(menu));
    
    .d3-context-menu {
    	position: absolute;
    	display: none;
    	background-color: #f2f2f2;
    	border-radius: 4px;
    	font-family: Arial, sans-serif;
    	font-size: 14px;
    	min-width: 150px;
    	border: 1px solid #d4d4d4;
    	z-index:1200;
    }
    
    .d3-context-menu ul {
    	list-style-type: none;
    	margin: 4px 0px;
    	padding: 0px;
    	cursor: default;
    }
    
    .d3-context-menu ul li {
    	padding: 4px 16px;
    }
    
    .d3-context-menu ul li:hover {
    	background-color: #4677f8;
    	color: #fefefe;
    }
    
    
    .d3-context-menu ul li > ul {
        position: absolute; 
        background-color: #f2f2f2; 
        top: 0; 
        left: 175px;
        z-index: -1; 
    } 
    
    .d3-context-menu ul li > ul li:hover 
    { 
        background-color: #4677f8;
    	color: #fefefe;
    }
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.0/d3.min.js"></script>
    &#13;
    &#13;
    &#13;

    我每次在鼠标悬停功能中删除和创建子菜单有没有更好的方法?

1 个答案:

答案 0 :(得分:6)

通过'mouseover''mouseout'更改'mouseenter''mouseleave'函数并在mouseleave函数中引入d3.select(this).selectAll("ul").style('display', 'none');来解决此问题。