D3js - Gráfico direcionado à força - destaque avançado dos nós e links vizinhos, é possível?
Eu consegui destacar o trabalho no meu gráfico dirigido por força, com a ajuda deeste tutorial de Mike Bostock. Agora para mais procedimentos na minha ideia e necessidades do meu gráfico, estou um pouco preso, em primeiro lugar porque ainda estou nooby sobre o d3js e segundo, não encontrei nada parecido ainda.
Para limpar minhas intenções, você pode ver o gráfico atual com destaque no seguinte link:http://jsfiddle.net/2FwSY/
Funciona muito bem, mas minha ideia é um pouco avançada. Eu queria saber se é possível ajustar o realce de tal forma que ao passar o mouse para o nó, ele realçaria os links desse nó para os nós vizinhos, os nós vizinhos e também os links dos nós vizinhos para os nós vizinhos.
Precisamente, no meu exemplo jsfiddle. Se você passar o mouseBNG
, BNG
, YHO
, CEO
e tudolinks between them
fica em destaque. O problema é que os pequenos nós azuis que eu estou usando como "conexão" entre nós maiores, meu destaque por enquanto fica "cortado" neles porque eles são nós de fato. Também parece-me que seria necessário umIF
declaração que diria se o nó pairado é aquele pequeno ou maior, porque eu quero que higllight em que nós um pouco de conexão está funcionando como se funciona agora ..
Eu não sei de onde começar, então qualquer sugestão ou conselho é bem vindo ...
script completo se parece com isso:
var data = {"nodes":[
{"name":"YHO", "full_name":"Yahoo", "type":1, "slug": "www.yahoo.com", "entity":"company", "img_hrefD":"", "img_hrefL":""},
{"name":"GGL", "full_name":"Google", "type":2, "slug": "www.google.com", "entity":"company", "img_hrefD":"", "img_hrefL":""},
{"name":"BNG", "full_name":"Bing", "type":2, "slug": "www.bing.com", "entity":"company", "img_hrefD":"", "img_hrefL":""},
{"name":"YDX", "full_name":"Yandex", "type":2, "slug": "www.yandex.com", "entity":"company", "img_hrefD":"", "img_hrefL":""},
{"name":"Desc1", "type":4, "slug": "", "entity":"description"},
{"name":"Desc2", "type":4, "slug": "", "entity":"description"},
{"name":"Desc4", "type":4, "slug": "", "entity":"description"},
{"name":"CEO", "prefix":"Mr.", "fst_name":"Jim", "snd_name":"Bean", "type":3, "slug": "", "entity":"employee"},
{"name":"ATT", "prefix":"Ms.", "fst_name":"Jenna", "snd_name":"Jameson", "type":3, "slug": "", "entity":"employee"},
{"name":"CTO", "prefix":"Mr.", "fst_name":"Lucky", "snd_name":"Luke", "type":3, "slug": "", "entity":"employee"},
{"name":"CDO", "prefix":"Ms.", "fst_name":"Pamela", "snd_name":"Anderson", "type":3, "slug": "", "entity":"employee"},
{"name":"CEO", "prefix":"Mr.", "fst_name":"Nacho", "snd_name":"Vidal", "type":3, "slug": "", "entity":"employee"},
{"name":"Desc5", "type":4, "slug": "", "entity":"description"},
],
"links":[
{"source":0,"target":4,"value":1,"distance":5},
{"source":0,"target":5,"value":1,"distance":5},
{"source":0,"target":6,"value":1,"distance":5},
{"source":1,"target":4,"value":1,"distance":5},
{"source":2,"target":5,"value":1,"distance":5},
{"source":3,"target":6,"value":1,"distance":5},
{"source":7,"target":3,"value":10,"distance":6},
{"source":8,"target":3,"value":10,"distance":6},
{"source":9,"target":1,"value":10,"distance":6},
{"source":10,"target":1,"value":10,"distance":6},
{"source":11,"target":12,"value":10,"distance":6},
{"source":12,"target":2,"value":10,"distance":6},
]
}
var w = 560,
h = 500,
radius = d3.scale.log().domain([0, 312000]).range(["10", "50"]);
var vis = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
//vis.append("defs").append("marker")
//.attr("id", "arrowhead")
//.attr("refX", 22 + 3) /*must be smarter way to calculate shift*/
//.attr("refY", 2)
//.attr("markerWidth", 6)
//.attr("markerHeight", 4)
//.attr("orient", "auto")
//.append("path")
//.attr("d", "M 0,0 V 4 L6,2 Z"); //this is actual shape for arrowhead
//d3.json(data, function(json) {
var force = self.force = d3.layout.force()
.nodes(data.nodes)
.links(data.links)
.linkDistance(function(d) { return (d.distance*10); })
//.friction(0.5)
.charge(-250)
.size([w, h])
.start();
var link = vis.selectAll("line.link")
.data(data.links)
.enter().append("svg:line")
.attr("class", function (d) { return "link" + d.value +""; })
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; })
.attr("marker-end", function(d) {
if (d.value == 1) {return "url(#arrowhead)"}
else { return " " }
;});
function openLink() {
return function(d) {
var url = "";
if(d.slug != "") {
url = d.slug
} //else if(d.type == 2) {
//url = "clients/" + d.slug
//} else if(d.type == 3) {
//url = "agencies/" + d.slug
//}
window.open("//"+url)
}
}
var node = vis.selectAll("g.node")
.data(data.nodes)
.enter().append("svg:g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("class", function(d){ return "node type"+d.type})
.attr("r",function(d){if(d.entity == "description"){ return 6 } else { return 18 }})
//.on("mouseover", expandNode);
//.style("fill", function(d) { return fill(d.type); })
node.append("text")
.attr("class", function(d){ return "nodetext title_"+d.name })
.attr("dx", 0)
.attr("dy", ".35em")
.style("font-size","10px")
.attr("text-anchor", "middle")
.style("fill", "white")
.text(function(d) { if (d.entity != "description"){return d.name} });
node.on("mouseover", function (d) {
if (d.entity == "company"){
d3.select(this).select('text')
.transition()
.duration(300)
.text(function(d){
return d.full_name;
})
.style("font-size","15px")
}
else if(d.entity == "employee"){
var asdf = d3.select(this);
asdf.select('text').remove();
asdf.append("text")
.text(function(d){return d.prefix + ' ' + d.fst_name })
.attr("class","nodetext")
.attr("dx", 0)
.attr("dy", ".35em")
.style("font-size","5px")
.attr("text-anchor", "middle")
.style("fill", "white")
.transition()
.duration(300)
.style("font-size","12px");
asdf.append("text").text(function(d){return d.snd_name })
.attr("class","nodetext")
.attr("transform","translate(0, 12)")
.attr("dx", 0)
.attr("dy", ".35em")
.style("font-size","5px")
.attr("text-anchor", "middle")
.style("fill", "white")
.transition()
.duration(300)
.style("font-size","12px");
}
else {
d3.select(this).select('text')
.transition()
.duration(300)
.style("font-size","15px")
}
if (d.entity == "company") {
d3.select(this).select('image')
.attr("width", "90px")
.attr("x", "-46px")
.attr("y", "-36.5px")
.attr("xlink:href", function (d) {
return d.img_hrefL
});
}
if (d.entity == "company") {
d3.select(this).select('circle')
.transition()
.duration(300)
.attr("r",28)
}
else if (d.entity == "employee"){
d3.select(this).select('circle')
.transition()
.duration(300)
.attr("r",32)
}
})
node.on("mouseout", function (d) {
if (d.entity == "company") {
d3.select(this).select('text')
.transition()
.duration(300)
.text(function(d){return d.name;})
.style("font-size","10px")
}
else if(d.entity == "employee"){
///////////////////////////
// CHANGE
///////////////////////////
d3.select(this).selectAll('text').remove();
//d3.select(this).select('text')
d3.select(this).append('text')
.text(function(d){return d.name;})
.style("font-size","14px")
.attr("dx", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.style("fill", "white")
.attr("class","nodetext")
.transition()
.duration(300)
.style("font-size","10px")
}
else {
d3.select(this).select('text')
.transition()
.duration(300)
.style("font-size","10px")
}
if (d.entity == "company") {
d3.select(this).select('image')
.attr("width", "70px")
.attr("x", "-36px")
.attr("y", "-36px")
.attr("xlink:href", function (d) {
return d.img_hrefD
});
}
if (d.entity == "company" || d.entity == "employee") {
d3.select(this).select('circle')
.transition()
.duration(300)
.attr("r",18)
}
});
node.on("mouseover", fade(.4,"red"))
.on("mouseout", fade(1));
var linkedByIndex = {};
data.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
function fade(opacity,color) {
return function(d) {
node.style("stroke-opacity", function(o) {
thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
})
.style("stroke", function(o) {
return o.source === d || o.target === d ? color : "#000" ;
});
};
}
//});