2013-08-29 18 views
8

Ho creato un grafico forzato e volevo cambiare la forma dei nodi per i dati che contiene "entity":"company" in modo da avere una forma rettangolare, e l'altra senza questa parte di dati sarebbero cerchi così come sono ora.Grafico diretto a forza D3, forma diversa in base ai dati e al valore fornito?

Potete vedere il mio esempio di lavoro con soli nodi cerchio qui: http://jsfiddle.net/dzorz/uWtSk/

ho cercato di aggiungere rettangoli con if else dichiarazione nella parte del codice in cui aggiungo forma al nodo in questo modo:

function(d) 
    { 
     if (d.entity == "company") 
     { 
      node.append("rect") 
       .attr("class", function(d){ return "node type"+d.type}) 
       .attr("width", 100) 
       .attr("height", 50) 
       .call(force.drag); 
     } 
     else 
     { 
     node.append("circle") 
      .attr("class", function(d){ return "node type"+d.type}) 
      .attr("r", function(d) { return radius(d.value) || 10 }) 
      //.style("fill", function(d) { return fill(d.type); }) 
      .call(force.drag); 
     } 
    } 

Ma poi non ho avuto alcuna forma su nessun nodo.

Qual è un modo corretto per configurarlo?

L'intero codice simile a questo: script:

var data = {"nodes":[ 
         {"name":"Action 4", "type":5, "slug": "", "value":265000}, 
         {"name":"Action 5", "type":6, "slug": "", "value":23000}, 
         {"name":"Action 3", "type":4, "slug": "", "value":115000}, 
         {"name":"Yahoo", "type":1, "slug": "www.yahoo.com", "entity":"company"}, 
         {"name":"Google", "type":1, "slug": "www.google.com", "entity":"company"}, 
         {"name":"Action 1", "type":2, "slug": "",}, 
         {"name":"Action 2", "type":3, "slug": "",}, 
         {"name":"Bing", "type":1, "slug": "www.bing.com", "entity":"company"}, 
         {"name":"Yandex", "type":1, "slug": "www.yandex.com)", "entity":"company"} 
        ], 
      "links":[ 
         {"source":0,"target":3,"value":10}, 
         {"source":4,"target":3,"value":1}, 
         {"source":1,"target":7,"value":10}, 
         {"source":2,"target":4,"value":10}, 
         {"source":4,"target":7,"value":1}, 
         {"source":4,"target":5,"value":10}, 
         {"source":4,"target":6,"value":10}, 
         {"source":8,"target":4,"value":1} 
         ] 
       }  



    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", 17 + 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) 
      .distance(100) 
      .charge(-1000) 
      .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) { return radius(d.value) || 10 }) 
      //.style("fill", function(d) { return fill(d.type); }) 
      .call(force.drag); 

     node.append("svg:image") 
      .attr("class", "circle") 
      .attr("xlink:href", function(d){ return d.img_href}) 
      .attr("x", "-16px") 
      .attr("y", "-16px") 
      .attr("width", "32px") 
      .attr("height", "32px") 
      .on("click", openLink()); 

     node.append("svg:text") 
      .attr("class", "nodetext") 
      .attr("dx", 0) 
      .attr("dy", ".35em") 
      .attr("text-anchor", "middle") 
      .text(function(d) { return d.name }); 

     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 + ")"; }); 
     }); 
    //});  

css:

.link10 { stroke: #ccc; stroke-width: 3px; stroke-dasharray: 3, 3; } 
.link1 { stroke: #000; stroke-width: 3px;} 
.nodetext { pointer-events: none; font: 10px sans-serif; } 

.node.type1 { 
    fill:brown; 
} 
.node.type2 { 
    fill:#337147; 
} 
.node.type3 { 
    fill:blue; 
} 
.node.type4 { 
    fill:red; 
} 

.node.type5 { 
    fill:#1BC9E0; 
} 

.node.type6 { 
    fill:#E01B98; 
} 

image.circle { 
    cursor:pointer; 
} 

È possibile modificare il mio jsfiddle collegato sul all'inizio del post ...

+0

Sembra che tu non stia usando il codice per cambiare le forme nel tuo jsfiddle. Potresti pubblicarne uno che dimostri il problema, per favore? –

+0

Ho postato il codice problematico con if else statement above (vedi il primo blocco di codice) ... In jsfiddle ho cancellato questa affermazione così in essa puoi vedere solo le forme del cerchio – dzordz

+0

E 'davvero importante dove hai messo quel codice e come lo chiami. –

risposta

6

Soluzione qui: http://jsfiddle.net/Bull/4btFx/1/

ho avuto questo lavoro aggiungendo una classe a ciascun nodo, quindi usando "selectAll" per ogni classe per aggiungere le forme. Nel codice qui sotto, aggiungo un "nodo" di classe e una classe restituita dal mio JSON (d.type) che è "rect" o "ellipse".

var node = container.append("g") 
    .attr("class", "nodes") 
    .selectAll(".node") 
    .data(graph.nodes) 
    .enter().append("g") 
    .attr("class", function(d) { 
    return d.type + " node"; 
    }) 
    .call(drag); 

Quindi è possibile aggiungere la forma per tutti gli elementi di ogni classe:

d3.selectAll(".rect").append("rect") 
    .attr("width", window.nodeWidth) 
    .attr("height", window.nodeHeight) 
    .attr("class", function(d) { 
    return "color_" + d.class 
    }); 

    d3.selectAll(".ellipse").append("rect") 
    .attr("rx", window.nodeWidth*0.5) 
    .attr("ry", window.nodeHeight*0.5) 
    .attr("width", window.nodeWidth) 
    .attr("height", window.nodeHeight) 
    .attr("class", function(d) { 
    return "color_" + d.class 
    }); 

Nell'esempio di cui sopra, ho usato i rettangoli con raggio per disegnare le ellissi in quanto concentra allo stesso modo come il rettangoli. Ma funziona anche con altre forme. Nel jsfiddle che ho collegato, il centraggio è disattivato, ma le forme sono corrette.

0

Ho implementato questo comportamento utilizzando il metodo filter che ho ricavato da Filtering in d3.js on bl.ocks.org.

initGraphNodeShapes() { 
    let t = this; 

    let graphNodeCircles = 
    t.graphNodesEnter 
     .filter(d => d.shape === "circle") 
     .append("circle") 
     .attr("r", 15) 
     .attr("fill", "green"); 

    let graphNodeRects = 
    t.graphNodesEnter 
     .filter(d => d.shape === "rect") 
     .append("rect") 
     .attr("width", 20) 
     .attr("height", 10) 
     .attr("x", -10) // -1/2 * width 
     .attr("y", -5) // -1/2 * height 
     .attr("fill", "blue"); 

    return graphNodeCircles.merge(graphNodeRects); 
} 

ho questo all'interno di initGraphNodeShapes chiamata, perché il mio codice è relativamente grande e refactoring. t.graphNodesEnter è un riferimento alla selezione dei dati dopo la chiamata enter() di join dei dati altrove. Ping me se hai bisogno di più contesto. Inoltre, io uso la versione d => ... perché sto usando ES6 che abilita lambda. Se si utilizza pre-ES6, sarà necessario modificarlo nel modulo function(d)....

Problemi correlati