Here is my problem. My graph currently looks like this: Which is dandy. However, I want the black squares on top to be filled with pictures. Luckily I have a CSS file that has pictures linked with classes. I also have a JSON file that contains all the class names. All those class names are assigned to the squares and I can see the picture in the inspect element on Chrome. The only issue is the pictures don't appear in the square. (Also my axises broke, but that is secondary concern). CSS, JSON
This is where I'm assigning classes and creating the rectangles.
svg.selectAll(".div")
.data(data.chartData, function(d){return d.vNm;})
.enter().append("rect")
.attr("x", function(d){
return x(d.vNm);
})
.attr("y", function(d){
return (y(d.values.reduce(function(sum, d){
return sum + d.amount;
}, 0))) - 64.5;
})
.attr("width", 43)
.attr("height", 43)
.attr("class", function(d){return d.vId;})
.style("fill", function(d) { return segColor(d.data.type); });
One approach to solve your problem is to use html elements like div for the images above the chart instead of svg elements, so you can use the full power of css.
Luckily you don't need to calculate the position of those html elements by yourself, there are some libraries that help you position the images correctly above the bars in the chart.
Check out https://popper.js.org/ for example, you can just call its API for each bar you render using d3.js:
var popper = new Popper(barElement, onPopper, {
placement: 'top'
});
SVG elements do not follow exactly the same CSS rules as typical HTML elements.
In your case, background-image doesn't work.
The least painful way to achieve the effect would be to embed an <image> tag after the <rect>:
<image width="100" height="100" xlink:href="data:image/png;base64,...">
It means that you have to modify your JSON to store the image's base64 data in there instead of CSS.
Related
I'm trying to create a d3 force graph with countries' flags, using a spritesheet for the imgs.
I guess I'm still having a hard time understanding d3 syntactically. I was going to use a background-image from a css flag class, and then the subimages would have background-positions. However, adding an img with a class, as in:
var nodesDrawn = d3
.select("#container")
.selectAll("img")
.data(nodesData)
.enter()
.append("img")
.attr('class', function(d){return "flag flag-"+d.code;})
;
produces images, but doesn't work with the force graph... force nodes without links
Alternatively I have produced the graph itself, and do have nodes that work, but can't use images instead of svg circles... force links without nodes
var nodesDrawn = svg
.append("g")
.selectAll("img")
.data(nodesData)
.enter()
.append("img")
.attr('class', function(d){return "flag flag-"+d.code;})
;
And you can see that with links but not nodes, I'm trying to append the nodes to an svg, whereas the working images are being appended to the body directly. Can anyone help me understand how this works?
img is an HTML tag, and the graph you're building is SVG. Once you start working inside of a svg tag on a page, you're dealing with SVG elements, not HTML elements.
You can, though,
Put HTML inside of SVG by using the foreignObject tag
Use the SVG equivalent of the img tag, which is the image tag
So, I am thinking something along the lines of a tool tip or a pop-up, except with much more information in it, and I also want every information box to be in the same location on the page. Overall, I just want to be about to click on an SVG (that represents some data element), and on a click event, trigger and information box to pop up in front of it; maybe even give it it's own close function if it covers the SVG. I know I have seen this many times before, but the exact name is escaping me at the moment.
Right now, I have a circle:
node.append("circle")
.attr("cx", sankey.nodeWidth()/2)
.attr("cy", function(d){return d.dy/2;})
.attr("r",function(d){return Math.sqrt(d.dy);})
.style("fill", function(d){return d.color = color(d.name.replace(/ .*/,""));})
.style("stroke", function(d){return d3.rgb(d.color).darker(1);})
.style("stroke-width",5)
.on("mouseover", tip.show)
.on("mouseout", tip.hide)
.on("click", changeColor(function(d){return d.color;}))
.append("title")
I'm hoping to write something like:
.on("click",function(d){/*Create a rect element*/})
.append("text", "This element represents the "+d.name+" element and will weigh approximately "+d.weight+"lbs.")
.attr("cx", 50)
.attr("cy", 50)
.on("click_exit?" function(d){this.remove();})
I am not certain how to approach this, but I just want a text box to display on click and have an exit button (or some closing method) to close it. Can I add something like the above code to my previous code, or must I create an entire new svg element completely disjoint from it?
I've done things similar to this before, i've found that SVG can be a real pain when not doing actual d3 graphical stuff. I would work with html in this case.
What i did was create an html element with the desired template, absolutely position it where i wanted, and then set display:none or opacity:0.
Then for your onClick function
.on("click",function(d){
d3.select('.my-info-box p')
.append(d)
.style('display','block')
})
This is the bare bones functionality. The takeaway here is to use html and not svg. To close it you can position a × in the top right/left of the box, and then onClick, close the info box.
I am using D3 render a simple network diagram. And in each node I want to display html content for that foreign object is used. Foreign object is having html inside. The network is getting rendered. But I am not able to view the html content anybody know why it is not rendering the html?
I am using below code.
dom.svg.selectAll('.node').append("foreignObject")
.attr("width", 100)
.attr("height", 100)
.append("xhtml:body").append("xhtml:p")
.style("color", "red")
.text("Object in SVG");
Here is the fiddle
You can't append foreignObjects (or indeed anything) to circle elements. Instead, append them to a container element like gs for example. Fixed here.
I'm relatively new to D3, svg, and javascript in general, so please bear with me :]
I have been experimenting with D3 for creating plots and graphs. I have created a small plot using D3 and have been attempting to make it compatible with IE8. Here is a link to the more-or-less working build of my graph.
http://jsfiddle.net/kingernest/YDQR4/1/
After some research, I quickly realized that the only way running D3 on IE8 would be at all feasible is by using other APIs in conjunction with D3. Luckily, I found that someone had already put in some work into a project called "r2d3" which, from my understanding, uses raphael to paint the canvas on the IE8 window instead of using SVG (which apparenly was not supported in IE8).
I have been able to get items drawn on the screen, which is half the battle. However, I'm having many issues, particularly with my tooltip. My tooltip is written as a DIV container that floats and changes position/opacity on hover of the data circles. This seems to work fine in other browsers, but with r2d3, I have not been able to get it working. I suspect this is because of the fact that I am creating the div tooltip outside of the (in the #main div). However, I have tried placing tooltips inside of the SVG container with no avail. I then did more reseach and discovered I would have to wrap a div container inside a tag, but after some experimentation with this, I still wasn't able to get the tooltip to work correctly in IE. I attempted to wrap the in a SVG group (), and altered the positioning of this object instead, but this did not seem to work either, and simply through numerous exceptions when trying to append the foreignObject tag to a group.
At this point I'm sort of stuck, and was wondering if anyone had any suggestions as to how I may be able to successfully implement the tooltips. I've also noticed that using d3.select(this) inside my functions, when attempting to select a particular data point (in this case, a circle) seems to present a number of issues when attempting to access or modify that item's attributes, but I think this is a whole other issue entirely.
Any help is greatly appreciated!
Example of how I'm currently creating the tooltips:
//Create tooltip element
var tooltip = d3.select("#main")
.append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("opacity", 0);
function mousemove()
{ //Move tooltip to mouse location
return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");
}
//Mouseover function for circles, displays shortened tooltip and causes other circles to become opaque
function mouseover()
{
var myCircle = d3.select(this);
d3.select(this).attr("class", "dataCircleSelected"); //Color circle green
tooltip.html( //Populate tooltip text
"Username: " + d3.select(this).attr("username") + "<br/>" +
"Session ID: " + d3.select(this).attr("sessionid") + "<br/>" +
"Impact CPU: " + d3.select(this).attr("impact")
)
.transition()
.duration(250)
.style("opacity", .7);
//After 1000ms, make other circle opaque
svg.selectAll("circle")
.filter(function(d, i){ //return every other circle
return !d.compare(myCircle[0][0].__data__);
})
.transition().delay(1000)
.style("opacity", .2);
}
Have you tried using foreignObjects AND explicitly using the xhtml namespace for html tags in the foreignObject (write xhtml:div instead of div) as explained here: HTML element inside SVG not displayed ?
This would give something like that for the tooltip definition
var tooltip = d3.select("#main").append("foreignObject")
.append("xhtml:div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("opacity", 0);
I have a piece of JavaScript code which creates (using D3.js) an svg element which contains a chart. I want to update the chart based on new data coming from a web service using AJAX, the problem is that each time I click on the update button, it generates a new svg, so I want to remove the old one or update its content.
Here is a snippet from the JavaScript function where I create the svg:
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
How can I remove the old svg element or at least replace its content?
Here is the solution:
d3.select("svg").remove();
This is a remove function provided by D3.js.
If you want to get rid of all children,
svg.selectAll("*").remove();
will remove all content associated with the svg.
Setting the id attribute when appending the svg element can also let d3 select so remove() later on this element by id :
var svg = d3.select("theParentElement").append("svg")
.attr("id","the_SVG_ID")
.attr("width",...
...
d3.select("#the_SVG_ID").remove();
I had two charts.
<div id="barChart"></div>
<div id="bubbleChart"></div>
This removed all charts.
d3.select("svg").remove();
This worked for removing the existing bar chart, but then I couldn't re-add the bar chart after
d3.select("#barChart").remove();
Tried this. It not only let me remove the existing bar chart, but also let me re-add a new bar chart.
d3.select("#barChart").select("svg").remove();
var svg = d3.select('#barChart')
.append('svg')
.attr('width', width + margins.left + margins.right)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')');
Not sure if this is the correct way to remove, and re-add a chart in d3. It worked in Chrome, but have not tested in IE.
I am using the SVG using D3.js and i had the same issue.
I used this code for removing the previous svg but the linear gradient inside SVG were not coming in IE
$("#container_div_id").html("");
then I wrote the below code to resolve the issue
$('container_div_id g').remove();
$('#container_div_id path').remove();
here i am removing the previous g and path inside the SVG, replacing with the new one.
Keeping my linear gradient inside SVG tags in the static content and then I called the above code, This works in IE
You could also just use jQuery to remove the contents of the div that contains your svg.
$("#container_div_id").html("");
You should use append("svg:svg"), not append("svg") so that D3 makes the element with the correct 'namespace' if you're using xhtml.
I follow the code from https://www.d3-graph-gallery.com/graph/line_basic.html and had this code:
svg.append("path")
.datum(filteredData)
.attr("fill", "none")
.attr("stroke", "blue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(k) { return x(k.date) })
.y(function(k) { return y(k.value) })
)
So for me it turned out to be that I slap this right before the generation of new line:
d3.selectAll("path").remove()