Protovis Treemap - Показывать метки при наведении

У меня есть карта дерева, которую я создал. Теперь я пытаюсь заставить ховер работать правильно. Я хотел бы, чтобы текст для каждого treemap.leaf появлялся только тогда, когда пользователь наводит курсор на этот конкретный лист.

Я безуспешно пытался следовать этому примеру http://mbostock.github.com/protovis/docs/interaction.html

Код, который у меня есть до сих пор, выглядит следующим образом:

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();

person Josh O'Bryan    schedule 21.09.2011    source источник


Ответы (1)


Здесь есть несколько вопросов:

  • Когда вы используете метод .event(), и функция, которую вы передаете, возвращает экземпляр pv.Mark, Protovis повторно визуализирует метку и ее дочерние элементы. (Документация довольно непрозрачна в отношении требования, чтобы вы возвращали метку, которую хотите повторно отобразить.)

  • В макете Древовидной карты метки не являются дочерними узлами — они представляют собой отдельную группу дочерних элементов макета. Поэтому, когда вы обновляете узел, вы не получите соответствующую метку для повторного рендеринга.

  • У вас опечатка в строке:

    .fillStyle(function(d) d.active ? "lightcoral" : color(d))
    

    d - это данные, а не экземпляр. Должен быть:

    .fillStyle(function() this.active() ? "lightcoral" : color(d))
    

    Но, как отмечалось выше, это все равно не обновит метку (и хотя я не слишком много играл с этим, просто исправление этой строки, кажется, выделяет все узлы, а не только тот, который вы закончили).

Итак, чтобы все это исправить, вы хотите установить active на treemap, а не на узел. Вместо того, чтобы просто использовать true/false, вы можете установить индекс активного узла, а затем использовать тот же индекс для ссылки на метку:

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;
 });

Здесь работает jsFiddle.

Недостатком здесь является то, что вы каждый раз перерисовываете всю карту дерева. Я думаю, что, вероятно, есть способ перерисовать только конкретный узел и метку, но это будет более сложно, поэтому, если производительность не кажется проблемой, я бы не стал беспокоиться.

person nrabinowitz    schedule 26.09.2011