0

I'm trying to develop a d3 navigation menu without using the normal li/ul approach. So far I have 2 levels and I'm using mouse events to trigger the changes. However, the first cycle works okay and the parent items go black on mouseout thereafter things start behaving oddly and this line doesn't execute; svg.selectAll(".lvl1").attr("fill", "black"); but the remove() process works. Have I missed something or is it hanging on an event? Any ideas that will help extend this approach to level 3 would also be appreciated. https://jsfiddle.net/sjp700/djcc6kxq/

lvl2.selectAll(".band")
        .attr("width", function (d) { return d.width; })
        .attr("height", 18)
        .style("opacity", .5) // set the element opacity
        .style("stroke", "black")
        .attr("class", "tbd")
        .style("cursor", "move")
        .on('mouseover', over2)
        .on('mouseout', out)
        .attr("link", function (d) { return d.link; });    
    }


    function out() {
        var t = d3.select(this);
        t.attr("fill", "pink")
        setTimeout(function () {
        svg.selectAll(".lvl2").remove();
        svg.selectAll(".lvl1").attr("fill", "black");
        }, 2000);    
    }
user3359706
  • 511
  • 1
  • 5
  • 16
  • you're not selecting the correct thing. Remember you're styling the rect. So select like so svg.selectAll('.lvl1 rect) – thatOneGuy Aug 30 '16 at 13:31

1 Answers1

1

As mentioned in the comments, you need to style the rect not the g element.

Updated fiddle : https://jsfiddle.net/thatOneGuy/djcc6kxq/1/

Also, I have rearranged the colouring of the rects, so previously you had :

function out() {
  var t = d3.select(this);
  t.attr("fill", "pink")
  //setTimeout(function() {
    svg.selectAll(".lvl2").remove();
    svg.selectAll(".lvl1 rect").attr("fill", "black");
 // }, 2000);
}

But change it to this to keep the last selected tab coloured pink :

function out() {

  //setTimeout(function() {
  svg.selectAll(".lvl2").remove();
  svg.selectAll(".lvl1 rect").attr("fill", "black");

  var t = d3.select(this);
  t.attr("fill", "pink")
    // }, 2000);
}

To be honest, I wouldn't use the remove as when you try mouseover the level 2 elements, because you aren't over the parent anymore, they get removed. I would just create the structure and hide all at first. Then on mouseover of parent, show children, i.e set visibility to visible and on mouseout, set visibility to hidden. Just saves you removing and then recreating elements.

thatOneGuy
  • 9,977
  • 7
  • 48
  • 90
  • Great suggestions. Any ideas on how I can select just the children of the selected parent to make visible? Previously, I filtered the data before drawing : data2 = data.filter(function (d) { return d.level === "two" && d.parent === t.attr("name"); }); – user3359706 Aug 30 '16 at 15:17
  • This works https://jsfiddle.net/sjp700/djcc6kxq/2/ but is there a better way? var t = d3.select(this); var parent = t.attr("name") var subset = svg.selectAll(".lvl2 rect") .filter(function (d) { return d.parent === parent; }); subset.style("visibility", "visible"); – user3359706 Aug 30 '16 at 15:51
  • Whats the reason why it has to be full D3 and not use normal approach as you have said ? If you have to do it your way I recommend building a tree like structure from your data. i.e a node with children etc. See this example for unflattening your data : http://stackoverflow.com/questions/18017869/build-tree-array-from-flat-array-in-javascript And then once thats done, just loop through the data. So the top level, create a tab, then the second level create the drop down, third create a drop down to the side of the second level and so on – thatOneGuy Aug 30 '16 at 16:04
  • I think that it could be more adaptable and easier to update than the normal methods but I could be wrong! Second goal is to get a better understanding of d3 from this exercise -some success there already. Finally, it might be useful to others. However, I think I may need more help implementing your ideas. – user3359706 Aug 30 '16 at 16:26
  • Hi, This version is working https://jsfiddle.net/sjp700/djcc6kxq/3/ but after several clicks it seems to go off the rails! The time to respond varies a lot. What are the advantages from going with the tree like structure? Any ideas on how to improve this would be welcome. – user3359706 Aug 30 '16 at 18:57
  • for your new one to work, just set an on hover state for level 2 to keep level 2 rect's visible, that way they wont hide after 1 second – thatOneGuy Aug 31 '16 at 08:27
  • Not sure I understand? Do you mean by setting visibility using css? How will I selectively show/hide level 2 for the relevant level 1? – user3359706 Aug 31 '16 at 08:59