ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javascript-如何在基于d3力的布局中在节点标签内的文本下划线?

2019-10-30 00:35:57  阅读:220  来源: 互联网

标签:labels d3-js force-layout css javascript


我正在使用基于d3力的图,该图的节点标签实际上是URL,单击该URL会将用户带到目标URL.出于可用性的原因,是否可以在网址下划线?更好的是,当用户将鼠标悬停在某个标签上时,下划线是否可以显示和消失,文本的颜色是否可以更改?这将帮助用户了解标签是可单击的.请帮忙.

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

    });
}

解决方法:

正如Matt Walters所说,您可以更改文本颜色并使用CSS添加下划线,包括添加悬停效果.

但是,我强烈建议您将链接实现为实际的< a>元素超链接,它是perfectly acceptable in SVG.我已经对其进行了测试,您可以将text元素包装在链接中,也可以将链接放在text元素中,但要包围实际的文本内容.唯一的麻烦是,您必须将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;
}

标签:labels,d3-js,force-layout,css,javascript
来源: https://codeday.me/bug/20191030/1964134.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有