将一条线附加到力导向图并使用D3应用变换

时间:2014-07-29 17:44:20

标签: javascript d3.js

我在D3中有一个强制定向图,可以在Web套接字上正确呈现。我的任务是根据后续的Web套接字消息在此图表中添加或删除链接和节点。我遇到的问题是,当我平移或缩放图形时,会应用变换。我不知道如何将该转换应用于新添加的链接或节点。因此,添加的链接取决于源节点和目标节点的原始cx cy位置。以下是其中的代码。希望有人可以告诉我如何将转换应用于新添加的链接。

代码为了简洁而按要求编辑:

    var DataPlane = (function() {

//This method gets called when a link is either added or removed from the svg via web socket.
var remapDataPlane = function(data) {
    var dpData = $.parseJSON(data);
    ...
    if (dpData.addedLinks.length > 0) {
        //get the svg
        var parentSvg = d3.select("#app_dataPlane svg").select("g")
        var svg = parentSvg.select("g");

        //this portion gets the transform that has been applied to the svg group element.
        var trans = svg.attr("transform");

        //get a list of switches from svg
        var svgSwitches = d3.selectAll(".switch");
        //Process unidirectional and bidirectional links -- BEGIN
        var bidLinks = [];
        var uniLinks = [];
        var pairs = [];
        var idx = 0;


        function hasMatchingNode(element, index, array) {
            return (element.src.dpid !== this.src.dpid && element.src.dpid === this.dst.dpid && element.dst.dpid === this.src.dpid);
        }

        function parseLinks(element, index, array) {
            var node = array.filter(hasMatchingNode, element);
            if (node.length > 0) {
                var match = array.indexOf(node.pop());
                array.splice(match, 1);
            } else {
                uniLinks.push(element);
                array.splice(index, 1);
            }
        }
        dpData.addedLinks.map(parseLinks);
        if (dpData.addedLinks != undefined) {
            dpData.addedLinks.forEach(function(item) {
                item["nature"] = "bidirectional";
            });
            uniLinks.forEach(function(item) {
                item["nature"] = "unidirectional";
            });

            //Links are added in pairs to represent bidirectional nature.  I elminate duplicate links from the data and merge them with unidirectional links here.
            $.merge(dpData.addedLinks, uniLinks);
        }

        //For each link being added to the graph 
        for (var i = 0; i <= dpData.addedLinks.length - 1; i++) {

            //Get the name of the source node for the link and it's corresponding coordinates
            var srcName = 'switch_' + dpData.addedLinks[i].src.dpid;
            var srcC = document.getElementById(srcName);
            var srcCx = +srcC.getAttribute('cx');
            var srcCy = +srcC.getAttribute('cy');
            var srcCtm = srcC.getCTM();
            var srcCoords = getScreenCoords(srcCx, srcCy, srcCtm);

            //Get the name of the destination node for the link and it's corresponding coordinates
            var dstName = 'switch_' + dpData.addedLinks[i].dst.dpid;
            var dstC = document.getElementById(dstName);
            var dstCx = +dstC.getAttribute('cx');
            var dstCy = +dstC.getAttribute('cy');
            var dstCtm = dstC.getCTM();
            var dstCoords = getScreenCoords(dstCx, dstCy, dstCtm);

            //Append the line to the graph using the coordinates derived from the Cx & Cy coordinates
            var link = svg.append("line")
                .attr("x1", srcCoords.x)
                .attr("y1", srcCoords.y)
                .attr("x2", dstCoords.x)
                .attr("y2", dstCoords.y)
                .attr("class", "link")
                .attr("id", function(d) {
                    return "name_" + dpData.addedLinks[i].dst.dpid + dpData.addedLinks[i].src.dpid;
                })
                .style("stroke-width", 2)
                //Set Style for unidirectional otherwise grey
                .style("stroke", function(d) {
                    if (d != undefined && d.nature == "unidirectional") {
                        return "green";
                    }
                })
                // **** This is where I try and apply the transform to the link ****
                .attr("transform", trans)                   
        }
    }

    function getScreenCoords(x, y, ctm) {
        var xn = ctm.e + x * ctm.a;
        var yn = ctm.f + y * ctm.d;
        return {
            x: xn,
            y: yn
        };
    }
};      

// Initial code omitted for brevity as requested

return {
    drawDataPlane: drawDataPlane,
    remapDataPlane: remapDataPlane
};
   })();

SVG Elements的样本:

    <svg width="814" height="305" pointer-events="all">
<g>
    <g transform="translate(6.568073042618323,138.38858706474264) scale(0.8420541187522115)">
        <rect width="1628" height="610" fill="white"></rect>
        <line class="link" id="name_00:00:00:00:00:00:00:0100:00:00:00:00:00:00:03" x1="427.59429499296965" y1="125.07073054436019" x2="375.8732495447546" y2="138.7148361886131" style="stroke-width: 2px;"></line>
        <line class="link" id="name_00:00:00:00:00:00:00:0200:00:00:00:00:00:00:01" x1="375.8732495447546" y1="138.7148361886131" x2="400.55190412548484" y2="186.17410516927373" style="stroke-width: 2px;"></line>
        <circle r="6" id="switch_00:00:00:00:00:00:00:02" class="switch" fill="#15a9ff" cx="400.55190412548484" cy="186.17410516927373"></circle>
        <circle r="6" id="switch_00:00:00:00:00:00:00:03" class="switch" fill="#15a9ff" cx="427.59429499296965" cy="125.07073054436019"></circle>
        <circle r="6" id="switch_00:00:00:00:00:00:00:01" class="switch selectedSwitch" fill="#15a9ff" cx="375.8732495447546" cy="138.7148361886131"></circle>
    </g>
</g>

平移/缩放功能:

    function redraw() {
        svg.attr("transform",
            "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); /* skewX(30) */
    }

0 个答案:

没有答案