I'm trying to add a tooltip with data on a choropleth map. It already appears on mouse over but I'm stuck trying to show the data that's in the csv file I used to create the map. I'd like to show the "name" + "pop" + "%".
Here's how I loaded the data:
d3.queue()
.defer(d3.json, "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson")
.defer(d3.csv, "https://raw.githubusercontent.com/lcercos/geojson/main/eurostat_data-map.csv", function(d) { data.set(d.code, +d.pop); })
.await(ready);
Here's the on mouse over function:
function ready(error, topo) {
var div = d3.select("body").append("div") // calling tooltip
.attr("class", "tooltip")
.style("opacity", 0);
let mouseOver = function(d) {
d3.selectAll(".Country")
.transition()
.duration(100)
.style("opacity", .5)
d3.select(this)
.transition()
.duration(100)
.style("opacity", 1)
.style("stroke", "black");
div.transition()
.duration(50)
.style("opacity", 1);
div.html(d.name + d.value + "%") // html data <- Is here the problem?
.style("left", (d3.event.pageX + 15) + "px")
.style("top", (d3.event.pageY - 10) + "px");
}
let mouseLeave = function(d) {
d3.selectAll(".Country")
.transition()
.duration(0)
.style("opacity",)
d3.select(this)
.transition()
.duration(0)
.style("stroke", "transparent");
div.transition()
.duration("50")
.style("opacity", 0);
}
Related
I have created a multiline chart from an array of objects with nested data, however the circles are only appended to 1 line. I am using react on the frontend and getting the data from a rest api, As shown in this image Example The lines are created and the tooltip on the circles works properly but only one line has circles appended.
Object.values(data).forEach(item => {
var valueline = d3
.line()
.x(function(d) {
return x(d.circuit);
})
.y(function(d) {
return y(+d.points);
});
var colorScale = d3
.scaleSequential(interpolateRainbow) //.scaleSequential(d3.interpolateRainbow)
.domain([1, 20]);
console.log(colorScale(1));
svg
.append("path")
.data([item.results])
.attr("class", "line")
.style("stroke", colorScale(item.constructor))
.attr("d", valueline);
var xScale = d3
.scaleLinear()
.domain([0, item.results.length-1]) // input
.range([0, width]); // output
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
svg
.selectAll(".dot")
.data(item.results)
.enter()
.append("circle") // Uses the enter().append() method
.attr("class", "dot")
.attr("r", 5) // Assign a class for styling
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d, i) {
return y(d.points);
}).on("mouseover", function(d) {
let points = item.results.filter(xd => xd.circuit==d.circuit)[0].points
div.transition()
.duration(200)
.style("opacity", .9);
div .html(item.name + "<br/>" + points)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
Try the changes below noting the use of an iterator to differentiate the class/selection of dots for each line. You could use something else like an attribute of the data e.g. name etc.
Also not i've moved the line and color scale functions out of your forEach loop as they don't need to be declared multiple times. The same applies to your tooltip which could resused instead of adding multiple divs to the DOM.
var valueline = d3
.line()
.x(function(d) {
return x(d.circuit);
})
.y(function(d) {
return y(+d.points);
});
var colorScale = d3
.scaleSequential(interpolateRainbow) //.scaleSequential(d3.interpolateRainbow)
.domain([1, 20]);
console.log(colorScale(1));
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
Object.values(data).forEach((item,k) => {
svg
.append("path")
.data([item.results])
.attr("class", "line")
.style("stroke", colorScale(item.constructor))
.attr("d", valueline);
var xScale = d3
.scaleLinear()
.domain([0, item.results.length-1]) // input
.range([0, width]); // output
svg
.selectAll(".dot-"+k)
.data(item.results)
.enter()
.append("circle") // Uses the enter().append() method
.attr("class", "dot-"+k)
.attr("r", 5) // Assign a class for styling
.attr("cx", function(d, i) {
return xScale(i);
})
.attr("cy", function(d, i) {
return y(d.points);
}).on("mouseover", function(d) {
let points = item.results.filter(xd => xd.circuit==d.circuit)[0].points
div.transition()
.duration(200)
.style("opacity", .9);
div .html(item.name + "<br/>" + points)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
I would like to ask if anyone know how to get the code to do similar chart like this https://www.theguardian.com/world/interactive/2013/feb/12/state-of-the-union-reading-level
It is written in D3 but I couldn't find similar codes online.
Thanks
I think this is just a fairly involved tooltip on a scatter plot. Here's a simpler example:
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); })
.on("mouseover", function(d) {
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");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
You might also find this other example useful.
I draw a line graph using D3.js and i am using tooltip in line graph,but i am also using tooltip in legends but enable to show the tooltip in legends,i wrote given code,it is possible to show the tooltip in legends.
var dates=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31];
var legend = canvas.append("g")
.attr("class", "legend")
// .attr("transform", "translate(70,10)");
var legendRect = legend.selectAll('rect').data(dates);
legendRect.enter()
.append("rect")
.attr("x", function (d,i){return i*14;})
.attr("width", 12)
.attr("height", 20)
.attr("y", 10)
.style("fill","steelblue")
legend.selectAll("text")
.data(dates)
.enter()
.append("text")
.attr("x", function (d,i){return i*14;})
.attr("y", 25)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.text(function(d) {
return d;
})
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(formatTime(d.key) + "<br/>" + d.value)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY-28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
Iam adding tooltip in text but enable to show the tooltip in my values(I have only problem in legend tooltip)
Check out this code. It does exactly what you want.
This is also a great example.
I have a bar chart and I have text values at the end of each bar. What I would like to do is set text to invisible, and on mouseover I'd like it to show the number associated with the bar, at the magnitude of that bar. I'm having trouble figuring out how to do this in an efficient manner.
var tooltip = d3.select("body").append("div")
.style("position", "absolute")
.attr("class", "tooltip")
.style("opacity", 0);
var rect = svg.selectAll("rect")
.attr("class", "rect")
.data(dataset)
.enter()
.append("rect")
.attr("y", function(d,i){
return yScale(i);
})
.attr("x", 0)
.attr("width", function(d,i){
return xScale(d);
})
.attr("height", h/dataset.length)
.style("fill", function(d,i){
return colors(d);
})
.on("mouseover", function(d){
d3.select(this).style("opacity", 0.5)
tooltip.transition()
.duration(200)
.style("opacity", 1);
tooltip.html(d)
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + "px")
})
.on("mouseout", function(d){
d3.select(this).style("opacity", 1)
tooltip.transition()
.duration(500)
.style("opacity", 0)
});
Instead of mouseover and mouseout, I recommend doing it with $(this).hover and $(this).mousemove. Try something like this:
$(this).hover(
function() {
tooltip.transition()
.duration(200)
.style("opacity", 1)
// In order to trigger the magnitude or 'width' of the rect:
var rectWidth = $(this).attr("width");
}, function () {
tooltip.transition()
.duration(500)
.style("opacity", 1e-6)
}
);
/*$(this).mousemove(function(event) {
tooltip
.style("left", event.clientX + "px")
.style("top", event.clientY + "px")
});*/
I made a line graph with d3.js (see the attached image1).
I managed to insert tooltips on graph dots when mouseover.
I'd like to change color and size of dots too. I tried in many ways but it seems really difficult. Any help?
Here is the piece of code:
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5.5)
.style("fill", "#fff8ee")
.style("opacity", .8) // set the element opacity
.style("stroke", "#f93") // set the line colour
.style("stroke-width", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); })
.on("mouseover", function(d) {
div.transition()
.duration(70)
.style("opacity", .7)
;
div .html(formatTime(d.date) + "<br/>" + d.close)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(200)
.style("opacity", 0);
});
Just set color and size in the handlers:
.on("mouseover", function(d) {
d3.select(this).attr("r", 10).style("fill", "red");
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 5.5).style("fill", "#fff8ee");
});
I don't know why, but while d3.select(this) used to work, it doesn't anymore. I now use d3.select(event.currentTarget).
So, if we consider svg as the graph and all its circles being red by default, we can change the color of the circles to green on mouseover and return the color to red on mouseout like this:
svg.on("mouseover", function(d){
d3.select(event.currentTarget)
.style("fill", "green");
})
.on("mouseout", function(d){
d3.select(event.currentTarget)
.style("fill", "red");
});