d3.js: How do I draw and highlight links in this relationship graph? -
i've been trying solve graph problem couple weeks now... still pretty new d3.js, things seem might simple still elude me.
here's illustration of i'm trying do:
the goals:
i want show relationships between industry nodes/size nodes , product nodes.
when hover product node, want highlight link, source (industry or size) , target (product) of each relevant relationship.
when hover industry or size node, want highlight it's links relevant products.
the questions
how draw links? know somehow involves using d3.map... can't figure out.
how highlight nodes , links (goals 2 , 3)?
if there better, more efficient way of getting layout , behavior, please let me know - trying hard learn tricks!
the fiddle renders basic layout simplified set of data: http://jsfiddle.net/9hgbd/
the data looks this:
var data = { "product": [ { "type": "product", "name": "product 1" }, { "type": "product", "name": "product 2" }, { "type": "product", "name": "product 3" }, { "type": "product", "name": "product 4" }, { "type": "product", "name": "product 5" } ], "industry": [ { "type": "industry", "name": "industry 1" }, { "type": "industry", "name": "industry 2" }, { "type": "industry", "name": "industry 3" }, { "type": "industry", "name": "industry 4" }, { "type": "industry", "name": "industry 5" } ], "size": [ { "type": "size", "name": "size 1" }, { "type": "size", "name": "size 2" }, { "type": "size", "name": "size 3" }, { "type": "size", "name": "size 4" }, { "type": "size", "name": "size 5" } ], "links": [ { "source": "industry 1", "target": "product 1" }, { "source": "industry 3", "target": "product 1" }, { "source": "industry 5", "target": "product 1" }, { "source": "industry 2", "target": "product 2" }, ...etc.. ] };
the javascript i'm using looks this:
function renderrelationshipgraph(){ var width = 800, boxwidth = 200, boxheight = 20, gap = 4, margin = {top: 16, right: 16, bottom: 16, left: 16}, height = (data.product.length * (boxheight + gap)) + margin.top + margin.bottom; var pnodes = []; var inodes = []; var snodes = []; var links = []; data.product.foreach(function(d, i) { d.x = ((width-margin.left-margin.right)/3)/2 - boxwidth/2; d.y = margin.top + (boxheight+ 4)*i; pnodes.push(d); }); data.industry.foreach(function(d, i) { d.x = 0; d.y = margin.top + (boxheight+ 4)*i; inodes.push(d); }); data.size.foreach(function(d, i) { d.x = ((width-margin.left-margin.right)/3) - boxwidth; d.y = margin.top + (boxheight+ 4)*i; snodes.push(d); }); var svg = d3.select("#graph").append("svg") .attr("width", width) .attr("height", height) .append("g"); svg.append("g") .attr("class", "industries"); svg.append("g") .attr("class", "products") .attr("transform", "translate("+ (width-margin.left-margin.right)/3 + ", 0)"); svg.append("g") .attr("class", "sizes") .attr("transform", "translate("+ 2*((width-margin.left-margin.right)/3) + ", 0)"); var products = svg.select(".products"); var product = products.selectall("g") .data(pnodes) .enter() .append("g") .attr("class", "unit"); product.append("rect") .attr("x", function(d) {return d.x;}) .attr("y", function(d) {return d.y;}) .attr("width", boxwidth) .attr("height", boxheight) .attr("class", "product") .attr("rx", 6) .attr("ry", 6) .on("mouseover", function() { d3.select(this).classed("active", true); }) .on("mouseout", function() { d3.select(this).classed("active", false); }); product.append("text") .attr("class", "label") .attr("x", function(d) {return d.x + 14;}) .attr("y", function(d) {return d.y + 15;}) .text(function(d) {return d.name;}); var industries = svg.select(".industries"); var industry = industries.selectall("g") .data(inodes) .enter() .append("g") .attr("class", "unit"); industry.append("rect") .attr("x", function(d) {return d.x;}) .attr("y", function(d) {return d.y;}) .attr("width", boxwidth) .attr("height", boxheight) .attr("class", "industry") .attr("rx", 6) .attr("ry", 6) .on("mouseover", function() { d3.select(this).classed("active", true); }) .on("mouseout", function() { d3.select(this).classed("active", false); }); industry.append("text") .attr("class", "label") .attr("x", function(d) {return d.x + 14;}) .attr("y", function(d) {return d.y + 15;}) .text(function(d) {return d.name;}); var sizes = svg.select(".sizes"); var size = sizes.selectall("g") .data(snodes) .enter() .append("g") .attr("class", "unit"); size.append("rect") .attr("x", function(d) {return d.x;}) .attr("y", function(d) {return d.y;}) .attr("width", boxwidth) .attr("height", boxheight) .attr("class", "size") .attr("rx", 6) .attr("ry", 6) .on("mouseover", function() { d3.select(this).classed("active", true); }) .on("mouseout", function() { d3.select(this).classed("active", false); }); size.append("text") .attr("class", "label") .attr("x", function(d) {return d.x + 14;}) .attr("y", function(d) {return d.y + 15;}) .text(function(d) {return d.name;}); } renderrelationshipgraph();
thanks on this!
ok tried make example work since have same sort of problem. sake of posterity answering here well. maybe have same problem or finds easier solution.
new javascript (tried learn bit in past week) may not best solution. files , result available in jsfiddle. i'll not provide whole codes , point changes.
in order able add arbitrary number of columns changed
json
file , replacedtype
levellvl
. replacedindustriy
,product
,size
category callednodes
.each rectangle , line in
svg
created in javascript file setupid
can referred later (when changing color).
the relevant code
data.nodes.foreach(function (d, i) { d.x = margin.left + d.lvl * (boxwidth + gap.width); d.y = margin.top + (boxheight + gap.height) * count[d.lvl]; d.id = "n" + i; count[d.lvl] += 1; nodes.push(d); }); data.links.foreach(function (d) { links.push({ source: find(d.source), target: find(d.target), id: "l" + find(d.source).id + find(d.target).id }); });
the method find
used here function finds node name passed it.
the
mouseover
,mouseout
events updated follows:.on("mouseover", function () { mouse_action(d3.select(this).datum(), true, true); }) .on("mouseout", function () { mouse_action(d3.select(this).datum(), false, true); });
it uses methods, mouse_action
accepts starting node , state (active or inactive). in method visit each link, process , change state. method traverses in both directions (left , right) on node mouse entered , traverses left or right on other nodes.
function mouse_action(val, stat, direction) { "use strict"; d3.select("#" + val.id).classed("active", stat); links.foreach(function (d) { if (direction == "root") { if (d.source.id === val.id) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color if (d.target.lvl < val.lvl) mouse_action(d.target, stat, "left"); else if (d.target.lvl > val.lvl) mouse_action(d.target, stat, "right"); } if (d.target.id === val.id) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color if (direction == "root") { if(d.source.lvl < val.lvl) mouse_action(d.source, stat, "left"); else if (d.source.lvl > val.lvl) mouse_action(d.source, stat, "right"); } } }else if (direction == "left") { if (d.source.id === val.id && d.target.lvl < val.lvl) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color mouse_action(d.target, stat, direction); } if (d.target.id === val.id && d.source.lvl < val.lvl) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color mouse_action(d.source, stat, direction); } }else if (direction == "right") { if (d.source.id === val.id && d.target.lvl > val.lvl) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color mouse_action(d.target, stat, direction); } if (d.target.id === val.id && d.source.lvl > val.lvl) { d3.select("#" + d.id).movetofront().classed("activelink", stat); // change link color d3.select("#" + d.id).movetofront().classed("link", !stat); // change link color mouse_action(d.source, stat, direction); } } }); }
Comments
Post a Comment