javascripttreemapprotovis

Protovis Treemap - Show labels on hover over


I have a treemap that I've created. Now I'm trying to get the hover over to work properly. I would like the text for each treemap.leaf to only appear when the user hovers over that particular leaf.

I've tried to follow this example to no avail http://mbostock.github.com/protovis/docs/interaction.html

The code I have so far is as follows:

var json = {
    "sectors":{
        "electronics": { "Sony": 85, "AMD": 70, "Techtronics": 20, "Apple": 220, "Microsoft": 340},
        "automotive": {"Chevy": 43, "Audi":120, "BMW": 200}},
    "ids":{"Sony":72833,"AMD":582926,"Techtronics":839261, "Apple":822463, "Microsoft":242512, "Chevy":627363, "Audi":524362,"BMW":25143}   
};

var tree = json.sectors;
var ids = json.ids;

var nodes = pv.dom(tree).root("tree").nodes();
color = pv.Colors.category10().by(function(d){return  d.parentNode.nodeName});

var vis = new pv.Panel()
 .width(400)
 .height(400)
 .canvas("test");
var treemap = vis.add(pv.Layout.Treemap)
 .nodes(nodes)
 .round(true);  

treemap.leaf.add(pv.Panel)
 .def("active", false)
 .fillStyle(function(d) d.active ? "lightcoral" : color(d))
 .strokeStyle("#fff")
 .lineWidth(1)
 .antialias(false)
 .cursor("pointer")
 .event("mouseover", function(d) { return this.active(true)});

treemap.label.add(pv.Label)
 .visible(function() {return this.parent.children[0].active()})
 .textStyle(function(d) {return pv.rgb(0, 0, 0, 1)});

vis.render();

Solution

  • There are a couple of issues here:

    So to fix all this, you want to set the active def on treemap, not on the node. Instead of just using true/false, you can set the index of the active node, and then use the same index to refer to the label:

    var treemap = vis.add(pv.Layout.Treemap)
     .nodes(nodes)
     .round(true)
     // define the active node on the layout
     .def("active", -1);  
    
    treemap.leaf.add(pv.Panel)
     .fillStyle(function(d) { 
         return treemap.active() == this.index ? "lightcoral" : color(d) 
     })
     // ...
     .event("mouseover", function() { 
         return treemap.active(this.index);
     })
     .event("mouseout", function() { 
         return treemap.active(-1);
     });
    
    treemap.label.add(pv.Label)
     .visible(function() {
         return treemap.active() == this.index;
     });
    

    Working jsFiddle here.

    The downside here is that you're re-rendering the entire treemap each time. I think there's probably a way to only re-render the specific node and label, but it would be more complex, so if the performance doesn't seem to be an issue, I wouldn't bother.