How to make a d3.js tool tip with embeded HTML elements - javascript

I am trying to make a tooltip with embedded elements such as img, h1 and p tags in d3.js. JavaScript is housed in a rails app. The tooltip is suppose to dynamically change the text upon hovering on a g element. Currently I am just trying to get one img tag to show up and text to dynamically change upon hover within one tool tip. However every time I try and accomplish this two things happen. Either the image or the text shows up (not both) or the javascript breaks all together. In the code below it just shows the text changing. The image does not show up at all. The code I have to make the tooltip is this:
var tooltip = d3.select("body")
.append("div").attr("id", "tool_tip").style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background-color", "yellow")//.style("top","100px").style("left","20px")
.text("a simple tooltip").append("img").attr("src","http://www.metmuseum.org/~/media/Images/Metpublication/Cover/2004/Echoing_Images_Couples_in_African_Sculpture.jpg");
The code that dynamically changes the text and moves the tooltip on hover is this:
svg.append("g").attr("class","points")
.selectAll("text").data(places.features)
.enter().append("path").attr("r", function(d){return 1234567})
.attr("class", "point")
.on("mouseover", function(d) {
var div = document.getElementById('profile');
var test = $('#test').text();
div.innerHTML = "";
div.innerHTML = div.innerHTML + d3.event.pageY+ ' X:'+d3.event.pageX +'<img src='+test+'>';
$('#tool_tip').css("top",d3.event.pageY);
$('#tool_tip').css("left",d3.event.pageX);
$('#tool_tip').css("visibility", "visible");
$('#tool_tip img').css("visibility", "visible");
var tool_tip = $('#tool_tip');
// alert($(this).attr('d'));
var j = places.features[0].properties.name
//adding text to tool tip by different points
// alert(JSON.stringify(d.properties.TeamName));
// alert(JSON.stringify(d));
$('#tool_tip').text(d.properties[0].TeamName);
// return tooltip;//.style("visibility", "visible");
//Warren you need to build out the pop up here. Ideally you can pull the data from the json object "places.json."
});

I first had to delete .append("img").attr("src","http://www.metmuseum.org/~/media/Images/Metpublication/Cover/2004/Echoing_Images_Couples_in_African_Sculpture.jpg"); from my tooltip variable in
var tooltip = d3.select("body")
.append("div").attr("id", "tool_tip").style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("background-color", "yellow")//.style("top","100px").style("left","20px")
.text("a simple tooltip").append("img").attr("src","http://www.metmuseum.org/~/media/Images/Metpublication/Cover/2004/Echoing_Images_Couples_in_African_Sculpture.jpg");
That was causing embeded image tags when the page was being rendered. It was also causing the text to form within the embeded image and not after the #tool_tip div. As far as forming the tooltip on mouseover within the block of code
svg.append("g").attr("class","points")
.selectAll("text").data(places.features)
.enter().append("path").attr("r", function(d){return 1234567})
.attr("class", "point")
.on("mouseover", function(d) {...
that I have posted in my question I did away with $('#tool_tip').text(d.properties[0].TeamName); and added this line of code return tooltip.html(d.properties[0].TeamName+"<img src = 'http://www.metmuseum.org/~/media/Images/Metpublication/Cover/2004/Echoing_Images_Couples_in_African_Sculpture.jpg'>")//text(d.properties[0].TeamName);//.append("img").attr("src","http://www.metmuseum.org/~/media/Images/Metpublication/Cover/2004/Echoing_Images_Couples_in_African_Sculpture.jpg");
the .html() function allowed me to properly format the html within the #tool_tip div on hover.

Related

Multiple tooltips not showing correctly in react

I am working with react D3 charts, and I have created charts and it is working fine.
What I have done
I have several charts which are updating with in some time intervals, something like live data
So here to achieve this I out use effect and updating my charts every second, and my data in charts updates correctly.
I have given one tooltip on hover over the the bar, so that user can check the data for each bar or line.
Using below code to show the tooltip
.on("mousemove", function (event, d) {
// this whole code is when I hover that perticular bar
d3.select(this)
.transition()
.duration("50")
.attr("opacity", 0.6)
.attr("x", (a) => xScaleBars(a.timeline) - 3)
.attr("width", xScaleBars.bandwidth() + 6)
.style("filter", "url(#glow)");
div.transition().duration(50).style("opacity", 1);
div
.html(
`</text><text"></br> value : ${d.dataToShow}
<br/>
</text><text"></br> Month : ${d.month}
`
)
.style("left", event.pageX - 58 + "px")
.style("top", event.pageY - 140 + "px");
})
.on("mouseout", function (d, i) {
// this is when I move cursor out of that bar
d3.select(this)
.transition()
.duration("50")
.attr("width", xScaleBars.bandwidth())
.attr("x", (a) => xScaleBars(a.timeline))
.style("filter", "none")
.attr("opacity", "1");
div.transition().duration("50").style("opacity", 0);
})
Issue I am facing
The issue is when I hover over one chart component it shows the tooltip, and than when I hover over the other both shows at the same time.
What I am trying to do is to show the tooltip when I hover the one bar of any chart and than hide it,I tried below code
d3.select("svg").selectAll(".tooltipCHart").remove();
But it doesn't resolve my issue, I think I am missing some small part
here is my code sandbox which I tried
The problem is that you're creating a new tooltip div every time you re-render the chart.
A better approach is to have a hidden tooltip div in the beginning (in the render / return from your function component) and then just modify its contents and style (opacity: 1) on mouseover and mouseout. Keep track of the tooltip div using a ref.
See working codesandbox (I only modified chart1, you can make similar changes to chart2)

Replace Circles and Texts in d3 demo with foreignObject containing custom HTML and ko binding

Given this working fiddle which is an exact copy of this d3 demo, I would like to replace the circle and text elements in the SVG with foreignObject elements which contain some custom HTML.
I was able to manually add one using the following code:
var newFO = document.createElementNS('http://www.w3.org/2000/svg', "foreignObject");
$('svg').append(newFO);
$(newFO).append("<div class='test'>" + strNameVar + "</div>");
(fiddle with this implemented)
But it's not part of the graph, obviously. I really don't understand d3 enough to insert these on the fly using the "links" dataset in the demo. Basically I need to adapt the following code to use a foreignObject instead of a text element and then insert the custom HTML:
var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text")
.attr("x", 8)
.attr("y", ".31em")
.text(function (d) { return d.name; });
update:
This version of the fiddle is the closest I've come, but it's applying the transform to the div instead of the parent foreignObject.
You can do this by appending the g elements first and then the foreignObject elements below. Like this (in a slight abuse of selectors):
var node = svg.selectAll("foreignObject")
.data(force.nodes())
.enter().append("g");
node.append("foreignObject")
// etc
Complete example here.

d3 how to add image to the label of a graph node?

I've made a fast stand-alone part of the project I have as to show you my problem. I have this circle that represent a node in my graph and what I want is to have on mouseover a box appearing with some text and image. This far I have the node, the box and the text. My problem is that the image doesn't appear, there is only a border of the space dedicated to the image and nothing inside.
I don't know if I'am using the right order of appending things?
I`m using a div that is created initially and it's invisible, then I create the circle and bind a listener to it for the mouseover event. The listener appends to the div a text field and the image. For the image it gives the href attribute and on mouseout it renders the div invisible again. Would you help me find what is going wrong in all this....thank you!
//the box, invisible for now
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("width","60px")
.style("height","28px")
.style("padding","2px")
.style("font","12px sans-serif")
.style("border","0px")
.style("border-radius","8px")
.style("background", "lightsteelblue")
.style("visibility", "hidden");
//the svg container
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
//the node
svg.append("circle")
.attr("class", "logo")
.attr("cx", 225)
.attr("cy", 225)
.attr("r", 20)
.on("mouseover", function(d){
tooltip.text("some text");
tooltip.append("image")
.attr("href","https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width","16px")
.attr("height","12px");
tooltip.style("visibility", "visible");
})
.on("mousemove", function(){return tooltip.style("top", (event.pageY-
10)+"px").style("left",(event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
You need to change image to img and href to src. Complete working example here.

Cannot make labels work on zoomable d3 sunburst

After fiddling around for several hours now, I still cannot make labels work in my D3 Sunburst layout. Here's how it looks like:
http://codepen.io/anon/pen/BcqFu
I tried several approaches I could find online, here's a list of examples I tried with, unfortunately all failed for me:
[cannot post link list because of new users restriction]
and of course the coffee flavour wheel: http://www.jasondavies.com/coffee-wheel/
At the moment i fill the slices with a title tag, only to have it displayed when hovering over the element. For that I'm using this code:
vis.selectAll("path")
.append("title")
.text(function(d) { return d.Batch; });
Is there something similar I could use to show the Batch number in the slice?
--
More info: Jason Davies uses this code to select and add text nodes:
var text = vis.selectAll("text").data(nodes);
var textEnter = text.enter().append("text")
.style(...)
...
While the selection for his wheel gives back 97 results (equaling the amount of path tags) I only get one and therefore am only able to display one label (the one in the middle)
Needs some finessing but the essential piece to get you started is:
var labels = vis.selectAll("text.label")
.data(partition.nodes)
.enter().append("text")
.attr("class", "label")
.style("fill", "black")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d, i) { return d.Batch;} );
You can see it here
The trick is that in addition to making sure you are attaching text nodes to the appropriate data you also have to tell them where to go (the transform attribute with the handy centroid function of the arc computer).
Note that I do not need vis.data([json]) because the svg element already has the data attached (when you append the paths), but I still have to associate the text selection with the nodes from each partition.
Also I class the text elements so that they will not get confused with any other text elements you may want to add in the future.

Changing Element Position on Page JS/D3

This is a simple question that I just can't seem to get figured out -- All I want to do is change the position of an element on a page. I've tried the following:
// Text
body = d3.select('body')
sometext = body.append('text').text('testing') // text appears
// Different Ways i've tried to move it
.attr('cx', 40)
.attr('x', 40)
.attr("transform", "translate("40, 100")
However, none of this moves the text -- What am I missing (http://jsfiddle.net/Hn5JX/)? I'm having the same issue moving svg elements around a page, i just thought this was easier to see on the jsfiddle. Thanks for help with a basic question,
Here's an example of moved text using d3js.
http://jsfiddle.net/JnNtZ/
Make sure to include:
"http://mbostock.github.com/d3/d3.js"
Then include the following javascript
// Create an svg "canvas" to place text on
var w = 400, h = 400;
var vis = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add text and set attributes
var text1 = vis.append('text').text('text1');
var text2 = vis.append('text').text('text2');
text1.attr("y", "300").style("fill", "red");
text2.attr("x", "200").attr("y", "403").style("fill", "blue"); // Notice how this text is on the edge of the canvas
​
I think the problem you were running into is that upon selecting text, you're getting an HTML element instead of an SVGText element (It seems you need an SVG element to allow manipulations by d3js). You also need to make sure that the (x,y) coordinates of the text fall inside the given canvas.

Categories