D3.js分层边缘捆绑按组着色

时间:2018-06-05 22:19:34

标签: javascript html css d3.js svg

我正在尝试根据他们连接的组在我的分层边缘捆绑可视化中为连接着色。可以看到here的一个例子。

enter image description here

这是我当前的鼠标悬停功能:

    function mouseover(d) {
        svg.selectAll("path.link.target-" + d.key)
            .classed("target", true)
            .each(updateNodes("source", true));

        svg.selectAll("path.link.source-" + d.key)
            .classed("source", true)
            .each(updateNodes("target", true));
    }

以下是我发布的示例中的鼠标悬停功能:

function mouseovered(d) 
{
        // Handle tooltip
        // Tooltips should avoid crossing into the center circle

        d3.selectAll("#tooltip").remove();
        d3.selectAll("#vis")
            .append("xhtml:div")
            .attr("id", "tooltip")
            .style("opacity", 0)
            .html(d.title);
        var mouseloc = d3.mouse(d3.select("#vis")[0][0]),
            my = ((rotateit(d.x) > 90) && (rotateit(d.x) < 270)) ? mouseloc[1] + 10 : mouseloc[1] - 35,
            mx = (rotateit(d.x) < 180) ? (mouseloc[0] + 10) :  Math.max(130, (mouseloc[0] - 10 - document.getElementById("tooltip").offsetWidth));
        d3.selectAll("#tooltip").style({"top" : my + "px", "left": mx + "px"});
        d3.selectAll("#tooltip")
            .transition()
            .duration(500)
            .style("opacity", 1);
        node.each(function(n) { n.target = n.source = false; });

        currnode = d3.select(this)[0][0].__data__;

        link.classed("link--target", function(l) { 
                if (l.target === d) 
                { 
                    return l.source.source = true; 
                }
                if (l.source === d) 
                { 
                    return l.target.target = true; 
                }
            })
            .filter(function(l) { return l.target === d || l.source === d; })
            .attr("stroke", function(d){
                if (d[0].name == currnode.name)
                {
                    return color(d[2].cat);
                }
                return color(d[0].cat);
            })
            .each(function() { this.parentNode.appendChild(this); });

        d3.selectAll(".link--clicked").each(function() { this.parentNode.appendChild(this); });

        node.classed("node--target", function(n) { 
                return (n.target || n.source); 
            });
}

我对D3有些新意,但我假设我需要做的是根据密钥检查组,然后将其与该组的颜色相匹配。

我的完整代码在这里:

 <script type="text/javascript">
    color = d3.scale.category10(); 

    var w = 840,
        h = 800,
        rx = w / 2,
        ry = h / 2,
        m0,
        rotate = 0
    pi = Math.PI;

    var splines = [];

    var cluster = d3.layout.cluster()
        .size([360, ry - 180])
        .sort(function(a, b) {
            return d3.ascending(a.key, b.key);
        });

    var bundle = d3.layout.bundle();

    var line = d3.svg.line.radial()
        .interpolate("bundle")
        .tension(.5)
        .radius(function(d) {
            return d.y;
        })
        .angle(function(d) {
            return d.x / 180 * Math.PI;
        });

    // Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
    var div = d3.select("#bundle")
        .style("width", w + "px")
        .style("height", w + "px")
        .style("position", "absolute");

    var svg = div.append("svg:svg")
        .attr("width", w)
        .attr("height", w)
        .append("svg:g")
        .attr("transform", "translate(" + rx + "," + ry + ")");

    svg.append("svg:path")
        .attr("class", "arc")
        .attr("d", d3.svg.arc().outerRadius(ry - 180).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
        .on("mousedown", mousedown);

    d3.json("TASKS AND PHASES.json", function(classes) {

        var nodes = cluster.nodes(packages.root(classes)),
            links = packages.imports(nodes),
            splines = bundle(links);

        var path = svg.selectAll("path.link")
            .data(links)
            .enter().append("svg:path")
            .attr("class", function(d) {
                return "link source-" + d.source.key + " target-" + d.target.key;
            })
            .attr("d", function(d, i) {
                return line(splines[i]);
            });

        var groupData = svg.selectAll("g.group")
            .data(nodes.filter(function(d) {
                return (d.key == 'Department' || d.key == 'Software' || d.key == 'Tasks' || d.key == 'Phases') && d.children;
            }))
            .enter().append("group")
            .attr("class", "group");

        var groupArc = d3.svg.arc()
            .innerRadius(ry - 177)
            .outerRadius(ry - 157)
            .startAngle(function(d) {
                return (findStartAngle(d.__data__.children) - 2) * pi / 180;
            })
            .endAngle(function(d) {
                return (findEndAngle(d.__data__.children) + 2) * pi / 180
            });        

        svg.selectAll("g.arc")
            .data(groupData[0])
            .enter().append("svg:path")
            .attr("d", groupArc)
            .attr("class", "groupArc")
            .attr("id", function(d, i) {console.log(d.__data__.key); return d.__data__.key;})
            .style("fill", function(d, i) {return color(i);})
            .style("fill-opacity", 0.5)
            .each(function(d,i) {

                var firstArcSection = /(^.+?)L/;

                var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];

                newArc = newArc.replace(/,/g , " ");

                svg.append("path")
                    .attr("class", "hiddenArcs")
                    .attr("id", "hidden"+d.__data__.key)
                    .attr("d", newArc)
                    .style("fill", "none");
            });



        svg.selectAll(".arcText")
            .data(groupData[0])
            .enter().append("text")
            .attr("class", "arcText")
            .attr("dy", 15)
            .append("textPath")
            .attr("startOffset","50%")
            .style("text-anchor","middle")
            .attr("xlink:href",function(d,i){return "#hidden" + d.__data__.key;})
            .text(function(d){return d.__data__.key;});    

        svg.selectAll("g.node")
            .data(nodes.filter(function(n) {
                return !n.children;
            }))
            .enter().append("svg:g")
            .attr("class", "node")
            .attr("id", function(d) {
                return "node-" + d.key;
            })
            .attr("transform", function(d) {
                return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
            })
            .append("svg:text")
            .attr("dx", function(d) {
                return d.x < 180 ? 25 : -25;
            })
            .attr("dy", ".31em")
            .attr("text-anchor", function(d) {
                return d.x < 180 ? "start" : "end";
            })
            .attr("transform", function(d) {
                return d.x < 180 ? null : "rotate(180)";
            })
            .text(function(d) {
                return d.key.replace(/_/g, ' ');
            })
            .on("mouseover", mouseover)
            .on("mouseout", mouseout);

        d3.select("input[type=range]").on("change", function() {
            line.tension(this.value / 100);
            path.attr("d", function(d, i) {
                return line(splines[i]);
            });
        });
    });

    d3.select(window)
        .on("mousemove", mousemove)
        .on("mouseup", mouseup);

    function mouse(e) {
        return [e.pageX - rx, e.pageY - ry];
    }

    function mousedown() {
        m0 = mouse(d3.event);
        d3.event.preventDefault();
    }

    function mousemove() {
        if (m0) {
            var m1 = mouse(d3.event),
                dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
            div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
        }
    }

    function mouseup() {
        if (m0) {
            var m1 = mouse(d3.event),
                dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;

            rotate += dm;
            if (rotate > 360) rotate -= 360;
            else if (rotate < 0) rotate += 360;
            m0 = null;

            div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");

            svg.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
                .selectAll("g.node text")
                .attr("dx", function(d) {
                    return (d.x + rotate) % 360 < 180 ? 25 : -25;
                })
                .attr("text-anchor", function(d) {
                    return (d.x + rotate) % 360 < 180 ? "start" : "end";
                })
                .attr("transform", function(d) {
                    return (d.x + rotate) % 360 < 180 ? null : "rotate(180)";
                });
        }
    }

    function mouseover(d) {
        svg.selectAll("path.link.target-" + d.key)
            .classed("target", true)
            .each(updateNodes("source", true));

        svg.selectAll("path.link.source-" + d.key)
            .classed("source", true)
            .each(updateNodes("target", true));
    }

    function mouseout(d) {
        svg.selectAll("path.link.source-" + d.key)
            .classed("source", false)
            .each(updateNodes("target", false));

        svg.selectAll("path.link.target-" + d.key)
            .classed("target", false)
            .each(updateNodes("source", false));
    }

    function updateNodes(name, value) {
        return function(d) {
            if (value) this.parentNode.appendChild(this);
            svg.select("#node-" + d[name].key).classed(name, value);
        };
    }

    function cross(a, b) {
        return a[0] * b[1] - a[1] * b[0];
    }

    function dot(a, b) {
        return a[0] * b[0] + a[1] * b[1];
    }

    function findStartAngle(children) {
        var min = children[0].x;
        children.forEach(function(d) {
            if (d.x < min)
                min = d.x;
        });
        return min;
    }

    function findEndAngle(children) {
        var max = children[0].x;
        children.forEach(function(d) {
            if (d.x > max)
                max = d.x;
        });
        return max;
    }
</script>

0 个答案:

没有答案