如何将标记头放置在链接中间

2023-12-09

我想在链接中间放置一个标记,而不是像我的代码那样将其放置在末尾。

尽管我用谷歌搜索了它,但我无法找到我的代码的解决方案。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <script src="../D3/d3.min.js"></script>
  </head>

  <body>
      <style>
          body {
              background-color: #3a5795;
          }



svg:not(.active):not(.ctrl) {
  cursor: crosshair;
}

path.link {
  fill: none;
  stroke:floralwhite;
  stroke-width: 4px;
  cursor: default;
}

svg:not(.active):not(.ctrl) path.link {
  cursor: pointer;
}

path.link.selected {
  stroke-dasharray: 10,2;
}

path.link.dragline {
  pointer-events: none;
}

path.link.hidden {
  stroke-width: 0;
}

rect.node {
  stroke-width: 1.5px;
  cursor: pointer;
}

rect.node.reflexive {
  stroke: #000 !important;
  stroke-width: 2.5px;
}

text {
  font: 12px sans-serif;
  pointer-events: none;
}

text.id {
  text-anchor: middle;
  font-weight: bold;
}

 </style>
      <script type="text/javascript">
          // set up SVG for D3
          var width = 1400,
              height = 800,
              colors = d3.scale.category10();

          var svg = d3.select('body')
            .append('svg')
            .attr('oncontextmenu', 'return false;')
            .attr('width', width)
            .attr('height', 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 rect).
          //  - links are always source < target; edge directions are set by 'left' and 'right'.
          var nodes = [
     {
         "id": "Component",
         "description": "Component are the Containers",
          "type":"wiring"
     },
     {
         "id": "Form Design And Data Design",
         "description": "In the Form Design and Data Design we can create form and data",
         "type": "wiring"
     },
     {
         "id": "Data and Property ",
         "description": "All the Data has the Property and value Associated with It",
          "type":"wiring"
     },
     {
         "id": "Entity Query",
         "description": "Entity Queries can be used to create Entity Relationship ",
         "type": "wiring"
     },
     {
         "id": "Entity Query and Entity Data",
         "description": "Entity Data Can be used to create ",
         "type": "wiring"
     }
          ],
            lastNodeId = 2,
            links = [

            ];

          // init D3 force layout
          var force = d3.layout.force()
              .nodes(nodes)
              .links(links)
              .size([width, height])
              .linkDistance(250)
              .charge(-1000)
              .gravity(0.05)
              .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', 6)
              .attr('markerHeight', 5)
              .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'),


              rect = 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 wrapText(text, width) {
              text.each(function () {
                  var textEl = d3.select(this),
                      words = textEl.text().split(/\s+/).reverse(),
                      word,
                      line = [],
                      linenumber = 0,
                      lineHeight = 1.1, // ems
                      y = textEl.attr('y'),
                      dx = parseFloat(textEl.attr('dx') || 0),
                      dy = parseFloat(textEl.attr('dy') || 0),
                      tspan = textEl.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em');

                  while (word = words.pop()) {
                      line.push(word);
                      tspan.text(line.join(' '));
                      if (tspan.node().getComputedTextLength() > width) {
                          line.pop();
                          tspan.text(line.join(' '));
                          line = [word];
                          tspan = textEl.append('tspan').attr('x', 0).attr('y', y).attr('dx', dx).attr('dy', ++linenumber * lineHeight + dy + 'em').text(word);
                      }
                  }
              });
          }



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

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

              rect.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();


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

              // update existing nodes (reflexive & selected visual states)
              rect.selectAll('rect')
                .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 = rect.enter().append('svg:g');

              //g.append('svg:rect')
              //  .attr('class', 'node')
              //  .attr('r', 30)
              g.append('svg:rect')
            .attr('class', 'node')
            .attr('width', 150)
            .attr("height", 60)
            .attr("rx", 30)
            .attr("ry", 30)
            .attr("x", -75)
            .attr("y", -16.5)
            .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; })
                  .call(wrapText, 100);

              // remove old nodes
              rect.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) {
                  rect.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) {
                 rect
                    .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();



</script>
  </body>

</html>

要在链接的中点绘制标记,您可以使用marker-mid其工作原理非常类似于marker-start and marker-end只是它在中间插入了一个标记元素。

path.enter().append('svg:path')
            .style('marker-mid', function (d) { return 'url(#start-arrow)'; })

出于演示目的,我刚刚使用了start-arrow这里,当然可以根据您的喜好进行调整。

但是,只有在中点有顶点时才会绘制标记。对于您的代码来说,情况并非如此,因为您正在绘制从源到目标的一条直线,仅定义起点和终点。另一方面,拥有一条直线会很方便,因为计算中点并将直线分成两段相当容易,从而在中间插入一个新顶点。您的计算中已经进行了计算tick()处理程序提供中间结果以帮助找到中点:

// Coordinates of mid point on line to add new vertex.
midX = (targetX - sourceX) / 2 + sourceX;   
midY = (targetY - sourceY) / 2 + sourceY;

//                                    | v --- new vertex --- v |               
return 'M' + sourceX + ',' + sourceY + 'L' + midX + ',' + midY + 'L' + targetX + ',' + targetY;

查看以下代码片段以了解工作演示。

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <script src="../D3/d3.min.js"></script>
  </head>

  <body>
      <style>
          body {
              background-color: #3a5795;
          }



svg:not(.active):not(.ctrl) {
  cursor: crosshair;
}

path.link {
  fill: none;
  stroke:floralwhite;
  stroke-width: 4px;
  cursor: default;
}

svg:not(.active):not(.ctrl) path.link {
  cursor: pointer;
}

path.link.selected {
  stroke-dasharray: 10,2;
}

path.link.dragline {
  pointer-events: none;
}

path.link.hidden {
  stroke-width: 0;
}

rect.node {
  stroke-width: 1.5px;
  cursor: pointer;
}

rect.node.reflexive {
  stroke: #000 !important;
  stroke-width: 2.5px;
}

text {
  font: 12px sans-serif;
  pointer-events: none;
}

text.id {
  text-anchor: middle;
  font-weight: bold;
}

 </style>
      <script type="text/javascript">
          // set up SVG for D3
          var width = 1400,
              height = 800,
              colors = d3.scale.category10();

          var svg = d3.select('body')
            .append('svg')
            .attr('oncontextmenu', 'return false;')
            .attr('width', width)
            .attr('height', 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 rect).
          //  - links are always source < target; edge directions are set by 'left' and 'right'.
          var nodes = [
     {
         "id": "Component",
         "description": "Component are the Containers",
          "type":"wiring"
     },
     {
         "id": "Form Design And Data Design",
         "description": "In the Form Design and Data Design we can create form and data",
         "type": "wiring"
     },
     {
         "id": "Data and Property ",
         "description": "All the Data has the Property and value Associated with It",
          "type":"wiring"
     },
     {
         "id": "Entity Query",
         "description": "Entity Queries can be used to create Entity Relationship ",
         "type": "wiring"
     },
     {
         "id": "Entity Query and Entity Data",
         "description": "Entity Data Can be used to create ",
         "type": "wiring"
     }
          ],
            lastNodeId = 2,
            links = [

            ];

          // init D3 force layout
          var force = d3.layout.force()
              .nodes(nodes)
              .links(links)
              .size([width, height])
              .linkDistance(250)
              .charge(-1000)
              .gravity(0.05)
              .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', 6)
              .attr('markerHeight', 5)
              .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'),


              rect = 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 wrapText(text, width) {
              text.each(function () {
                  var textEl = d3.select(this),
                      words = textEl.text().split(/\s+/).reverse(),
                      word,
                      line = [],
                      linenumber = 0,
                      lineHeight = 1.1, // ems
                      y = textEl.attr('y'),
                      dx = parseFloat(textEl.attr('dx') || 0),
                      dy = parseFloat(textEl.attr('dy') || 0),
                      tspan = textEl.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em');

                  while (word = words.pop()) {
                      line.push(word);
                      tspan.text(line.join(' '));
                      if (tspan.node().getComputedTextLength() > width) {
                          line.pop();
                          tspan.text(line.join(' '));
                          line = [word];
                          tspan = textEl.append('tspan').attr('x', 0).attr('y', y).attr('dx', dx).attr('dy', ++linenumber * lineHeight + dy + 'em').text(word);
                      }
                  }
              });
          }



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

          // update force layout (called automatically each iteration)
          function tick() {
                console.log(path);
              // 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),
                      midX = (targetX - sourceX) / 2 + sourceX,
                      midY = (targetY - sourceY) / 2 + sourceY;
                
                  return 'M' + sourceX + ',' + sourceY + 'L' + midX + ',' + midY + 'L' + targetX + ',' + targetY;
              });

              rect.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-mid', function (d) { return '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-mid', function (d) { return '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();


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

              // update existing nodes (reflexive & selected visual states)
              rect.selectAll('rect')
                .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 = rect.enter().append('svg:g');

              //g.append('svg:rect')
              //  .attr('class', 'node')
              //  .attr('r', 30)
              g.append('svg:rect')
            .attr('class', 'node')
            .attr('width', 150)
            .attr("height", 60)
            .attr("rx", 30)
            .attr("ry", 30)
            .attr("x", -75)
            .attr("y", -16.5)
            .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; })
                  .call(wrapText, 100);

              // remove old nodes
              rect.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) {
                  rect.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) {
                 rect
                    .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();



</script>
  </body>

</html>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将标记头放置在链接中间 的相关文章

随机推荐

  • Azure 发布:无法更新 Azure 中的 API

    我正在尝试从 Visual Studio 在 Azure 上发布我的 net3 1 web 应用程序 Visual Studio 在 开始更新 API 步骤上失败 这是 Visual Studio 的输出 Build started 1 g
  • 读取 JPEG:ImageIO.read() 弄乱了色彩空间

    我正在尝试在 Servlet 中读取 重新缩放和保存图像 这是相关代码 BufferedImage image ImageIO read file BufferedImage after new BufferedImage width he
  • 向文件夹中的所有工作簿添加新的和删除旧的 VBA

    我有大约 60 个包含多个模块的工作簿 我需要删除一个模块中的一个子例程 然后将代码添加到特定的工作表 目前 每次打开工作簿时都会运行代码 要求运行并将数据存档到另一个工作表 它可以工作 问题是我们多次出现在练习册中 所以每次打开它们时 我
  • 如何在 ASP.NET 5 中使用 JavaScriptSerializer?

    我正在将我的项目移植到DNX Core 5 0并试图找到工作 但我找不到JavaScriptSerializer and AppSettingReader类 我知道System Web已被删除 因此请任何人帮助我找到使用它们的替代方案 有没
  • 将资源管理器文件拖放到 tkinter 条目小部件中?

    我对 Python 还很陌生 我正在尝试将文件名 包含完整路径 输入到 TKinter 条目小部件 由于文件名的路径可能很长 我希望能够直接拖放文件 从 Windows 资源管理器 在 Perl 中我看到了以下内容 use Tk DropS
  • 黑洞相当于什么?

    我正在 postgreSQL 中开始一个新项目 最新 使用 MySQL 5 5 一段时间了 过去我大量使用过blackhole表来简化我的应用程序代码 它允许我在应用程序代码中进行一次插入 INSERT INTO blackhole1 va
  • tfidf.transform() 函数未返回正确的值

    我试图在某个文本语料库上拟合 tfidf 矢量器 然后使用相同的矢量器来查找新文本的 tfidf 值的总和 但是 总和值并不符合预期 下面是示例 text I am new to python and R how can anyone he
  • XCopy 不会在 Visual Studio 中复制

    我将使用 Visual Studio 中的构建后事件将 exe 复制到另一个文件夹中 每次构建都应该发生这种情况 我没有任何错误 exe 输出位于自定义文件夹中 但它不会复制到另一个文件夹中 为什么 Visual Studio 的构建输出仅
  • 在 Excel 中拆分地址字段

    我有一个 Excel 文件 其中包含带有地址的单元格 3个不同的数据示例 123 Main Street n Apartment2 n New York NY 10001 123 Main Street n New York NY 1000
  • 在 MVC3 中通过 TempData 将 MemoryStream 转换为 IMG - 有更好的方法吗?

    除其他属性外 模型还包含一个将 MSChart 作为 MemoryStream 返回的方法 在我的视图中 我将 MemoryStream 复制到 TempData Chart 然后使用 URL Action 调用控制器操作 以使用 Temp
  • 静态选项菜单

    我想为我的所有活动屏幕创建一个静态选项菜单 我不想覆盖onCreateOptionsMenu 在每项活动中 Since Menu类是一个具有大量方法的接口 很难创建实现类的静态对象 还有其他方法可以做同样的事情吗 如果我正确地阅读了你的问题
  • Duke 快速重复数据删除:java.lang.UnsupportedOperationException:尚不支持操作?

    我正在尝试使用Duke快速重复数据删除引擎在我工作的公司的数据库中搜索一些重复的记录 我从命令行运行它 如下所示 java cp C utils duke 0 6 duke 0 6 jar C utils duke 0 6 lucene c
  • 如何在javascript中过滤对象数组中的数组?

    我有一个包含电影信息的对象数组 每个对象都具有流派价值 该值可以是字符串或数组 我正在从查询字符串中获取流派并将其保存到名为流派的变量中 现在我只想整理该类型的电影 我的对象数组如下所示 movies title Apocalypse No
  • 如何使用 GDB 调试 jonesforth?

    jonesforth 通常按如下方式启动 cat jonesforth f jonesforth 有什么好的调试方法jonesforth 在Ubuntu上 如果您使用的是 Ubuntu 请允许gdb附加到正在运行的进程 echo 0 gt
  • 如何将数据从先前的 segue 传递到子视图控制器?

    我需要从 a 传递数据View Controller to a child of a parent view controller prepareSegue没有传递数据 我需要在 viewdidload 之前让它通过 这是我尝试将信息从视图
  • 返回 MySQL 中每个“group by”的“最后”行

    有没有更有效的方法来执行以下操作 select from foo as a where a id select max id from foo where uid a uid group by uid group by uid 这个答案看起
  • sed 命令 - 适用于文件夹的所有文本 (.txt) 文件

    我想应用这个 sed 命令 sed begin 644 d file1 txt gt file1 txt 到目录的所有文件 基本上我想保持相同的名称 但在找到某个字符串后删除所有行 我如何调整这个 sed 命令以应用于所有文本 txt 文件
  • 如何使用 Recharts 获取折线图上的悬停元素

    我实际上是新来的 ReactJS 中也有新功能 我想做的是 当我将鼠标悬停在值 1 行上时 只有值 1 数据才会显示在工具提示内 如您所见 此工具提示的情况并非如此 请帮助我真的需要它 在每个 Line 元素上尝试此代码 activeDot
  • 识别数组中相似的实例并将它们合并

    我有一个数组数组 像这样 Abradolf Lincler 4 Abradolf Lincler 4 Scary Terry 4 Abradolf Lincler 4 Scary Terry 4 Scary Terry 4 Abradolf
  • 如何将标记头放置在链接中间

    我想在链接中间放置一个标记 而不是像我的代码那样将其放置在末尾 尽管我用谷歌搜索了它 但我无法找到我的代码的解决方案