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:

relationship chart

the goals:

  1. i want show relationships between industry nodes/size nodes , product nodes.

  2. when hover product node, want highlight link, source (industry or size) , target (product) of each relevant relationship.

  3. when hover industry or size node, want highlight it's links relevant products.

the questions

  1. how draw links? know somehow involves using d3.map... can't figure out.

  2. how highlight nodes , links (goals 2 , 3)?

  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 , replaced type level lvl. replaced industriy, product , size category called nodes.

  • each rectangle , line in svg created in javascript file setup id 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

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -