我正在使用d3来创建一个力节点模型。我遇到一个错误,ID选择器无法找到具有特定ID的节点。我想要做的是当你的鼠标移动到节点上时,文本显示出来,当鼠标离开它时消失。但我的问题是它不会消失,因为选择器无法找到它。
我对d3很新,所以我从许多例子中复制了很多代码,看起来很混乱。我附上整个代码,以便您可以直接在浏览器中运行它。您可以查看handleMouseOut
和handleMouseOver
来监视主要观点。
问题看起来像是
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>
答案 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。