Andrej Andrej - 1 month ago 9
Javascript Question

Show and hide additional element in d3.js

I have a simple script (also on JSFiddle) which draws scatterplot from given data. When I go over the data point on the scatter the script should display red circle below my chart; and vice versa, when the event "mouseout" is called the circle should disappear.

Now the red circle is shown when the "mouseover" event is called, but the circle appends to other circles. I wonder how to properly implement show/hide functionality in this case.

The code is pasted below.

var data = [[4,3], [3,3], [1,4], [2,3]];

var margin = {top: 20, right: 15, bottom: 60, left: 60},
width = 500 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;

var x = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d[0]; })])
.range([ 0, width ]);

var y = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d[1]; })])
.range([ height, 0 ]);

var chart = d3.select('body')
.append('svg:svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.attr('class', 'chart')

var main = chart.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.attr('width', width)
.attr('height', height)
.attr('class', 'main')

// Draw the x axis
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom');

main.append('g')
.attr('transform', 'translate(0,' + height + ')')
.attr('class', 'main axis date')
.call(xAxis);

// draw the y axis
var yAxis = d3.svg.axis()
.scale(y)
.orient('left');

main.append('g')
.attr('transform', 'translate(0,0)')
.attr('class', 'main axis date')
.call(yAxis);

var g = main.append("svg:g");

g.selectAll("scatter-dots")
.data(data)
.enter().append("svg:circle")
.attr("cx", function (d,i) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5);

// FUNCTION TO DISPLAY CIRCLE BELO CHART
g.on('mouseover', function(){
div.style("display", "block")
div.append("svg")
.attr("width", 50)
.attr("height", 50)
.append("circle")
.attr("cx", 25)
.attr("cy", 25)
.attr("r", 25)
.style("fill", "red");
});

g.on('mouseout', function(){
div.style("display", "none")
});

var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("display", "none");

Answer

You're appending a new SVG every time you hover the circle.

An easy and lazy solution is removing the SVG on "mouseout":

g.on('mouseout', function(){
    div.select("svg").remove();
});

Here is your fiddle: https://jsfiddle.net/39pmwzzh/