D3.js增加了引力

时间:2015-09-23 18:37:02

标签: javascript d3.js

我是D3的新手,我正在尝试修改此示例以制作相对静止的有向图:http://bl.ocks.org/rkirsling/5001347

现在我拥有它,以便为每个节点分配一个位置并将它们设置为固定。这通常有效但节点卡住且无生命。我想要的是将节点分配的位置作为它们的位置,但是如果我拖动其中一个节点,它会移回到它的位置,就像这个例子中的引力一样:http://bl.ocks.org/mbostock/1804919

如何修改以下代码以包含此内容?

function start(element, numNodes, numEdges) {
            // set up SVG for D3
            var width = 960,
                height = 500,
                colors = d3.scale.category10();
            var svg = d3.select("#visrep").append('svg').attr('oncontextmenu', 'return false;').attr('width', width).attr('height', height);
            //var force = d3.layout.force().gravity(0.05).distance(100).charge(-100).size([width, height]);
            //var force = cola.d3adaptor().avoidOverlaps(true).linkDistance(30).size([width, height]).nodes(nodes).links(links).size([width, height]);
            // set up initial nodes and links
            //  - nodes are known by 'id', not by index in array.
            //  - reflexive edges are indicated on the node (as a bold black circle).
            //  - links are always source < target; edge directions are set by 'left' and 'right'.
            var nodes, links;
            var nodes = [
                { id: 0, reflexive: false },
                { id: 1, reflexive: true },
                { id: 2, reflexive: false }
            ],
              lastNodeId = 2;
            nodes = [];
            var count = 0, lineLimit = 10;
            for (var i = 0; i < numNodes; i++) {
                if (nod[i].nodeID < lineLimit) count++;
            }
            var L = 50, r = 12;
            var d = 2 * r + L;
            var R = (count - 1) * d;
            var m = width / 2;
            var X;
            //alert("L: " + L + " r: " + r + " d: " + d + " R: " + R + " m: " + m);
            for (var i = 0; i < numNodes; i++) {

                if (nod[i].nodeID <= lineLimit) {
                    X = m - (R / 2) + (i * d);
                   // alert("doing node: " + nod[i].nodeID + "   at => " + X);
                    nodes.push({ x: X, y: (height)/3, id: nod[i].nodeID, reflexive: true });
                }
                else {
                    X = m + (R / 2) - ((i-count) * d);
                   // alert("doing node: " + nod[i].nodeID + " at => " + X);
                    nodes.push({ x: X, y: (height * 2) / 3, id: nod[i].nodeID, reflexive: true });
                }
            }

            lastNodeId = numNodes - 1;
            var links = [
                { source: nodes[0], target: nodes[1], left: false, right: true },
                { source: nodes[1], target: nodes[2], left: false, right: true }
            ]
            links = [];
            for (var i = 0; i < numEdges; ++i) {
                //d3.select(element).append("h3").text("Source: " + nodes[edges[i].source - 1].id + " Target: " + nodes[edges[i].target - 1].id);
                links.push({ source: nodes[edges[i].source - 1], target: nodes[edges[i].target - 1], left: false, right: true });
            }

            // init D3 force layout
            var force = d3.layout.force()
                .nodes(nodes)
                .links(links)
                .size([width, height])
                .linkDistance(150)
                .charge(-500)
                .on('tick', tick);
            //var force = cola.d3adaptor().avoidOverlaps(true).size([width, height]).nodes(nodes).links(links).size([width, height]).on('tick', tick);

            // define arrow markers for graph links
            svg.append('svg:defs').append('svg:marker')
                .attr('id', 'end-arrow')
                .attr('viewBox', '0 -5 10 10')
                .attr('refX', 6)
                .attr('markerWidth', 3)
                .attr('markerHeight', 3)
                .attr('orient', 'auto')
              .append('svg:path')
                .attr('d', 'M0,-5L10,0L0,5')
                .attr('fill', '#000');

            svg.append('svg:defs').append('svg:marker')
                .attr('id', 'start-arrow')
                .attr('viewBox', '0 -5 10 10')
                .attr('refX', 4)
                .attr('markerWidth', 3)
                .attr('markerHeight', 3)
                .attr('orient', 'auto')
              .append('svg:path')
                .attr('d', 'M10,-5L0,0L10,5')
                .attr('fill', '#000');

            // line displayed when dragging new nodes
            var drag_line = svg.append('svg:path')
              .attr('class', 'link dragline hidden')
              .attr('d', 'M0,0L0,0');

            // handles to link and node element groups
            var path = svg.append('svg:g').selectAll('path'),
                circle = svg.append('svg:g').selectAll('g');

            // mouse event vars
            var selected_node = null,
                selected_link = null,
                mousedown_link = null,
                mousedown_node = null,
                mouseup_node = null;

            function resetMouseVars() {
                mousedown_node = null;
                mouseup_node = null;
                mousedown_link = null;
            }

            var n = nodes.length; nodes.forEach(function (d, i) {
                if (d.Category == "Chip Life Cycle") {
                    //d.x = (width / (n * i)) + 10;
                    //d.y = height * 0.75;
                    d.fixed = true;
                }
                else if (d.Category == "Abstraction") {
                    //d.x = (width / (n * i)) + 10;
                    //d.y = height * 0.75;
                    d.fixed = true;
                }
                else if (d.Category == "Properties") {
                    //d.x = (width / (n * i)) + 10;
                    //d.y = height * 0.4;
                    d.fixed = true;
                }
                else {
                    //d.x = (width / (n * i)) + 10;
                    //d.y = height * 0.4;
                    d.fixed = true;
                }
                ++i;
            });
            // update force layout (called automatically each iteration)
            function tick() {
                // draw directed edges with proper padding from node centers
                path.attr('d', function (d) {
                    var deltaX = d.target.x - d.source.x,
                        deltaY = d.target.y - d.source.y,
                        dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
                        normX = deltaX / dist,
                        normY = deltaY / dist,
                        sourcePadding = d.left ? 17 : 12,
                        targetPadding = d.right ? 17 : 12,
                        sourceX = d.source.x + (sourcePadding * normX),
                        sourceY = d.source.y + (sourcePadding * normY),
                        targetX = d.target.x - (targetPadding * normX),
                        targetY = d.target.y - (targetPadding * normY);
                    return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
                });

                circle.attr('transform', function (d) {
                    return 'translate(' + d.x + ',' + d.y + ')';
                });
            }

            // update graph (called when needed)
            function restart() {
                // path (link) group
                path = path.data(links);

                // update existing links
                path.classed('selected', function (d) { return d === selected_link; })
                  .style('marker-start', function (d) { return d.left ? 'url(#start-arrow)' : ''; })
                  .style('marker-end', function (d) { return d.right ? 'url(#end-arrow)' : ''; });


                // add new links
                path.enter().append('svg:path')
                  .attr('class', 'link')
                  .classed('selected', function (d) { return d === selected_link; })
                  .style('marker-start', function (d) { return d.left ? 'url(#start-arrow)' : ''; })
                  .style('marker-end', function (d) { return d.right ? 'url(#end-arrow)' : ''; })
                  .on('mousedown', function (d) {
                      if (d3.event.ctrlKey) return;

                      // select link
                      mousedown_link = d;
                      if (mousedown_link === selected_link) selected_link = null;
                      else selected_link = mousedown_link;
                      selected_node = null;
                      restart();
                  });

                // remove old links
                path.exit().remove();


                // circle (node) group
                // NB: the function arg is crucial here! nodes are known by id, not by index!
                circle = circle.data(nodes, function (d) { return d.id; });

                // update existing nodes (reflexive & selected visual states)
                circle.selectAll('circle')
                  .style('fill', function (d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
                  .classed('reflexive', function (d) { return d.reflexive; });

                // add new nodes
                var g = circle.enter().append('svg:g');

                g.append('svg:circle')
                  .attr('class', 'node')
                  .attr('r', 12)
                  .style('fill', function (d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
                  .style('stroke', function (d) { return d3.rgb(colors(d.id)).darker().toString(); })
                  .classed('reflexive', function (d) { return d.reflexive; })
                  .on('mouseover', function (d) {
                      if (!mousedown_node || d === mousedown_node) return;
                      // enlarge target node
                      d3.select(this).attr('transform', 'scale(1.1)');
                  })
                  .on('mouseout', function (d) {
                      if (!mousedown_node || d === mousedown_node) return;
                      // unenlarge target node
                      d3.select(this).attr('transform', '');
                  })
                  .on('mousedown', function (d) {
                      if (d3.event.ctrlKey) return;

                      // select node
                      mousedown_node = d;
                      if (mousedown_node === selected_node) selected_node = null;
                      else selected_node = mousedown_node;
                      selected_link = null;

                      // reposition drag line
                      drag_line
                        .style('marker-end', 'url(#end-arrow)')
                        .classed('hidden', false)
                        .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + mousedown_node.x + ',' + mousedown_node.y);

                      restart();
                  })
                  .on('mouseup', function (d) {
                      if (!mousedown_node) return;

                      // needed by FF
                      drag_line
                        .classed('hidden', true)
                        .style('marker-end', '');

                      // check for drag-to-self
                      mouseup_node = d;
                      if (mouseup_node === mousedown_node) { resetMouseVars(); return; }

                      // unenlarge target node
                      d3.select(this).attr('transform', '');

                      // add link to graph (update if exists)
                      // NB: links are strictly source < target; arrows separately specified by booleans
                      var source, target, direction;
                      if (mousedown_node.id < mouseup_node.id) {
                          source = mousedown_node;
                          target = mouseup_node;
                          direction = 'right';
                      } else {
                          source = mouseup_node;
                          target = mousedown_node;
                          direction = 'left';
                      }

                      var link;
                      link = links.filter(function (l) {
                          return (l.source === source && l.target === target);
                      })[0];

                      if (link) {
                          link[direction] = true;
                      } else {
                          link = { source: source, target: target, left: false, right: false };
                          link[direction] = true;
                          links.push(link);
                      }

                      // select new link
                      selected_link = link;
                      selected_node = null;
                      restart();
                  });

                // show node IDs
                g.append('svg:text')
                    .attr('x', 0)
                    .attr('y', 4)
                    .attr('class', 'id')
                    .text(function (d) { return d.id; });

                // remove old nodes
                circle.exit().remove();

                // set the graph in motion
                force.start();
            }

            function mousedown() {
                // prevent I-bar on drag
                //d3.event.preventDefault();

                // because :active only works in WebKit?
                svg.classed('active', true);

                if (d3.event.ctrlKey || mousedown_node || mousedown_link) return;

                // insert new node at point
                var point = d3.mouse(this),
                    node = { id: ++lastNodeId, reflexive: false };
                node.x = point[0];
                node.y = point[1];
                nodes.push(node);

                restart();
            }

            function mousemove() {
                if (!mousedown_node) return;

                // update drag line
                drag_line.attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + d3.mouse(this)[0] + ',' + d3.mouse(this)[1]);

                restart();
            }

            function mouseup() {
                if (mousedown_node) {
                    // hide drag line
                    drag_line
                      .classed('hidden', true)
                      .style('marker-end', '');
                }

                // because :active only works in WebKit?
                svg.classed('active', false);

                // clear mouse event vars
                resetMouseVars();
            }

            function spliceLinksForNode(node) {
                var toSplice = links.filter(function (l) {
                    return (l.source === node || l.target === node);
                });
                toSplice.map(function (l) {
                    links.splice(links.indexOf(l), 1);
                });
            }

            // only respond once per keydown
            var lastKeyDown = -1;

            function keydown() {
                d3.event.preventDefault();

                if (lastKeyDown !== -1) return;
                lastKeyDown = d3.event.keyCode;

                // ctrl
                if (d3.event.keyCode === 17) {
                    circle.call(force.drag);
                    svg.classed('ctrl', true);
                }

                if (!selected_node && !selected_link) return;
                switch (d3.event.keyCode) {
                    case 8: // backspace
                    case 46: // delete
                        if (selected_node) {
                            nodes.splice(nodes.indexOf(selected_node), 1);
                            spliceLinksForNode(selected_node);
                        } else if (selected_link) {
                            links.splice(links.indexOf(selected_link), 1);
                        }
                        selected_link = null;
                        selected_node = null;
                        restart();
                        break;
                    case 66: // B
                        if (selected_link) {
                            // set link direction to both left and right
                            selected_link.left = true;
                            selected_link.right = true;
                        }
                        restart();
                        break;
                    case 76: // L
                        if (selected_link) {
                            // set link direction to left only
                            selected_link.left = true;
                            selected_link.right = false;
                        }
                        restart();
                        break;
                    case 82: // R
                        if (selected_node) {
                            // toggle node reflexivity
                            selected_node.reflexive = !selected_node.reflexive;
                        } else if (selected_link) {
                            // set link direction to right only
                            selected_link.left = false;
                            selected_link.right = true;
                        }
                        restart();
                        break;
                }
            }

            function keyup() {
                lastKeyDown = -1;

                // ctrl
                if (d3.event.keyCode === 17) {
                    circle
                      .on('mousedown.drag', null)
                      .on('touchstart.drag', null);
                    svg.classed('ctrl', false);
                }
            }

            // app starts here
            svg.on('mousedown', mousedown)
              .on('mousemove', mousemove)
              .on('mouseup', mouseup);
            d3.select(window)
              .on('keydown', keydown)
              .on('keyup', keyup);
            restart();
        }

        var nod;
        var edges;
        function visualize(element, numEdges, numNodes) {
            //start();
            //graph = new Visualizer(element);
            for (var i = 0; i < numEdges ; ++i) {
                //graph.addLink(edges[i].source, nodeEdge[i].target);
                d3.select(element).append("h3").text("Source: "+ edges[i].source + " Target: " + edges[i].target);
            }
            for (var i = 0; i < numNodes; ++i) {
                //graph.addNode(node[i].nodeID, nodes[i].Category);
                d3.select(element).append("h3").text("Node: " + nod[i].nodeID + " Category: " + nod[i].Category);
            }
            start(element, numNodes, numEdges);
        //    //graph.start();
        }

修改

根据要求,HTML虽然相当无聊。我的C#将div元素&#34;#visrep&#34;传递给visualize函数。在&#39;元素&#39;参数。

<asp:Content ID="DescriptionContent" ContentPlaceHolderID="MainContent" runat="server">
    <script type="text/javascript" src="Scripts/d3.js"></script>
      <div id="visJumboContainer" class="jumbotron">
          <div id="visrep" class="ContentHead"></div>
      </div>
   <script type="text/javascript">

       <%--This is where the script from above sits--%>

   </script>
</asp:Content>

0 个答案:

没有答案