vertical bar showing values in javascript - javascript

I have an issue and I really need your help.
I have a realtime graph with a vertical bar that moves with cursor and i want it to show the value of the graph (d.time and d.value) when the cursor points to. http://jsfiddle.net/QBDGB/54/ i have two series of data (data1s and data2s) that is generated randomly and I put the time in which the data is generated in "time" variable as you can see:
now = new Date(Date.now() - duration);
var data1 = initialise();
var data2 = initialise();
//Make stacked data
var data1s = data1;
var data2s = [];
for(var i = 0; i < data1s.length; i++){
data2s.push({
value: data1s[i].value + data2[i].value,
time: data2[i].time
}
)};
function initialise() {
var arr = [];
for (var i = 0; i < n; i++) {
var obj = {
time: Date.now(),
value: Math.floor(Math.random() * 100)
};
arr.push(obj);
}
return arr;
}
When I hover around the graph I want the tooltip show the time and value but it does not recognize it and show "undefined" since I do not know how to pass my datasets (data1s and data2s) so "mouseover function can recognize which data to show! This is how the tooltip functions are made and call from "path1" and "path2".
function mouseover() {
div.transition()
.duration(500)
.style("opacity", 1);
}
function mousemove(d) {
div
.text( d.time+ ", " + d.value)
.style("left", (d3.event.pageX ) + "px")
.style("top", (d3.event.pageY ) + "px");
}
function mouseout() {
div.transition()
.duration(500)
.style("opacity", 1e-6);
}
var path1 = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.data([data1s])
.attr("class", "line1")
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
var path2 =svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.data([data2s])
.attr("class", "line2")
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
Do you have any idea of what to do? i think i need to add
svg.selectAll("path1")
.attr("opacity", 1)
or svg.selectAll("datas1")
.attr("opacity", 1)
Somewhere! but i do not know how..
Thank you,

Update your mouseover function as:
function mousemove(d) {
div
.text( d[0].time+ ", " + d[0].value)
.style("left", (d3.event.pageX ) + "px")
.style("top", (d3.event.pageY ) + "px");
}
Include the index to the object 'd'.
Hope that helps.

Related

D3: How to set text inside a circle

I'm newbie with D3.js and I'm trying to put a text inside a circle but I am only able to do it with one of them and not with all the circles.
You can find all the code in this snipet
And the function where I create the circles and I try to put the text inside of is "setPointsToCanvas"
setPointsToCanvas(canvas, data, scales, x_label, y_label, lang) {
canvas
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 20) //Radius size, could map to another dimension
.attr("cx", function(d) {
return scales.xScale(parseFloat(d.value_x));
}) //x position
.attr("cy", function(d) {
return scales.yScale(parseFloat(d.value_y));
}) //y position
.style("fill", "#FFC107")
.on("mouseover", tipMouseOver)
.on("mouseout", tipMouseOut);
//Ad label for each circle
canvas
.data(data)
//.enter()
.append("text")
.attr("x", function(d) {
return scales.xScale(parseFloat(d.value_x));
})
.attr("y", function(d) {
return scales.yScale(parseFloat(d.value_y) - 0.9);
})
.text(function(d) {
return d.name.substring(0, 3);
})
.style("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "10pt")
.style("fill", "#344761");
let tooltip = d3
//.select("#" + this.props.idContainer)
.select("body")
.append("div")
.attr("class", "tooltip-player")
.style("opacity", 0);
/**
* We define this function inside of setPointsToCanvas to get access to canvas, data, scales and tooltip
* #param {*} d
* #param {*} iter
*/
function tipMouseOver(d, iter) {
let players = data.filter(p => {
if (p.value_x === d.value_x && p.value_y === d.value_y) {
return p;
}
});
let html = "";
for (let i = 0; i < players.length; i++) {
let text_x =
lang === "es"
? String(parseFloat(players[i].value_x).toFixed(2)).replace(
".",
","
)
: parseFloat(players[i].value_x).toFixed(2);
let text_y =
lang === "es"
? String(parseFloat(players[i].value_y).toFixed(2)).replace(
".",
","
)
: parseFloat(players[i].value_y).toFixed(2);
if (i > 0) html += "<hr>";
html +=
players[i].name +
"<br><b>" +
x_label +
": </b>" +
text_x +
"%<br/>" +
"<b>" +
y_label +
": </b>" +
text_y +
"%";
}
tooltip
.html(html)
.style("left", d3.event.pageX + 15 + "px")
.style("top", d3.event.pageY - 28 + "px")
.transition()
.duration(200) // ms
.style("opacity", 0.9); // started as 0!
// Use D3 to select element, change color and size
d3.select(this)
//.attr("r", 10)
.style("cursor", "pointer");
}
/**
* We create this function inside of setPointsToCanvas to get access to tooltip
*/
function tipMouseOut() {
tooltip
.transition()
.duration(500) // ms
.style("opacity", 0); // don't care about position!
//d3.select(this).attr("r", 5);
}
}
And here you can see how I'm only able to get one text inside of one circle and not the text inside all of them.
What am I doing wrong?
Following the advice of #Pablo EM and thanks to #Andrew Reid for your appreciated help I publish the solution to my problem.
How #Andrew Reid said if I have problems with selectAll("text") I have to change it for another text grouper. How I had it, I changed by selectAll("textCircle") and everything works fine to me.
This is the code which writes the text inside each circle. This piede of code you can find it inside of "setPointsToCanvas" method.
//Ad label for each circle
canvas
.selectAll("textCircle")
.data(data)
.enter()
.append("text")
.attr("x", function(d) {
return scales.xScale(parseFloat(d.value_x));
})
.attr("y", function(d) {
return scales.yScale(parseFloat(d.value_y) - 0.9);
})
.text(function(d) {
return d.name.substring(0, 3);
})
.style("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "10pt")
.style("fill", "#344761");
Now, here you've got an image of the final result:
If you access to the code through CodeSandBox posted before you can access to all the code and check how it works perfectly.

D3 Map + Graph Coordinated Visualization: selecting wrong countries / map changing attributes

Here is my issue: I have a map SVG and a bar Graph SVG. I want to create a coordinated selection. For instance, the user highlights a bar in the graph and the country on the map corresponding to that data is also highlighted and Vice Versa.
Right now I can highlight any country on the map and the proper corresponding bar will also highlight. However, the same does not work for the bars. When I highlight a bar, a random country is highlighted and after that the country names, as displayed in a tooltip, are all jumbled and wrong.
Here is the map -> bar graph highlight:
...
map.selectAll("countries")
.data(b.features)
.enter()
.append("path")
.attr("d", path)
//.style("stroke", "black")
.on("mouseover", function(d) {
activeDistrict = d.properties.ADMIN,
chart.selectAll("rect")
.each(function(d) {
if(d){
if (d.Country == activeDistrict){
console.log("confirmed" + d.Country)
d3.select(this).style("stroke", "blue").style("stroke-width", "3");
}
}
})
...
Here is the bar graph -> map highlight. This is the function I cannot get to behave properly.
var bars = chart.selectAll(".bars")
.data(data)
.enter()
.append("rect")
.on("mouseover", function(d) {
activeDistrict = d.Country,
//console.log(activeDistrict),
map.selectAll("path")
.data(b.features)
.each(function(d) {
if (d){
//console.log("activeDistrict = " + activeDistrict)
if (d.properties.ADMIN == activeDistrict){
d3.select(this).style("stroke", "blue").style("stroke-width", "3");
console.log(d.properties.ADMIN + "=" + activeDistrict)
}
}
});
And here is my entire JS:
<script>
window.onload = setMap();
function setMap(){
d3.csv("/data/blah.csv").then(function(data) {
//console.log(data);
d3.json("/data/blah.topojson").then(function(data2) {
//console.log(data2);
//Code with data here
var width = window.innerWidth * 0.5, // 960
height = 460;
var activeDistrict;
//chart vars
var chartWidth = window.innerWidth * 0.425,
chartHeight = 473,
leftPadding = 25,
rightPadding = 2,
topBottomPadding = 5,
chartInnerWidth = chartWidth - leftPadding - rightPadding,
chartInnerHeight = chartHeight - topBottomPadding * 2,
translate = "translate(" + leftPadding + "," + topBottomPadding + ")";
var yScale = d3.scaleLinear()
.range([0, chartHeight])
.domain([0, 2000]);
//create new svg container for the map
var map = d3.select("body")
.append("svg")
.attr("class", "map")
.attr("width", width)
.attr("height", height);
//create new svg container for the chart
var chart = d3.select("body")
.append("svg")
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr("class", "chart");
//create Albers equal area conic projection centered on France
var projection = d3.geoNaturalEarth1()
.center([0, 0])
.rotate([-2, 0, 0])
//.parallels([43, 62])
.scale(175)
.translate([width / 2, height / 2]);
var path = d3.geoPath()
.projection(projection);
//translate TopoJSON
d3.selectAll(".boundary")
.style("stroke-width", 1 / 1);
var b = topojson.feature(data2, data2.objects.ne_10m_admin_0_countries);
//console.log(b)
//console.log(b.features[1].properties.ADMIN) //country name
var graticule = d3.geoGraticule();
var attrArray = ["blah blah blah"];
function joinData(b, data){
//loop through csv to assign each set of csv attribute values to geojson region
for (var i=0; i<data.length; i++){
var csvRegion = data[i]; //the current region
var csvKey = data[i].Country; //the CSV primary key
//console.log(data[i].Country)
//loop through geojson regions to find correct region
for (var a=0; a<b.features.length; a++){
var geojsonProps = b.features[a].properties; //gj props
var geojsonKey = geojsonProps.ADMIN; //the geojson primary key
//where primary keys match, transfer csv data to geojson properties object
if (geojsonKey == csvKey){
//assign all attributes and values
attrArray.forEach(function(attr){
var val = parseFloat(csvRegion[attr]); //get csv attribute value
geojsonProps[attr] = val; //assign attribute and value to geojson properties
});
};
};
};
return b;
};
joinData(b,data);
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
//Dynamically Call the current food variable to change the map
var currentFood = "Beef2";
var valArray = [];
data.forEach(function(element) {
valArray.push(parseInt(element[currentFood]));
});
var currentMax = Math.max.apply(null, valArray.filter(function(n) { return !isNaN(n); }));
console.log("Current Max Value is " + currentMax + " for " + currentFood)
var color = d3.scaleQuantile()
.domain(d3.range(0, (currentMax + 10)))
.range(d3.schemeReds[7]);
function drawMap(currentMax){
d3.selectAll("path").remove();
// Going to need to do this dynamically
// Set to ckmeans
var color = d3.scaleQuantile()
.domain(d3.range(0, currentMax))
.range(d3.schemeReds[7]);
//console.log(b[1].Beef1)
map.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
map.append("path")
.datum(graticule.outline)
.attr("class", "graticule outline")
.attr("d", path);
console.log(map.selectAll("path").size())
map.selectAll("countries")
.data(b.features)
.enter()
.append("path")
.attr("d", path)
//.style("stroke", "black")
.on("mouseover", function(d) {
activeDistrict = d.properties.ADMIN,
chart.selectAll("rect")
.each(function(d) {
if(d){
//console.log("activeDistrict = " + activeDistrict)
if (d.Country == activeDistrict){
console.log("confirmed" + d.Country)
d3.select(this).style("stroke", "blue").style("stroke-width", "3");
}
}
})
tooltip.transition() //(this.parentNode.appendChild(this))
.duration(200)
.style("opacity", .9)
.style("stroke-opacity", 1.0);
tooltip.html(d.properties.ADMIN + "<br/>" + d.properties[currentFood] + "(kg/CO2/Person/Year)")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
activeDistrict = d.properties.ADMIN,
chart.selectAll("rect")
.each(function(d) {
if (d){
//console.log("activeDistrict = " + activeDistrict)
if (d.Country == activeDistrict){
d3.select(this).style("stroke", "none").style("stroke-width", "0");
}
}
})
tooltip.transition()
.duration(500)
.style("opacity", 0)
.style("stroke-opacity", 0);
})
.style("fill", function(d) { return color(d.properties[currentFood]) });
};
drawMap(currentMax);
console.log("sum", d3.sum(valArray))
//console.log(map.selectAll("path")._groups[0][200].__data__.properties.ADMIN)
function setChart(data, data2, currentMax, valArray){
d3.selectAll("rect").remove();
d3.selectAll("text").remove();
var color = d3.scaleQuantile()
.domain(d3.range(0, (currentMax + 10)))
.range(d3.schemeReds[7]);
var chartBackground = chart.append("rect2")
.attr("class", "chartBackground")
.attr("width", chartInnerWidth)
.attr("height", chartInnerHeight)
.attr("transform", translate);
var yScale = d3.scaleLinear()
.range([0, chartHeight])
.domain([0, (currentMax+10)]);
var chartTitle = chart.append("text")
.attr("x", 20)
.attr("y", 40)
.attr("class", "chartTitle")
.text(currentFood.slice(0, -1));
var chartSub = chart.append("text")
.attr("x", 20)
.attr("y", 90)
.attr("class", "chartSub")
.text((d3.sum(valArray)*76) + " Billion World Total");
// Place Axis at some point
var bars = chart.selectAll(".bars")
.data(data)
.enter()
.append("rect")
.on("mouseover", function(d) {
activeDistrict = d.Country,
//console.log(activeDistrict),
map.selectAll("path")
.data(b.features)
.each(function(d) {
if (d){
//console.log("activeDistrict = " + activeDistrict)
if (d.properties.ADMIN == activeDistrict){
d3.select(this).style("stroke", "blue").style("stroke-width", "3");
console.log(d.properties.ADMIN + "=" + activeDistrict)
}
}
});
tooltip.transition() //(this.parentNode.appendChild(this))
.duration(200)
.style("opacity", .9)
.style("stroke-opacity", 1.0);
tooltip.html(d.Country + "<br/>" + d[currentFood] + "(kg/CO2/Person/Year)")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
map.selectAll("path")
.data(b.features)
.each(function(d) {
if (d){
//console.log("activeDistrict = " + activeDistrict)
if (d.properties.ADMIN == activeDistrict){
d3.select(this).style("stroke", "none").style("stroke-width", "0");
console.log(d.properties.ADMIN + "=" + activeDistrict)
}
}
});
tooltip.transition()
.duration(500)
.style("opacity", 0)
.style("stroke-opacity", 0);
})
.sort(function(a, b){
return a[currentFood]-b[currentFood]
})
.transition() //add animation
.delay(function(d, i){
return i * 5
})
.duration(1)
.attr("class", function(d){
return "bars" + d.Country;
})
.attr("width", chartWidth / data.length - 1)
.attr("x", function(d, i){
return i * (chartWidth / data.length);
})
.attr("height", function(d){
return yScale(parseFloat(d[currentFood]));
})
.attr("y", function(d){
return chartHeight - yScale(parseFloat(d[currentFood]));
})
.style("fill", function(d){ return color(d[currentFood]); });
};
setChart(data, data2, currentMax, valArray);
function createDropdown(data){
//add select element
var dropdown = d3.select("body")
.append("select")
.attr("class", "dropdown")
.on("change", function(){
changeAttribute(this.value, data)
});
//add initial option
var titleOption = dropdown.append("option")
.attr("class", "titleOption")
.attr("disabled", "true")
.text("Select Attribute");
//add attribute name options
var attrOptions = dropdown.selectAll("attrOptions")
.data(attrArray)
.enter()
.append("option")
.attr("value", function(d){ return d })
.text(function(d){ return d });
};
createDropdown(data);
function changeAttribute(attribute, data){
//change the expressed attribute
currentFood = attribute;
var valArray = [];
data.forEach(function(element) {
valArray.push(parseInt(element[currentFood]));
});
var currentMax = Math.max.apply(null, valArray.filter(function(n) { return !isNaN(n); }));
console.log("Current Max Value is " + currentMax + " for " + currentFood)
// Set a dynamic color range
var color = d3.scaleQuantile()
.domain(d3.range(0, currentMax))
.range(d3.schemeReds[7]);
//recolor enumeration units
drawMap(currentMax);
//reset chart bars
setChart(data, data2, currentMax, valArray);
};
}); //csv
}); //json
}; // end of setmap
When drawing countries initially you use:
map.selectAll("countries")
.data(b.features)
.enter()
.append("path")
As there are no elements with the tag countries on your page, the initial selection is empty, and .enter().append("path") creates a path for each item in your data array.
But when you do a mouseover on the bars you re-assign the data with a selectAll().data() sequence, but you do it a bit differently:
map.selectAll("path")
.data(b.features)
...
There are paths in your map that aren't countries: the graticule and the outline. Now we've selected all the paths and assigned new data to them. Since the first two items in the selection are the graticule and the outline they now have the data of the first two items in the data array. All the countries will have bound data of a country that is two away from them in the data array. This is why the wrong data will be highlighted when mouseovering the bars and afterwards why the country tooltips are wrong.
It is not clear why you update the data (I don't see it changing), you could append the countries as so:
var countries = map.selectAll("countries")
.data(b.features)
.enter()
.append("path")
... continue as before
or
map.selectAll("countries")
.data(b.features)
.enter()
.append("path")
.attr("class","country")
... continue as before
And then in the mouseover function of the bars use:
countries.each(....
or
map.selectAll(".country").each(...
Either way still lets you update the data with .data() if needed.
I'll note that the each method isn't necessary, but may be preferable in some situations, by the looks of it you could use:
var bars = chart.selectAll(".bars")
.data(data)
.enter()
.append("rect")
.on("mouseover", function(d) {
activeDistrict = d.Country,
map.selectAll(".country")
.data(b.features)
.style("stroke", function(d) {
if (d.properties.ADMIN == activeDistrict) return "blue"; else return color(d.properties[currentFood])
})
.style("stroke-width", function(d) {
if (d.properties.ADMIN == activeDistrict) return "3" else return 0;
});
})
...
You might try the following to be a bit more consistent in what you create and what you select.
The map:
select by class because you have more path in the svg
add a class to the bar to highlight instead of setting a style
map.selectAll(".countries")
.data(b.features)
.enter()
.append("path")
.attr("class", "countries")
.attr("d", path)
//.style("stroke", "black")
.on("mouseover", function(d) {
activeDistrict = d.properties.ADMIN,
chart.selectAll(".bars")
.classed("highlight", function(d) {
return d && d.Country === activeDistrict;
});
tooltip.transition() //(this.parentNode.appendChild(this))
.duration(200)
.style("opacity", .9)
.style("stroke-opacity", 1.0);
tooltip.html(d.properties.ADMIN + "<br/>" + d.properties[currentFood] + "(kg/CO2/Person/Year)")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
activeDistrict = d.properties.ADMIN,
chart.selectAll(".bars")
.classed("highlight", false);
tooltip.transition()
.duration(500)
.style("opacity", 0)
.style("stroke-opacity", 0);
})
.style("fill", function(d) { return color(d.properties[currentFood]) });
};
Drawing of the bars
fix the class, add a space between the bars and country
do not bind new data to the map paths on mouse over and mouse out
select map paths by class not by type
add a class to the map path to highlight instead of setting a style
var bars = chart.selectAll(".bars")
.data(data)
.enter()
.append("rect")
.on("mouseover", function(d) {
activeDistrict = d.Country;
//console.log(activeDistrict),
map.selectAll(".countries")
.classed("highlight", function(d) {
return d && d.properties.ADMIN === activeDistrict;
});
tooltip.transition() //(this.parentNode.appendChild(this))
.duration(200)
.style("opacity", .9)
.style("stroke-opacity", 1.0);
tooltip.html(d.Country + "<br/>" + d[currentFood] + "(kg/CO2/Person/Year)")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
map.selectAll(".countries")
.classed("highlight", false);
tooltip.transition()
.duration(500)
.style("opacity", 0)
.style("stroke-opacity", 0);
})
.sort(function(a, b){
return a[currentFood]-b[currentFood]
})
.transition() //add animation
.delay(function(d, i){
return i * 5
})
.duration(1)
.attr("class", function(d){
return "bars " + d.Country;
})
.attr("width", chartWidth / data.length - 1)
.attr("x", function(d, i){
return i * (chartWidth / data.length);
})
.attr("height", function(d){
return yScale(parseFloat(d[currentFood]));
})
.attr("y", function(d){
return chartHeight - yScale(parseFloat(d[currentFood]));
})
.style("fill", function(d){ return color(d[currentFood]); });

D3 js selectAll each doesn't iterate

I am trying to implement the FishEye lens (Cartesian) in my scatterplot.
I am trying to follow this approach, but apparently my selector already fails.
I have my FishEye defined as
var fisheye = d3.fisheye.circular().radius(120);
svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
console.log("here " + points.selectAll("circle").length);
points.selectAll("circle").each(function(d) {
console.log("aaa");
d.fisheye = fisheye(d);
/*points.selectAll("circle")
.each(function(d) {
console.log("???");
this.attr("cx", function(d) { return d.fisheye.x; })
this.attr("cy", function(d) { return d.fisheye.y; })
this.attr("r", function(d) { console.log("hype"); return 10; });
}); */
});
});
and my points is defined as
points = svg.append("g")
.attr("class", "point")
.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { // Set the x position using the x-scale
return x(d.x);
})
.attr("cy", function(d) { // Set the y position using the y-scale
return y(d.y);
})
.attr("r", 5) // Set the radius of every point to 5
.on("mouseover", function(d) { // On mouse over show and set the tooltip
if(!isBrushing){
tooltip.transition()
.duration(200)
.style("opacity", 0.9);
tooltip.html(d.symbol + "<br/> (" + parseFloat(x(d.x)).toFixed(4)
+ ", " + parseFloat(y(d.y)).toFixed(4) + ")")
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
}
})
.on("mouseout", function(d) { // on mouseout, hide the tooltip.
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
The console.log with "here" is spamming when I am moving the mouse, and shows the correct amount. Hwoever, the each loop is never executed as I do not see "aaa". I have also tried to just use selectAll("circle") but that doesn't work either.
What am I doing wrong and how can I get my FishEye to work?

d3 link static tooltip to points

I am trying to create a scatter plot and want to show tooltips by clicking on each point. The tooltip will disappear only when the point is deselected (clicked again). Currently, selected points will have a black border with r=8. Deselected points have no visible black border with r=4.5.
With the code below, when I deselect the points, the tooltip won't go away. How can I link the tooltip to each point? Thanks!
.on("click", function (d) {
var clickTooltip = d3.select("#data_visualization").append("div").attr("class", "click_tooltip");
if (d3.select(this).attr("r") < 8) {
d3.select(this)
.style("stroke", "black")
.style("stroke-width", "2px")
.style("stroke-opacity", 1)
.attr("r", 8);
clickTooltip.style("opacity", 0.62);
var clickTooltipText = "display";
clickTooltip.html(clickTooltipText)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 40) + "px");
} else {
d3.select(this)
.attr("r", 4.5)
.style("stroke-opacity", 0);
clickTooltip.style("opacity", 0);
}
}
You are appending a new element every time the click handler is called. Instead, create the element once and then select it:
var clickTooltip = d3.select("#data_visualization").append("div").attr("class", "click_tooltip");
.on("click", function (d) {
if (d3.select(this).attr("r") < 8) {
// etc
I figured it out. I am posting my answer here in case anyone is interested. The idea is to add an ID to each tooltip div. Later we can use JQuery to remove by ID.
.on("click", function (d) {
var pointID = "point_" + d3.select(this).attr("cx").replace(".", "_") + "_" + d3.select(this).attr("cy").replace(".", "_");
var clickTooltip = d3.select("#data_visualization")
.append("div")
.attr("id", pointID)
.attr("class", "click_tooltip");
if (d3.select(this).attr("r") < 8) {
d3.select(this)
.style("stroke", "black")
.style("stroke-width", "2px")
.style("stroke-opacity", 1)
.attr("r", 8);
clickTooltip.style("opacity", 0.62);
var clickTooltipText = "display";
clickTooltip.html(clickTooltipText)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 40) + "px");
} else {
d3.select(this)
.attr("r", 4.5)
.style("stroke-opacity", 0);
d3.select("#" + pointID).remove();
}
}

What is wrong with my javascript tooltip?

I have an issue and I really need your help.
I have a realtime graph with a vertical bar that moves with cursor and i want it to show the value of the graph (d.time and d.value) when the cursor points to. I am trying to get inspired of the tooltip from here: http://bl.ocks.org/WillTurman/4631136 adn that is what I have made: http://jsfiddle.net/QBDGB/54/ i have two series of data (data1s and data2s) that is generated randomly and I put the time in which the data is generated in "time" variable as you can see:
now = new Date(Date.now() - duration);
var data1 = initialise();
var data2 = initialise();
//Make stacked data
var data1s = data1;
var data2s = [];
for(var i = 0; i < data1s.length; i++){
data2s.push({
value: data1s[i].value + data2[i].value,
time: data2[i].time
}
)};
function initialise() {
var arr = [];
for (var i = 0; i < n; i++) {
var obj = {
time: Date.now(),
value: Math.floor(Math.random() * 100)
};
arr.push(obj);
}
return arr;
}
When I hover around the graph I want the tooltip show the time and value but it does not recognize it and show "undefined" since I do not know how to pass my datasets (data1s and data2s) so "mouseover function can recognize which data to show! This is how the tooltip functions are made and call from "path1" and "path2".
function mouseover() {
div.transition()
.duration(500)
.style("opacity", 1);
}
function mousemove(d) {
div
.text( d.time+ ", " + d.value)
.style("left", (d3.event.pageX ) + "px")
.style("top", (d3.event.pageY ) + "px");
}
function mouseout() {
div.transition()
.duration(500)
.style("opacity", 1e-6);
}
var path1 = svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.data([data1s])
.attr("class", "line1")
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
var path2 =svg.append("g")
.attr("clip-path", "url(#clip)")
.append("path")
.data([data2s])
.attr("class", "line2")
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
Do you have any idea of what to do? As you can see in http://bl.ocks.org/WillTurman/4631136 the layers can be recognized by
svg.selectAll(".layer")
.attr("opacity", 1)
.on("mouseover", function(d, i) {
svg.selectAll(".layer").transition()
.duration(250)
.attr("opacity", function(d, j) {
return j != i ? 0.6 : 1;
})})
.on("mousemove", function(d, i) {
mousex = d3.mouse(this);
mousex = mousex[0];
var invertedx = x.invert(mousex);
invertedx = invertedx.getMonth() + invertedx.getDate();
var selected = (d.values);
for (var k = 0; k < selected.length; k++) {
datearray[k] = selected[k].date
datearray[k] = datearray[k].getMonth() + datearray[k].getDate();
}
and the the "mousemove" function can be added for each layer but how can I have this for each of my path?
Thank you,

Categories

Resources