问题
I'm trying to add a tooltip showing the name of districts when you hover over it in the map in d3.js. The input is a topojson file and I've been able to successfully generate the map with district boundaries and highlight the currently selected district.
For the tooltip I tried doing something similar to this, but nothing happens at all. The code I've used is given below. The tooltip code is towards the end.
var width = 960,
height = 600;
var projection = d3.geo.albers()
.center([87, 28])
.rotate([-85, 0])
.parallels([27, 32]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6);
d3.json("data/nepal3.json", function(error, npl) {
var districts = topojson.feature(npl, npl.objects.nepal_districts);
projection
.scale(1)
.translate([0, 0]);
var b = path.bounds(districts),
s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
projection
.scale(s)
.translate(t);
g.selectAll(".nepal_districts")
.data(districts.features)
.enter().append("path")
.attr("class", function(d) { return "nepal_districts " + d.id; })
.attr("d", path)
.on("mouseover", function(d,i) {
d3.select(this.parentNode.appendChild(this)).transition().duration(300)
.style({'stroke-width':2,'stroke':'#333333','stroke-linejoin':'round','cursor':'pointer','fill':'#b9270b'});
})
.on("mouseout", function(d,i) {
d3.select(this.parentNode.appendChild(this)).transition().duration(100)
.style({'stroke-width':2,'stroke':'#FFFFFF','stroke-linejoin':'round','fill':'#3d71b6'});
});
g.append("path")
.datum(topojson.mesh(npl, npl.objects.nepal_districts, function(a, b) { return a !== b;}))
.attr("d", path)
.attr("class", "district-boundary");
/* Tooltip */
g.selectAll(".nepal_districts")
.data(districts.features)
.enter().append("text")
.append("svg:rect")
.attr("width", 140)
.attr("height", 140)
.text(function(d) { return d.properties.name; })
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
function mouseover() {
div.transition()
.duration(300)
.style("opacity", 1);
}
function mousemove() {
div
.text(d3.event.pageX + ", " + d3.event.pageY)
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
}
function mouseout() {
div.transition()
.duration(100)
.style("opacity", 1e-6);
}
});
The CSS is
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: #4c4c4c;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
The code I added for "Tooltip" does nothing at all. What am I doing wrong here?
The topojson file has this format. I wanted to get the "name" property to show up in the Tooltip.
{
"type": "Topology",
"objects": {
"nepal_districts": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Polygon",
"id": 0,
"properties": {
"name": "HUMLA"
},
"arcs": [
[
0,
1,
2,
3
]
]
},
回答1:
Had a similar problem where I ended up adding absolute positioned tooltip to body element, and modyfying its placement according to mouse position.
Add to directive:
function addTooltip(accessor) {
return function(selection) {
var tooltipDiv;
var bodyNode = d3.select('body').node();
selection.on("mouseover", function(topoData, countryIndex) {
if (!accessor(topoData, countryIndex)) {
return;
}
// Clean up lost tooltips
d3.select('body').selectAll('div.tooltipmap').remove();
formatValue(topoData, countryIndex);
tooltipDiv = d3.select('body').append('div').attr('class', 'tooltipmap');
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv.style('left', (absoluteMousePos[0] + 10) + 'px')
.style('top', (absoluteMousePos[1] - 15) + 'px')
.style('opacity', 1)
.style('z-index', 1070);
accessor(topoData, countryIndex) || '';
})
.on('mousemove', function(topoData, countryIndex) {
if (!accessor(topoData, countryIndex)) {
return;
}
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv.style('left', (absoluteMousePos[0] + 10) + 'px')
.style('top', (absoluteMousePos[1] - 15) + 'px');
var tooltipText = accessor(topoData, countryIndex) || '';
tooltipDiv.html(tooltipText);
})
.on("mouseout", function(topoData, countryIndex) {
if (!accessor(topoData, countryIndex)) {
return;
}
tooltipDiv.remove();
});
};
.tooltipmap{
background-color: #000000;
margin: 10px;
height: 50px;
width: 150px;
padding-left: 10px;
padding-top: 10px;
border-radius: 5px;
overflow: hidden;
display: block;
color: #FFFFFF;
font-size: 12px;
position: absolute;
opacity: 1;
h6{
margin: 0;
padding: 0;
}
p{
color: #FFFFFF;
}
}
Hope it helps!
来源:https://stackoverflow.com/questions/20070919/adding-tooltip-in-d3-js-map