Tooltip overwritten for moving images in D3 - d3.js

Here i'm working on moving images dynamically with random x and y, inside a zooming & dragging SVG. And also added tooltip for these images inside the loop itself. When the tooltip appears its content is overwritten with last element's tooltip. Please check out the FIDDLE. In the following code, inside the for loop, I try to display the tooltip as "user tooltip:"+i, but the last tooltip content is displayed for all the images.
for(var i in icons){
var rectx = Math.floor(Math.random()*(max-min+1)+min);
var recty = Math.floor(Math.random()*(max-min+1)+min);
//console.log("i : "+i);
if(icons[i]=="user"){
var tip="user tooltip: "+i;
console.log(tip);
svg.append("image")
.attr("id","user"+i)
.attr('x',rectx)
.attr('y',recty)
.attr('width', 30)
.attr('height', 24)
.attr("xlink:href", "http://www.worryfreelabs.com/wp-content/uploads/2016/06/WFl_logo-2015-icon-only-white-background.png")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html("user tooltip: "+i)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
}
}

The problem is with the scope of the variable. You can resolve this issue by implementing the functionality in a d3 way. Using enter method.
var imgHeight = 1025,
imgWidth = 1538, // Image dimensions (don't change these)
width = 500,
height = 500, // Dimensions of cropped region
translate0 = [-290, -180],
scale0 = 1; // Initial offset & scale
svg = d3.select("body").append("svg")
.attr("width", width + "px")
.attr("height", height + "px");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width + "px")
.attr("height", height + "px");
svg = svg.append("g")
.attr("transform", "translate(" + translate0 + ")scale(" + scale0 + ")")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
.append("g");
svg.append("image")
.attr("width", imgWidth + "px")
.attr("height", imgHeight + "px")
.attr("xlink:href", "http://www.myfreetextures.com/wp-content/uploads/2015/01/deep-green-grass-texture.jpg");
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var max = 400,
min = 200;
var icons = ["user", "user", "table"];
svg.selectAll("image.icon")
.data(icons.filter(function(d) {
return d == "user";
}))
.enter()
.append("image")
.classed("icon", true)
.attr("id", function(d, i) {
return "user" + i;
})
.attr('x', function() {
return Math.floor(Math.random() * (max - min + 1) + min);
})
.attr('y', function() {
return Math.floor(Math.random() * (max - min + 1) + min);
})
.attr('width', 30)
.attr('height', 24)
.attr("xlink:href", "http://www.worryfreelabs.com/wp-content/uploads/2016/06/WFl_logo-2015-icon-only-white-background.png")
.on("mouseover", function(d, i) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("user tooltip: " + i)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
setInterval(function() {
for (var i in icons) {
if (icons[i] == "user") {
d3.select("#user" + i).transition()
.delay(1000)
.attr('x', function(d) {
return Math.random() * 720 - 29;
})
.attr('y', function(d) {
return Math.random() * 200 - 30;
})
.duration(6000)
}
}
}, 500);
.overlay {
fill: none;
pointer-events: all;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Related

Adding transition animation breaking tooltip mouseover [duplicate]

This question already has an answer here:
D3: .transition() not working with events
(1 answer)
Closed 2 years ago.
I am adding animations to my scatterplot points in my d3.js line graph and when I added them in I noticed that the it broke my mouseover event listener for the tooltips that appear for each circle. The error message that I am receiving Uncaught Error: unknown type: mouseover and I'm wondering why the animation would break the event listener. Is it because I have it in the chain for the circle earlier than the event listener meaning that it is trying to call the method on the animation rather than the circle?
Here is my code:
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script>
var data = [
{ "x": "2020-04-26", "y": 461.0, "label": "7:41" },
{ "x": "2020-04-27", "y": 421.0, "label": "7:01" },
{ "x": "2020-04-28", "y": 519.0, "label": "8:39" },
{ "x": "2020-04-29", "y": 502.0, "label": "8:22" },
{ "x": "2020-04-30", "y": 511.0, "label": "8:31" },
{ "x": "2020-05-01", "y": 513.0, "label": "8:33" }
]
// D3 date parser
for (var i=0; i < data.length; i++){
var parser = d3.timeParse("%Y-%m-%d")
data[i].date = parser(data[i].x);
}
console.log(data)
var margin = { top: 10, right: 30, bottom: 30, left: 60 }
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#my_dataviz")
.append("svg")
.attr( 'preserveAspectRatio',"xMinYMin meet")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // translate(margin left, margin top)
var x = d3.scaleTime()
.domain([d3.min(data, function(d) { return d.date }), d3.max(data, function(d) { return d.date })])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," + (height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d){ return +d.y })])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Asleep (Minutes)");
// Add line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.y) })
);
// Add the scatterplot (data points)
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
.transition()
.delay(function(d,i){ return (i*3)})
.duration(2000)
.attr("cx", function(d){ return x(d.date) })
.attr("cy", function(d){ return y(d.y) })
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
</script>
.on is not part of a transition, you must put it before the transition. Try something like this:
.enter()
.append("circle")
.attr("r", 3)
// Add tooltip on hover
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.x + "<br/>" + d.label)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px")
})
// Remove tooltip after hover
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.delay(function(d,i){ return (i*3)})
.duration(2000)
.attr("cx", function(d){ return x(d.date) })
.attr("cy", function(d){ return y(d.y) });

Displaying correct X-coordinate value on the scatter point tooltip

In my scatterplot, I am hovering on the points, to generate a tooltip. But, my X-cordinate values are not right, corresponding to the graph axis. Can a clue be provided for the same??
One thing to note- I have 2 dataset arrays- 1 corresponds to Y value, the other corresponds to Y-Error values.
var width = 700;
var height = 700;
var padding = 90;
var myData = [12, 18, 20, 9, 17, 25, 30];
var errData = [6, 9, 10, 4.5, 8.5, 12.5, 15];
var svg = d3.select("body").
append("svg")
.attr("width", width)
.attr("height", height);
var Mydiv = d3.select("body")
.append("div")
//.append("span")
//.text('X')
.data(myData)
.attr("class", "toolDiv")
//.attr("span", "close")
.style("opacity", "0");
var MyLine = d3.select("body")
.append("div")
.data(myData)
.attr("class", "error-line");
//.style("opacity", 1);
//var m1 = d3.max(myData + errData)
var yScale = d3.scaleLinear().domain([0, d3.max(myData)]).range([height / 2, 50]);
var xScale = d3.scaleLinear().domain([0, d3.max(myData)]).range([0, width - 100]);
var y_ErScale = d3.scaleLinear().domain([0, d3.max(errData)]).range([height / 2, 50]);
var x_ErScale = d3.scaleLinear().domain([0, d3.max(errData)]).range([0, width - 100]);
var valueline = d3.selectAll("scatter-dots")
.append("line")
.attr("x", function(d, i) {
return xScale(myData[i]);
})
.attr("y", function(d) {
return yScale(d);
});
//.curve();
svg.append("g")
.selectAll("scatter-dots")
.data(myData)
.enter()
.append("line")
.data(myData)
.attr("class", "line")
.attr("d", valueline);
// .style("opacity", 0);
var eBar = d3.select("body").append("svg");
//var x_min =
var x_axis = d3.axisBottom()
.scale(xScale);
var y_axis = d3.axisLeft()
.scale(yScale);
svg.append("g")
.attr("transform", "translate(50, 10)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(50, " + xAxisTranslate + ")")
.call(x_axis);
svg.append("text")
.attr("transform",
"translate(" + (width / 1.2) + " ," + (height - 280) + ")")
.style("text-anchor", "middle")
.style("left", "70px")
.text("Points");
svg.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," + (height - 280) + ")")
.style("text-anchor", "middle")
.style("left", "70px")
.text("X-Axis");
svg.append("text")
.attr("transform",
"translate(" + (height / 40) + " ," + (width - 500) + ")rotate(-90)")
.style("text-anchor", "middle")
.style("left", "70px")
.text("Y-Axis");
// svg.append("text")
// .attr("transform",
// "translate(" + (height/10) + " ," + (width - 690) + ")rotate(-90)")
// .style("text-anchor", "middle")
// .style("left", "70px")
// .text("Y");
svg.append("g")
.selectAll("scatter-dots")
.data(myData)
.enter().append("svg:circle")
.attr("cx", function(d, i) {
return xScale(myData[i]);
})
.attr("cy", function(d) {
return yScale(d);
})
.attr("r", 3)
.style("opacity", 0.8)
.style("cursor", "help")
// .on("click", function(d, i){
// var active = Mydiv.active ? false : true ,
// newOpacity = active ? 0 : 0.9;
// Mydiv.transition()
// .duration(200)
// .style("opacity", newOpacity);
// Mydiv.html("X" + "-" + errData[i] + "<br/>" + "Y" + "-" + myData[i] )
// .style("left", (d3.event.pageX + 10) + "px")
// .style("top", (d3.event.pageY - 18) + "px");
// Mydiv.active = active;
// });
.on("mouseover", function(d, i) {
//console.log(this);
//console.log(d3.select(this));
//d3.select(this);
//console.log(d3.select(this));
Mydiv.transition()
.duration(200)
.style("opacity", 0.9);
Mydiv.html("X" + "-" + errData[i] + "<br/>" + "Y" + "-" + myData[i])
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
//div.html(yScale(d));
})
.on("mouseout", function(d) {
Mydiv.transition()
.duration(500)
.style("opacity", 0);
});
// var errorBar = eBar.append("path")
// .attr("d", yScale(errData))
// .attr("stroke", "red")
// .attr("stroke-width", 1.5);
// svg.append("g")
// .selectAll("error-bars")
// .data(errData)
// .enter().append("svg:path")
// .attr("cx", function (d,i) { return x_ErScale(errData[i]); } )
// .attr("cy", function (d) { return y_ErScale(d); } )
// .attr("stroke", "red")
// .attr("stroke-width", 1.5);
svg.append("g")
.selectAll("line")
.data(errData)
.enter()
.append("line")
.attr("class", "error-line")
.attr("x1", function(d) {
return x_ErScale(d);
})
.attr("y1", function(d) {
return y_ErScale(d) + 30;
})
.attr("x2", function(d) {
return x_ErScale(d);
})
.attr("y2", function(d) {
return y_ErScale(d) + 2;
})
.on("mouseover", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "1");
//.style("fill-opacity", 0);
})
.on("mouseout", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", 0.0);
//.style("fill-opacity", 1);
});
svg.append("g").selectAll("line")
.data(errData).enter()
.append("line")
.attr("class", "error-cap")
.attr("x1", function(d) {
return x_ErScale(d) - 8;
})
.attr("y1", function(d) {
return y_ErScale(d) - 30;
})
.attr("x2", function(d) {
return x_ErScale(d) + 8;
})
.attr("y2", function(d) {
return y_ErScale(d) - 30;
});
svg.append("g")
.selectAll("line")
.data(errData)
.enter()
.append("line")
.attr("class", "error-line")
.attr("x1", function(d) {
return x_ErScale(d);
})
.attr("y1", function(d) {
return y_ErScale(d) - 30;
})
.attr("x2", function(d) {
return x_ErScale(d);
})
.attr("y2", function(d) {
return y_ErScale(d) - 2;
})
.on("mouseover", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "1");
//.style("fill-opacity", 0);
})
.on("mouseout", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "0.6");
//.style("fill-opacity", 1);
});
// .on("mouseover", function(d){
// MyLine.transition()
// .duration(200)
// .style("opacity", 0);
// })
// .on("mouseout", function(d){
// MyLine.transition()
// .duration(200)
// .style("opacity", 1);
// });
// Add Error Bottom Cap
svg.append("g").selectAll("line")
.data(errData).enter()
.append("line")
.attr("class", "error-cap")
.attr("x1", function(d) {
return x_ErScale(d) - 8;
})
.attr("y1", function(d) {
return y_ErScale(d) + 30;
})
.attr("x2", function(d) {
return x_ErScale(d) + 8;
})
.attr("y2", function(d) {
return y_ErScale(d) + 30;
});
//svg.selectAll("scatter-dots")
// .data(myData)
// .enter()
// .on("mouseover", function()
// {
// //console.log(this);
// //console.log(d3.select(this));
// //d3.select(this);
// //console.log(d3.select(this));
// //div.transition()
// //.duration(200)
// //.style("opacity", 0.8);
// //div.html(myData);
// });
//// .on("mouseout", function(d)
//// {
//// div.transition()
//// .duration(500)
//// .style("opacity", 0);
//// });
/*body {
font: 10px sans-serif;
}
*/
#d1 {
position: relative;
top: 100px;
}
#svg1 {
position: relative;
bottom: 80px;
}
.axis_path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis_line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
cursor: pointer;
}
.error-line {
stroke: #b30059;
stroke-width: 2px;
opacity: 0.6;
stroke-dasharray: 2;
/*fill-opacity: 1;*/
/*opacity: 1;*/
}
.error-cap {
stroke: #b30059;
stroke-width: 2px;
stroke-type: solid;
}
.toolDiv {
position: absolute;
text-align: center;
width: 120px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
/*.toolDiv.image
{
position: static;
content: url(http://wfarm1.dataknet.com/static/resources/icons/set28/7f8535d7.png);
}*/
/*.close {
width: 10px;
height: 10px;
background: #fff;
position: absolute;
top: 0;
right: 0;
background: url('http://i.imgur.com/Idy9R0n.png') no-repeat 0 0;
cursor: pointer;
}
.close:hover {
background-position: -13px 0;
}*/
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
<head>
<title>Scatter Plot Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> -->
<link rel="stylesheet" type="text/css" href="scatter.css">
</head>
<body>
<script src="scatterplot.js" type="text/javascript"></script>
<div id="d1">
<svg id="svg1">
<div id="d2"></div>
</svg>
</div>
</body>
I've included a fiddle for reference.

Why is my D3.js tooltip not working

I tried to use the following code to show a d3.js tool-tip effect but I can't get it to work, why is the number not showing up:
<style>
svg {
width: 100%;
height: 100%;
position: center;
}
#hist_sexage {
background-color: lightgrey;
}
.rect:hover {
fill: yellow;
}
.tooltip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 red;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: blue;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
</style>
<svg id="hist_sexage" width="950" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var margin = {top: 30, right: 30, bottom: 40, left: 30};
var width = document.getElementById("hist_sexage").getBoundingClientRect().width-50;
var height = 400;
var g = d3.select("#hist_sexage")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.2);
var x1 = d3.scaleBand()
.padding(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["cornflowerblue", "orangered"]);
d3.csv("/blog/data/age_by_gender.csv",function(d, i, columns) {
for (var i = 1, n = columns.length; i < n; ++i) d[columns[i]] = +d[columns[i]];
return d;
},
function(error, data) {
if (error) throw error;
var keys = data.columns.slice(1);
x0.domain(data.map(function(d) { return d.Age_Group; }));
x1.domain(keys).rangeRound([0, x0.bandwidth()]);
y.domain([0, d3.max(data, function(d) { return d3.max(keys, function(key) { return d[key]; }); })]).nice();
g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x0(d.Age_Group) + ",0)"; })
.selectAll("rect")
.data(function(d) { return keys.map(function(key) { return {key: key, value: d[key]}; }); })
.enter().append("rect").attr("class", "rect")
.attr("x", function(d) { return x1(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x1.bandwidth())
.attr("height", function(d) { return height - y(d.value); })
.attr("fill", function(d) { return z(d.key); })
.on("mouseover", function() { tooltip.style("display", null); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 5;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.value);
console.log(d.value)
})
.on("mouseout", function() { tooltip.style("display", "none"); });
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.1em")
.attr("transform", "rotate(-45)" );;
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, ".0%"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Percentage");
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
});
// Prep the tooltip bits, initial display is hidden
var tooltip = d3.select("#hist_sexage").append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("g:rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "red")
.style("opacity", 0.5);
tooltip.append("g:text")
.attr("x", 30)
.attr("y", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
</script>
I am expecting to see it, if I move over the bar, it should show the number alongside with my cursor but it does not. Can you please help me troubleshoot this issue?
Thanks,
Well, you can't see the tooltip for a simple reason. You set its display to none...
.style("display", "none");
... but you forgot to change its style on mousemove. Therefore, its children will never be rendered.
Here is a working demo with fake data, changing the style in the mousemove:
var svg = d3.select("#hist_sexage");
var data = [30, 250, 120, 150, 90];
var rects = svg.selectAll("jamesWatson")
.data(data)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", function(d, i) {
return i * 20
})
.attr("height", 15)
.attr("width", function(d) {
return d
})
.attr("fill", "teal")
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] + 10;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.style("display", "inline")
.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d);
})
.on("mouseout", function() {
tooltip.style("display", "none");
});
var tooltip = d3.select("#hist_sexage").append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("g:rect")
.attr("width", 60)
.attr("height", 20)
.attr("fill", "red")
.style("opacity", 0.5);
tooltip.append("g:text")
.attr("x", 30)
.attr("y", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg id="hist_sexage"></svg>

Trying to add an id to a circle

I am doing research for a professor at my school and I am coding in d3. I am creating a graph that has tool tips and you can toggle the graph by clicking on the legend. However, when I toggle the lines disappears but I can't get the tool tips associated to that line. I know I need to somehow add an id to these circles but I have no idea how. I have included my code below to show what I have so far. Any help would be appreciated!
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: white;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 170px;
height: 500px;
padding: 1px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 5px;
pointer-events: none;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 20, right: 150, bottom: 60, left: 80},
width = 1160 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Parse the date / time
// Set the ranges
var x = d3.scaleTime().range([0, width-100]);
var formatxAxis=d3.format('.0f');
var y = d3.scaleLinear().range([height, 0]);
// Define the axe
var xAxis = d3.axisBottom().scale(x)
.tickFormat(formatxAxis).ticks(20);
var yAxis = d3.axisLeft().scale(y)
.ticks(5);
// Define the line
var valueline = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.year); })
.y(function(d) { return y(d.count); });
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("satisfaction.json", function(error, data) {
data.forEach(function(d) {
d.year = +d.year;
d.count = +d.count;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
//nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {
return d.word;
})
.entries(data);
//define colors for the lines
var color = d3.scaleOrdinal(d3.schemeCategory10);
// spacing for the legend
legendSpace = width/dataNest.length;
var circleid = svg.selectAll("circle")
.data(dataNest)
.enter()
.append("g")
.attr("id", function(d){
return "circle" + d.key.replace(/\s+/g, '');
});
// Loop through each symbol / key
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key); })
.attr("id", 'tag'+d.key.replace(/\s+/g, '')) // assign ID
.attr("d", valueline(d.values));
// Add the Legend
svg.append("text")
.attr("x", width - margin.left + 50)
.attr("y", legendSpace/4 + i*(legendSpace/6))
.attr("class", "legend") // style the legend
.style("fill", function() { // Add the colours dynamically
return d.color = color(d.key); })
.on("click", function(){
// Determine if current line is visible
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements based on the ID
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(100)
.style("opacity", newOpacity);
// Update whether or not the elements are active
d.active = active;
// Hide or show the elements based on the ID
d3.select("circle" + d.key.replace(/\s+/g, ''))
.transition().duration(100)
.style("opacity", newOpacity);
})
.text(d.key);
});
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.count); })
.on("click", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.word + "<br/>" + d.count + "<br/>" + d.songs)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 25) + "px");
})
.on("dblclick", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
;
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
Right now, you are trying to set your id before you have added the circles to the graph. Instead, you can set the id when you're appending the circles to your graph.
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("id", function(d){ return "circle" + d.key.replace(/\s+/g, ''); })
// ^---- add the id here when you're appending the circles
.attr("r", 5)
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.count); })
.on("click", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.word + "<br/>" + d.count + "<br/>" + d.songs)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 25) + "px");
})
.on("dblclick", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
;

d3.js adding id's to the stacked bar chart

I have created a stacked bar chart which depicts scanned and unscanned items as bars and also added the tooltip to represent the values of each stack when mouse is moved over. However when i move on a stack i would like to show tooltip like "UnScanned - 57 items" and when i move the mouse over the lower bar it should display "Scanned - 50" . I just need to differentiate the bar whether it is scanned or unscanned along with the data values displayed.
My code goes like:
<!DOCTYPE html>
<html>
<head>
<title>Scanned vs Non Scanned Data</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="../../js/Core_functions.js"></script>
<script type="text/javascript" src="../../js/graphic_functions.js"></script>
<style type="text/css">
svg {
width: 960px;
height: 500px;
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="container">
<h1>Mockup of Component Scanned Mapping DV</h1>
</div>
<script type="text/javascript">
var w = 960,
h = 500,
p = [20, 50, 30, 20],
x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]]),
y = d3.scale.linear().range([0, h - p[0] - p[2]]),
z = d3.scale.ordinal().range(["#819FF7", "#CB491A"]),
parse = d3.time.format("%m/%Y").parse,
format = d3.time.format("%b-%y");
/*var yAxis = d3.svg.axis()
.scale(y)
.ticks(12)
.orient("left");*/
var svg = d3.select("#container").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + p[3] + "," + (h - p[2]) + ")");
d3.csv("scandata.csv", function(scan) {
// Transpose the data into layers by cause.
var scantypes = d3.layout.stack()(["scanned", "unscanned"].map(function(scans) {
return scan.map(function(d) {
return {x: parse(d.date), y: +d[scans]};
});
}));
// Compute the x-domain (by date) and y-domain (by top).
x.domain(scantypes [0].map(function(d) { return d.x; }));
y.domain([0, d3.max(scantypes[scantypes .length - 1], function(d) { return d.y0 + d.y; })]);
// Add a group for each column.
var cause = svg.selectAll("g.scan")
.data(scantypes)
.enter().append("svg:g")
.attr("class", "scan")
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = cause.selectAll("rect")
.data(Object)
.enter().append("svg:rect")
.attr("x", function(d,i) {
if (i ==0)
{
return x(d.x)+ 10 ;
}
else
{
return x(d.x);
}} )
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand()/2)
.on("mouseover", function(d){
return tooltip.style("visibility", "visible")
.text((d.y))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 20) + "px"); ;})
.on("mousemove", function(d){
return tooltip.style("visibility", "visible")
.text((d.y))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 20) + "px"); ;})
.on("mouseout", function(d){return tooltip.style("visibility", "hidden");})
.on("click", function(d){console.log(d);});
var tooltip = d3.select("#container")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "visible")
.text("Scanned vs UnScanned")
.style("font", "Arial")
.style("font-size", "14px");
// Add a label per date.
var label = svg.selectAll("text")
.data(x.domain())
.enter().append("svg:text")
.attr("x", function(d) { return x(d) + x.rangeBand() / 3; })
.attr("y", 6)
.attr("text-anchor", "middle")
.attr("dy", ".71em")
.text(format);
// Add y-axis rules.
var rule = svg.selectAll("g.rule")
.data(y.ticks(5))
.enter().append("svg:g")
.attr("class", "rule")
.attr("transform", function(d) { return "translate(0," + -y(d) + ")"; });
rule.append("svg:line")
.attr("x2", w - p[1] - p[3])
.style("stroke", function(d) { return d ? "#fff" : "#000"; })
.style("stroke-opacity", function(d) { return d ? .7 : null; });
rule.append("svg:text")
.attr("x", -15)
.style("font-family","Arial 12px")
.attr("dy", ".25em")
.text(d3.format(",d"));
});
</script>
</body>
</html> </script>
</body>
</html>
My csv data :
date,scanned,unscanned
01/2014,10,90
02/2014,55,40
03/2014,45,23
04/2014,65,35
05/2014,100,20
06/2014,50,30
07/2014,10,90
08/2014,22,48
09/2014,0,100
10/2014,3,97
11/2014,22,60
12/2014,57,37
You could make this part of the data that you make for the chart:
var scantypes = d3.layout.stack()(["scanned", "unscanned"].map(function(scans) {
return scan.map(function(d) {
return {x: parse(d.date), y: +d[scans], type: scans};
});
}));
// more code...
.on("mouseover", function(d){
return tooltip.text(d.type + " - " + d.y);
});

Resources