d3 ID选择器无法选择

时间:2018-04-16 15:46:02

标签: javascript jquery d3.js

我正在使用d3来创建一个力节点模型。我遇到一个错误,ID选择器无法找到具有特定ID的节点。我想要做的是当你的鼠标移动到节点上时,文本显示出来,当鼠标离开它时消失。但我的问题是它不会消失,因为选择器无法找到它。

我对d3很新,所以我从许多例子中复制了很多代码,看起来很混乱。我附上整个代码,以便您可以直接在浏览器中运行它。您可以查看handleMouseOuthandleMouseOver来监视主要观点。

问题看起来像是

Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#t330.17798857827233-303.63309689212775-4' is not a valid selector.

但是带有该ID的文本已经存在。你能帮我解决这个问题吗?

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Force Layout with labels on edges</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
      div.tooltip { 
        position: absolute;     
        text-align: center;     
        width: 60px;          
        height: 28px;         
        padding: 2px;       
        font: 12px sans-serif;    
        background: lightsteelblue; 
        border: 0px;    
        border-radius: 8px;     
        pointer-events: none;     
    }
</style>
</head>
<body>

<script type="text/javascript">

    var w = 1000;
    var h = 600;
    var linkDistance=200;
    radius = 20;

    var colors = d3.scale.category10();

    var dataset = {

    nodes: [
    {name: "Adam"},
    {name: "Bob"},
    {name: "Carrie"},
    {name: "Donovan"},
    {name: "Edward"},
    {name: "Felicity"},
    {name: "George"},
    {name: "Hannah"},
    {name: "Iris"},
    {name: "Jerry"}
    ],
    edges: [
    {source: 0, target: 1, weight:1},
    {source: 0, target: 2, weight:1},
    {source: 0, target: 3, weight:1},
    {source: 0, target: 4, weight:1},
    {source: 1, target: 5, weight:1},
    {source: 2, target: 5, weight:1},
    {source: 2, target: 5, weight:1},
    {source: 3, target: 4, weight:1},
    {source: 5, target: 8, weight:1},
    {source: 5, target: 9, weight:1},
    {source: 6, target: 7, weight:1},
    {source: 7, target: 8, weight:1},
    {source: 8, target: 9, weight:1}
    ]
    };


    var svg = d3.select("body").append("svg").attr({"width":w,"height":h}).call(d3.behavior.zoom().on("zoom", function () {
          svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
        })).append("g");;

    var force = d3.layout.force()
        .nodes(dataset.nodes)
        .links(dataset.edges)
        .size([w,h])
        .linkDistance([linkDistance])
        .charge([-500])
        .theta(0.1)
        .gravity(0.05)
        .start();

    var circleAttrs = {
          r: radius,
      };

       // Define the div for the tooltip
      var div = d3.select("body").append("div") 
        .attr("class", "tooltip")       
        .style("opacity", 0);

    var edges = svg.selectAll("line")
      .data(dataset.edges)
      .enter()
      .append("line")
      .attr("id",function(d,i) {return 'edge'+i})
      .style("stroke","#000")
      .style("stroke-width", function(d,i) {return d.weight + "px"})
      .style("pointer-events", "none");

    var nodes = svg.selectAll("circle")
      .data(dataset.nodes)
      .enter()
      .append("circle")
      .attr(circleAttrs)  // Get attributes from circleAttrs var
      .on("mouseover", handleMouseOver)
      .on("mouseout", handleMouseOut)
      .on("click", clicked)
      .style("fill",function(d,i){return colors(i);})
      .call(force.drag)

/*    svg.selectAll("circle")
          .data(dataset)
          .enter()
          .append("circle")
          .attr(circleAttrs)  // Get attributes from circleAttrs var
          .on("mouseover", handleMouseOver)
          .on("mouseout", handleMouseOut)
          .on("click", clicked);*/


    var nodelabels = svg.selectAll(".nodelabel") 
       .data(dataset.nodes)
       .enter()
       .append("text")
       .attr({"x":function(d){return d.x;},
              "y":function(d){return d.y;},
              "class":"nodelabel",
              "stroke":"black"})
       .text(function(d){return d.name;});

    var edgepaths = svg.selectAll(".edgepath")
        .data(dataset.edges)
        .enter()
        .append('path')
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
               'class':'edgepath',
               'fill-opacity':0,
               'stroke-opacity':0,
               'fill':'blue',
               'stroke':'red',
               'id':function(d,i) {return 'edgepath'+i}})
        .style("pointer-events", "none");

    var edgelabels = svg.selectAll(".edgelabel")
        .data(dataset.edges)
        .enter()
        .append('text')
        .style("pointer-events", "none")
        .attr({'class':'edgelabel',
               'id':function(d,i){return 'edgelabel'+i},
               'dx':80,
               'dy':0,
               'font-size':10,
               'fill':'#aaa'});

    edgelabels.append('textPath')
        .attr('xlink:href',function(d,i) {return '#edgepath'+i})
        .style("pointer-events", "none")
        .text(function(d,i){return 'label '+i});


    svg.append('defs').append('marker')
        .attr({'id':'arrowhead',
               'viewBox':'-0 -5 10 10',
               'refX':25,
               'refY':0,
               //'markerUnits':'strokeWidth',
               'orient':'auto',
               'markerWidth':10,
               'markerHeight':10,
               'xoverflow':'visible'})
        .append('svg:path')
            .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
            .attr('fill', '#ccc')
            .attr('stroke','#ccc');


    force.on("tick", function(){

        edges.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;}
        });

        nodes.attr({"cx":function(d){return d.x;},
                    "cy":function(d){return d.y;}
        });

        nodelabels.attr("x", function(d) { return d.x; }) 
                  .attr("y", function(d) { return d.y; });

        edgepaths.attr('d', function(d) { var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
                                           //console.log(d)
                                           return path});       

        edgelabels.attr('transform',function(d,i){
            if (d.target.x<d.source.x){
                bbox = this.getBBox();
                rx = bbox.x+bbox.width/2;
                ry = bbox.y+bbox.height/2;
                return 'rotate(180 '+rx+' '+ry+')';
                }
            else {
                return 'rotate(0)';
                }
        });
    });

    var formatTime = function(){
        return 'time';
      };

      // Create Event Handlers for mouse
      function handleMouseOver(d, i) {  // Add interactivity
            div.transition()    
                .duration(200)    
                .style("opacity", .9);    
            div .html(formatTime(d.date) + "<br/>"  + d.close)  
                .style("left", (d3.event.pageX) + "px")   
                .style("top", (d3.event.pageY - 28) + "px");

            // Use D3 to select element, change color and size
            d3.select(this).attr({
              fill: "orange",
              r: radius+10
            });

            // Specify where to put label of text
            svg.append("text").attr({
                id: "t" + d.x + "-" + d.y + "-" + i,  // Create an id for text so we can select it later for removing on mouseout
                x: function() { return d.x - 30; },
                y: function() { return d.y - 15; }
            })
            .text(function() {
              console.log(d);
              return [d.x, d.y];  // Value of the text
            });

          }

      var clickScale = 2.0;   // scale used when circle is clicked

      function clicked(d, i) {
        if (d3.event.defaultPrevented) {
        return; // panning, not clicking
        }
        node = d3.select(this);
        var transform = getTransform(node, clickScale);
        svg.transition().duration(1000)
           .attr("transform", "translate(" + transform.translate + ")scale(" + transform.scale + ")");
        d3.behavior.zoom().scale(transform.scale)
            .translate(transform.translate);
        scale = transform.scale;
      }

      function getTransform(node, thisScale) {
        bbox = node.node().getBBox();
        var bx = bbox.x;
        var by = bbox.y;
        var bw = bbox.width;
        var bh = bbox.height;
        var tx = -bx*thisScale + w/2 - bw*thisScale/2;
        var ty = -by*thisScale + h/2 - bh*thisScale/2;
        return {translate: [tx, ty], scale: thisScale}
      }

      function handleMouseOut(d, i) {
            div.transition()    
                .duration(500)    
                .style("opacity", 0); 
            // Use D3 to select element, change color back to normal
            d3.select(this).attr({
              fill: "grey",
              r: radius
            });

            // Select text by id and then remove

            d3.select("#t" + d.x + "-" + d.y + "-" + i).remove();  // Remove text location
          }

</script>

</body>
</html>

1 个答案:

答案 0 :(得分:3)

错误很清楚,也是正确的; #t330.17798857827233-303.63309689212775-4确实是一个无效的选择器。 .引入了一个类选择器,不允许类选择器以未转义的数字开头。

要按ID获取元素,最好的选择是getElementById

var theElement = document.getElementById("t330.17798857827233-303.63309689212775-4");

请注意,&#39;没有前导#,因为getElementById没有使用CSS语法。

如果 使用CSS选择器,则可以使用属性选择器:

var theElement = document.querySelector('[id="t330.17798857827233-303.63309689212775-4"]');

这样,整个值就作为要查找的ID。