2014-01-22 84 views
3

我正在使用基於d3強制的圖形,其節點標籤實際上是URL,點擊時會將用戶轉到目標URL。出於可用性原因,有沒有辦法強調url?更好的是,下劃線是否會出現和消失,當用戶懸停在某個標籤上時,文本的顏色是否可以改變?這將有助於用戶瞭解標籤是可點擊的。請幫忙。如何在基於d3強制佈局的節點標籤中加下劃線?

enter image description here

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

var QueuedORG = []; 
var tempLIST = []; 


function drawVisual() 
{ 
    //alert(sessionStorage["queuedArray"]); 
    /*var getArr = []; 
    getArr = JSON.parse(localStorage.getItem('storeArray')); 
    document.getElementById('myMSG').innerHTML = getArr[1].parentURL;*/ 

    QueuedORG.length = 0; 
    tempLIST.length = 0; 

    //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); 

      //get links from LocalStorage 
      //QueuedORG = JSON.parse(sessionStorage.getItem("queuedArray")); 
      //QueuedORG = JSON.parse(localStorage["queuedArray"]); 

    QueuedORG.push({url: "http://understandblue.blogspot.com/", parentURL: "http://understandblue.blogspot.com", used:0}); 
    QueuedORG.push({url: "http://www.google.com", parentURL: "http://understandblue.blogspot.com/", used:0}); 
    QueuedORG.push({url: "http://paperfriendly.blogspot.com", parentURL: "http://understandblue.blogspot.com/", used:0}); 
    QueuedORG.push({url: "http://4pawsforever.org", parentURL: "http://understandblue.blogspot.com/", used:0}); 
    QueuedORG.push({url: "http://en.wikipedia.org", parentURL: "http://understandblue.blogspot.com/", used:0}); 

      var nodes = []; 
      nodes.length = 0; 

      var labelAnchors = []; 
      labelAnchors.length = 0; 
      var labelAnchorLinks = []; 
      labelAnchorLinks.length = 0; 
      var links = []; 
      links.length = 0; 

      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];}).on('click', function(d, i) { 
       var win = window.open(d.node.label, '_blank); 
       win.focus(); 
      }); 

      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").on('click', function(d, i){ 
         var win = window.open(d.node.label, '_blank); 
         win.focus();   
      }); 

      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); 

    }); 
} 

回答

3

正如Matt Walters所說,您可以更改文本顏色並添加CSS下劃線,包括添加懸停效果。

但是,我強烈建議您將鏈接實現爲實際的<a>元素超鏈接,它們是perfectly acceptable in SVG。我已經測試過了,可以將文本元素包裝在鏈接中,也可以將鏈接放在文本元素中,但圍繞實際的文本內容。唯一複雜的是,您必須使用xlink:href作爲url屬性,而不是簡單地使用href

這裏有一個力向圖我對別人的調試創造,適應於把所有的文本標籤到鏈接:
http://codepen.io/AmeliaBR/pen/AoFHg

在更新功能的鍵碼:

hypertext = hypertext.data(force.nodes()); 
// hypertext refers to a selection of text elements, joined to the data 

// Add labels for new nodes: 
hypertext.enter().append("text") //add the text element 
     //add any unchanging attributes of the <text>: 
     .attr("text-anchor", "middle") 
    //add a link element within each text element 
    .append("a") 
     //add unchanging attributes of the <a> link 
     .attr("target", "_blank") //set the link to open in an unnamed tab 
     .attr("xlink:show", "new"); 
      //show="new" is an XML way to tell the link to open in a new tab/window. 
      //Either attribute *should* work on its own, but best use both to be safe. 

// At this point, each new <text> element contains an <a> element, but the 
// variable hypertext still refers to the text elements. 

// Remove any outgoing/old text elements for non-existent nodes: 
hypertext.exit().remove(); 

// Compute data-based attributes for entering and updating texts: 
hypertext.attr("x", 8) //attributes of the <text> elements 
     .attr("y", "0.3em") 
    //Select the existing <a> element within each <text> 
    .select("a") 
     //Update the link attributes. Note that the <a> element was never given 
     //its own data, so it inherits the data from the parent <text> element. 
     .attr("xlink:href", function (d) { 
      return "http://example.com/" + d.name; //create url from data 
     }) 
     //Set the text within the link, which in this case is the only text 
     //within the text element. 
     .text(function (d) { 
      return d.name; //link text content 
     }); 

使用link元素創建了所有必要的功能,但它沒有添加默認的HTML鏈接樣式。爲此,有CSS:

text a { 
    fill: navy; 
} 
text a:visited { 
    fill:darkpurple; 
} 
text a:hover, text a:active { 
    text-decoration: underline; 
    fill:darkred; 
} 
+0

嘿,你們誰可以請告訴我如何可以實現節點標籤作爲xlink:href。我不太理解答案中的代碼,並且難以轉換我已相應分享的代碼。此外,我使用了類似於:window.open(d.node.label,'_blank')我該如何改變它? –

+2

@DarthCoder這個想法是創造類似'Link text''。所以當我添加新的文本標籤時,我會在「text」元素中添加一個「a」元素。當我想更改鏈接或文本數據時,我在「text」元素中選擇「a」元素。要在新選項卡中打開鏈接,XML屬性是[xlink:show =「new」](http://www.w3.org/TR/SVG/linking.html#AElement),您可以在'輸入()'鏈或在'update()'鏈中。我會用更詳細的評論和例子更新答案。 – AmeliaBR

1

我想你應該能夠做到這一切在CSS。這是美麗的一部分d3.js

沒有看到一些代碼它將很難確切地說你需要什麼,但我敢打賭,你可以做一些像this爲下劃線和類似的其他效果,你有。

你可以發表一些代碼,所以我們可以幫助你進一步?

+0

我已經分享了代碼,它不是完整的東西,但是這是與可視化相關的主代碼。希望它使事情更清晰:) –

相關問題