问题
I would like to show tooltip on hovering existing svg elements.
In the live example the elements to hover are created when binding data. In my case these elements exists already in DOM (circles). so I need to select them right after selectedElms.enter()
My question is how can I apply tip.show and tip.hide on circles ?
var data = [{
train: 1
}, {
train: 2
}, {
train: 3
}, {
train: 4
}]
var svg = d3.select('svg')
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.train + "</span>";
})
svg.call(tip);
let selectedElms = d3.selectAll('circle').data(data, function(d) {
if (d != undefined) {
return d.train
}
})
console.log('hi')
selectedElms.enter().on('mouseover', tip.show).on('mouseout', tip.hide)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"
></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<svg height="400" width="500">
<circle data='1' cx="100" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="1" />
<circle data='2' cx="200" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="2" />
<circle data='3' cx="300" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="3" />
<circle data='4' cx="400" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="4" />
</svg>
回答1:
There are just two things to correct to make it work as expected:
Like I mentioned in my answer to your first question on this topic, the key function is executed twice while matching data to DOM elements. To bind data to existing DOM elements you have to use the technique as laid out in Join existing elements of the DOM to data with d3.js. In your case the key function becomes
.data(data, function(d) { return (d && d.train) || this.id; })The first expression
d && d.trainchecks ifdrefers to an actual value and, if true, evalutates to its property.train. This is the case while the key function is executed for each datum in thedataargument. The second expressionthis.idis conditionally evaluated ifdisundefinedwhich is the case while the key function is executed for the selected, i.e. already existing, elements. If a match is found the respective datum is bound to the element.You are only interested in updating elements which already exist in the DOM. For that reason you do not need to use the enter selection at all. The update selection which is returned by
.data()will suffice. You can just drop the call to.enter().
Have a look at the following snippet to see it in action:
var data = [{
train: 1
}, {
train: 2
}, {
train: 3
}, {
train: 4
}]
var svg = d3.select('svg')
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.train + "</span>";
})
svg.call(tip);
let selectedElms = d3.selectAll('circle')
.data(data, function(d) {
return (d && d.train) || this.id;
})
selectedElms
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<svg height="400" width="500">
<circle data='1' cx="100" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="1" />
<circle data='2' cx="200" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="2" />
<circle data='3' cx="300" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="3" />
<circle data='4' cx="400" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="4" />
</svg>
来源:https://stackoverflow.com/questions/58277723/show-tooltip-on-hover-using-d3-tip-js