Yet another javascript beginner with a closure issue... However, I have been reading up on various sources on closure binding (most helpful), but I still can't fully transfer this to my specific issue.
For convenience, I have prepared a minimal jsfiddle. My problem is to use d3-tip with multiple, different rendering logics. In the jsfiddle you can see a plot on the top and one below. When you hover the mouse over the boxes, each plot should generate its own tooltip. However, as you can see, the first plot also uses the tooltip callback of the second plot. Or more general: The last tooltip callback overwrites previous callbacks.
The implementation follows some standard d3 / d3-tip patterns. Basiscally I have multiple plotting functions like this:
function somePlottingFunction(data, locator) {
var svg = ... // append svg
// define plot-specific tooltip logic
function tipRenderer(d) {
return "Renderer of plot 1: " + d;
}
tip = d3.tip()
.attr("class", "d3-tip")
.html(tipRenderer);
svg.call(tip);
// and a .enter()
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
// ... attr ...
.on("mouseover", (d) => tip.show(d)) // <= issue here
.on("mouseout", (d) => tip.hide(d));
}
The code does work when simply using .on("mouseover", tip.show)
. However in my actual code, I need additional logic in mouseover
, which is why I need a wrapping closure. My questions are:
- Why does the closure close over the wrong
tip
variable? Or rather: How can the second plotting function modify the closure binding of the first function? - How would an experience javascript programmer solve this?
Note: In the jsfiddle the two plotting functions (and the tooltip logics) are almost identical to keep the example small, which suggest to simply use the same tipRenderer
anyway. My actual use case is a page with entirely different plots, and thus, the tooltip rendering cannot (or should not) be unified.