2013-12-13 2 views
4

Я использую макет, основанный на силе, используя D3, и задавался вопросом, возможно ли, что когда я нажимаю на узлы или метки, я автоматически берусь на URL-адрес, хранящийся в этом узле/метке? Если да, то как я могу это достичь?Как сделать метки и узлы в D3 принудительной компоновке, доступной для перехода к URL-адресу?

enter image description here

Это как график будет выглядеть на самом деле (метки указывают сам URL)

enter image description here

Я делюсь с яваскрипта код, который я использую для построения графика D3. В коде в настоящее время я использую фиктивные данные, которые фактически будут заменены URL-адресами.

document.addEventListener('DOMContentLoaded', function() { 
    drawVisual(); 
}); 

function drawVisual() 
{ 
    //document.getElementById('myMSG').innerHTML = "last name"+localStorage.lastname; 
    /*var getArr = []; 
    getArr = JSON.parse(localStorage.getItem('storeArray')); 
    document.getElementById('myMSG').innerHTML = getArr[1].parentURL;*/ 


    //var w = 1024, h = 768; 

    var w=window.innerWidth 
    || document.documentElement.clientWidth 
    || document.body.clientWidth; 

    var h=window.innerHeight 
    || document.documentElement.clientHeight 
    || document.body.clientHeight; 
    //var w = 1024, h = 768; 

    //var vis = d3.select("#tab_5_contents").append("svg:svg").attr("width", w).attr("height", h); 
    var vis = d3.select("#forcedLayoutGraph").append("svg:svg").attr("width", w).attr("height", h); 

      var QueuedORG = []; 
      //QueuedORG = JSON.parse(localStorage.getItem('storeArray')); 
      QueuedORG.push({url: "Root", parentURL: "Root", used:0}); 
      QueuedORG.push({url: "a", parentURL: "Root", used:0}); 
      QueuedORG.push({url: "b", parentURL: "Root", used:0}); 
      QueuedORG.push({url: "c", parentURL: "Root", used:0}); 
      QueuedORG.push({url: "d", parentURL: "Root", used:0}); 
      QueuedORG.push({url: "e", parentURL: "a", used:0}); 
      QueuedORG.push({url: "f", parentURL: "a", used:0}); 
      QueuedORG.push({url: "g", parentURL: "a", used:0}); 
      QueuedORG.push({url: "h", parentURL: "a", used:0}); 
      QueuedORG.push({url: "p", parentURL: "b", used:0}); 
      QueuedORG.push({url: "q", parentURL: "b", used:0}); 
      QueuedORG.push({url: "r", parentURL: "b", used:0}); 
      QueuedORG.push({url: "x", parentURL: "c", used:0}); 
      QueuedORG.push({url: "y", parentURL: "x", used:0}); 
      QueuedORG.push({url: "y", parentURL: "c", used:0}); 
      QueuedORG.push({url: "x", parentURL: "a"}); 
      QueuedORG.push({url: "y", parentURL: "b"}); 


      var nodes = []; 

      var labelAnchors = []; 
      var labelAnchorLinks = []; 
      var links = []; 

      for(var i = 0; i < QueuedORG.length; i++) 
      { 
       var nodeExists = 0; 

       //check to see if a node for the current url has already been created. If yes, do not create a new node 
       for(var j = 0; j < nodes.length; j++) 
       { 
        if(QueuedORG[i].url == nodes[j].label) 
         nodeExists = 1; 

       } 

       if (nodeExists == 0) 
       { 
        var urlLabel = QueuedORG[i].url; 
        //remove 'http://' part 
        /*urlLabel = urlLabel.split("http://")[1]; 
        if(urlLabel.match("www")) 
        urlLabel = urlLabel.split("www.")[1]; 
        var rest = urlLabel.split("\.")[1]; 
        urlLabel = urlLabel.split("\.")[0];*/ 

        var node = { 
         label : QueuedORG[i].url, 
         category : QueuedORG[i].category 
        }; 
        nodes.push(node); 
        labelAnchors.push({ 
         node : node 
        }); 
        labelAnchors.push({ 
         node : node 
        }); 
       } 
      }; 

      for(var i=0;i<nodes.length; i++) 
      { 
       console.log("node i:"+i+nodes[i]+"\n"); 
       console.log("labelAnchor i:"+i+labelAnchors[i]+"\n"); 
      } 

      //To create links for connecting nodes 
      for(var i = 0; i < QueuedORG.length; i++) 
      { 
       var srcIndx = 0, tgtIndx = 0; 
       for(var j = 0; j < nodes.length; j++) 
       { 
        if(QueuedORG[i].url == nodes[j].label) //to find the node number for the current url 
        { 
         srcIndx = j; 
        } 

        if(QueuedORG[i].parentURL == nodes[j].label) //to find the node number for the parent url 
        { 
         tgtIndx = j; 
        } 
       } 
       //console.log("src:"+srcIndx+" tgt:"+tgtIndx); 

       //connecting the current url's node to the parent url's node 
       links.push({ 
        source : srcIndx, 
        target : tgtIndx, 
        weight : 1, 
       }); 

       labelAnchorLinks.push({ 
        source : srcIndx * 2, 
        target : srcIndx * 2 + 1, 
        weight : 1 
       }); 
      }; 

      var force = d3.layout.force().size([w, h]).nodes(nodes).links(links).gravity(1).charge(-10000).linkStrength(function(x) { 
       return x.weight * 10           // charge is for inter-node repel, link distance is node-node distance 
      }); 
      force.linkDistance(function(d) { 
       return d.weight * 100; 
      }); 

      force.start(); 

      var force2 = d3.layout.force().nodes(labelAnchors).links(labelAnchorLinks).gravity(0).linkStrength(10).charge(-500).size([w, h]); //charge is for inter-label repel, link distance is node-label distance 
      force2.linkDistance(function(d) { 
       return d.weight * 10; 
      }); 

      force2.start(); 

      var link = vis.selectAll("line.link").data(links).enter().append("svg:line").attr("class", "link").style("stroke", "#CCC"); 

      var colors = {"1": "black", "2": "blue", "3": "red"};   // 1=root node 2=blog nodes 3=.org nodes 
      var shape = {"1": "diamond", "2": "cross", "3": "circle"}; 

      var node = vis.selectAll("g.node").data(force.nodes()).enter().append("path").attr("class", "node").call(force.drag); 
     //node.append("circle").attr("r", 5).style("stroke", "#FFF").style("stroke-width", 3).attr("class", function(d) {return "node category"+d.category}); 

      node.attr("d", d3.svg.symbol().type(function(d) {return shape[d.category];})).style("stroke", "#FFF").style("fill", function(d){ return colors[d.category];}); 

      var anchorLink = vis.selectAll("line.anchorLink").data(labelAnchorLinks)//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); 

      var anchorNode = vis.selectAll("g.anchorNode").data(force2.nodes()).enter().append("svg:g").attr("class", "anchorNode"); 
      anchorNode.append("svg:circle").attr("r", 0).style("fill", "#FFF"); 
      anchorNode.append("svg:text").text(function(d, i) { 
       return i % 2 == 0 ? "" : d.node.label 
      }).style("fill", "#555").style("font-family", "Arial").style("font-size", 12); 

      var updateLink = function() { 
       this.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; 
       }); 
      } 

      var updateNode = function() { 
       this.attr("transform", function(d) { 
        return "translate(" + d.x + "," + d.y + ")"; 
       }); 

      } 

      force.on("tick", function() { 

       force2.start(); 

       node.call(updateNode); 

       anchorNode.each(function(d, i) { 
        if(i % 2 == 0) { 
         d.x = d.node.x; 
         d.y = d.node.y; 
        } else { 
         var b = this.childNodes[1].getBBox(); 

         var diffX = d.x - d.node.x; 
         var diffY = d.y - d.node.y; 

         var dist = Math.sqrt(diffX * diffX + diffY * diffY); 

         var shiftX = b.width * (diffX - dist)/(dist * 2); 
         shiftX = Math.max(-b.width, Math.min(0, shiftX)); 
         var shiftY = 5; 
         this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); 
        } 
       }); 

       anchorNode.call(updateNode); 

     link.call(updateLink); 
     anchorLink.call(updateLink); 

    }); 
} 

ответ

7

Вообще говоря, вы можете добавить кнопки мыши события SVG элементов в D3.js с помощью

.on('click', function(d, i) { 
    window.location.href = d.url; 
}) 

d является объектом данных и i в индексе г в коллекции.

Просто добавить, что обработчик щелчка в текстовом узел, а также в качестве узла (путь) узла, как в этой скрипке http://jsfiddle.net/jNyrf/

+1

d.url не работает. что работало d.node.label, но спасибо, что направили меня в правильном направлении :) –

+1

, пожалуйста, обновите с полным примером – FlavorScape

4

У вас здесь есть два варианта.

  • Вы можете использовать обработчик .on("click", ...), чтобы установить текущую страницу цели.
  • Элемент a с элементом .attr("xlink:href", url), который содержит элемент, действующий как гиперссылка, чтобы установить ссылку более традиционным способом.

Более подробная информация в this question/answer, хотя я полагаю, вам не придется импортировать xlink имен в явном виде, по крайней мере, не в последнюю версию D3.

+0

Можете ли вы представить подробную информацию о том, как создать элемент «а» с .attr ("XLink : href ", url)? Где я должен поместить эту строку кода? –

+1

Вопрос, на который я связан, имеет полный пример. –