
[code]

    <!DOCTYPE html>
    <html lang="ja">
    <style>
    svg {
        border: solid 1px;
    }
    </style>
    
    <head>
    <meta charset="utf-8">
    <title>D3.js(Force Layout)の練習</title>
    </head>
    
    <body>
    <script src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    
    <script>
        var w = 800;
        var h = 800;
    
        var nodes = [];
        var links = [];
        var xlink = [];
        var link2 = [];
    
        var url = "https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/hatena/b/hotentry&num=-1";
        var proxy_url = "http://allow-any-origin.appspot.com/" + encodeURIComponent(url);
    
        function for_each(array, func) {
            Array.prototype.forEach.call(array, func);
        }
    
        function get_html(callback) {
            var hatena_hotentry_url = "http://b.hatena.ne.jp/hotentry";
            hatena_hotentry_url = "http://allow-any-origin.appspot.com/" + encodeURIComponent(hatena_hotentry_url);
    
            /*// var hatena_hotentry_url = "./hatena_hotentry.html"  */
            var req = new XMLHttpRequest();
            req.open("GET", hatena_hotentry_url);
            req.onreadystatechange = function() {
                if (req.readyState === 4 && req.status === 200) {
                    callback(req.responseText);
                    req = undefined;
                }
            };
            req.send(null);
        }
    
        function html_to_relation(html) {
            var doc = new DOMParser().parseFromString(html, "text/html");
            var error_tags = doc.getElementsByTagName("parsererror");
            if (error_tags.length) {
                console.log("error: ", error_tags);
                return [
                    ["Parse error", "Maybe HTML is broken"]
                ];
            }
    
            var relation = [];
            /*// [["name", ...], ...]
             */
            var entry_elms = doc.querySelectorAll(
                "[data-track-section='default'] .entry-contents");
            for_each(entry_elms, function(entry_elm) {
                var entry_link_elm = entry_elm.querySelector(".entry-link");
                if (!entry_link_elm) {
                    return;
                }
    
                var name_array = [];
                relation.push(name_array);
                name_array.push(entry_link_elm.title);
    
                console.log(entry_link_elm.href)
    
                var entry_meta_elm = entry_elm.nextElementSibling;
                if (!entry_meta_elm) {
                    return;
                }
                for_each(entry_meta_elm.querySelectorAll("a.tag"), function(tag_elm) {
                    name_array.push(tag_elm.textContent);
                    name_array.push(entry_link_elm.href);
                });
            });
    
            return relation;
        }
    
        function relation_view(relation) {
            /*document.getElementById("view").textContent
               = JSON.stringify(relation, undefined, 2);
      */
    
            d3.json(proxy_url, function(error, json) {
                if (error) {
                    return console.warn(error);
                }
    
                var feeds = json.responseData.feed;
    
                for (var x = 0; x < feeds.entries.length; x++) {
                    var href = {
                        "url": feeds.entries[x].link
                    };
                    xlink.push(href);
                };
            });
    
            for (var i = 0; i < relation.length; i++) {
                if (i + 1 < relation.length) {
                    var num = {
                        "source": i,
                        "target": +(i + 1)
                    };
                } else {
                    var num = {
                        "source": i,
                        "target": 0
                    };
                }
                var list = {
                    "label": relation[i][0],
                    "url": relation[i][6]
                };
                nodes.push(list);
                links.push(num);
            }
            console.log(nodes)
    
            var force = d3.layout.force()
                .nodes(nodes)
                .links(links)
                .size([w, h])
                .linkStrength(0.1)
                .friction(0.9)
                .distance(200)
                .charge(-30)
                .gravity(0.1)
                .theta(0.8)
                .alpha(0.1)
                .start();
    
            /*console.log(nodes)*/
            var svg = d3.select("body").append("svg").attr({
                width: w,
                height: h
            });
            var link = svg.selectAll("line")
                .data(links)
                .enter()
                .append("line")
                .style({
                    stroke: "#ccc",
                    "stroke-width": 1
                });
    
            var node = svg.selectAll("circle")
                .data(nodes)
                .enter()
                .append("circle")
                .attr({
                    r: 20,
                    opacity: 0.5
                })
                .attr("xlink:href", function(d) {
                    return d.url;
                })
                .style({
                    fill: "red"
                })
                .call(force.drag);
    
            var label = svg.selectAll('text')
                .data(nodes)
                .enter()
                .append('text')
                .attr({
                    "text-anchor": "middle",
                    "fill": "black"
                })
                .style({
                    "font-size": 11
                })
                .text(function(d) {
                    return d.label;
                });
    
            force.on("tick", function() {
                link.attr({
                    x1: function(d) {
                        return d.source.x;
                    },
                    y1: function(d) {
                        return d.source.y;
                    },
                    x2: function(d) {
                        return d.target.x;
                    },
                    y2: function(d) {
                        return d.target.y;
                    }
                });
                node.attr({
                    cx: function(d) {
                        return d.x;
                    },
                    cy: function(d) {
                        return d.y;
                    }
                });
                label.attr({
                    x: function(d) {
                        return d.x;
                    },
                    y: function(d) {
                        return d.y
                    }
                });
    
            })
        }
    
        get_html(function(html) {
            relation_view(html_to_relation(html));
        });
    </script>
    </body>
    
    </html>
[/code]

上記のようなソースでforceレイアウトを描画しています。  
node配列の中にlabelとurlを準備し、こちら( <http://bl.ocks.org/tag1216/76e6bba3fd1784eba83c>
)を参考にさせて頂きリンクを貼れるようにしようとしましたが、上手く動作しません。  
どのように訂正すればノードをクリックすればリンク先に正しく飛ぶのでしょうか？  
お力添えよろしくお願いいたします。


CC BY-SA 3.0
2015-12-01T09:43:25.453
19516
2016-10-11T12:45:46.707
2016-01-31T13:01:17.177
2238
13172
question
javascript html
forceレイアウトのノードにリンクが追加されない


circle要素をa要素で囲むとリンクが有効になります。

[code]

        var node = svg.selectAll("a")
                  .data(nodes)
                  .enter()
                  .append("a")
                  .attr("href", function(d){return d.url;})
                  .append("circle")
                  .attr({r:20, opacity:0.5})
                  .style({fill:"red"})
                  .call(force.drag);
    
[/code]

しかし、円の上にテキストが重なるとクリックできない別の問題もあるようですが。

（追記）  
上記はIE11で確認していたのですが、ChromeやFirefoxでは

[code]

    .attr(":xlink:href", function(d){return d.url;})
    
[/code]

としないとリンクが認識されませんでした。  
（それ以前にfeedの読み込みでエラーが出ているようですが）

ちなみにテキスト上のクリックを無効にするには、text要素に

[code]

    pointer-events="none"
    
[/code]

を追加すればよいかと思います。


CC BY-SA 3.0
2015-12-02T04:51:28.090
19540
2015-12-02T08:15:59.047
2015-12-02T08:15:59.047
13314
13314
19516
answer