Deleting d3 svg elements for redraw - javascript

I hope you can help me, because this is driving me nuts!
So i was trying to redraw a svg using d3. In my code i add the svg using:
d3.xml("Images/vertical_line.svg", "image/svg+xml", function(xml) {
var importedNode = document.importNode(xml.documentElement, true);
var svg = d3.select('#'+id+'_verticallinecontainer').node().appendChild(importedNode);
});
When my update function is called i then proceed to remove the element:
d3.select("#"+id+'_verticallinecontainer').remove();
This removes the container and the element. I then proceed with redrawing the svg again using the above code.
My problem is that when it appends the svg again it does it twice and i do not understand why! It seems that d3 somehow caches the svg, adding it again.
Hope you can help to clear out what is wrong, any help would be appreciated!

I had a similar problem to this. removing the SVG element did not allow me to fully update the data like I wanted.
Instead, I removed the g elements created inside the SVG with this line:
d3.selectAll("g > *").remove()
in my updateGraph() function
Full explanation and situation shown here:
Repainting/Refreshing Graph in D3

FIDDLE with a quick example of adding, removing and the adding again an SVG and a contained circle. Hope this helps.
function update() {
svg.remove();
svg = d3.selectAll("body").append("svg");
svg.append("circle")
.attr("cx",40)
.attr("cy",40)
.attr("r",20)
.style("fill","blue");
}

Related

having problems selecting svg child elements using d3

I have an svg that I'm trying to access and modify using d3.js. The svg file name is us-map.svg. I've included a reference to the svg in my html like this:
<object id="imgMap" data="us-map.svg" type="image/svg+xml">
</object>
I can select imgMap in my chrome watch panel like this:
var imgMap = d3.select('#imgMap')
However, I'm not able to select child elements. For example, my imgMap svg has several child <g> elements but the child elements are not returned with this function:
d3.select('#imgMap').selectAll('g')
Am I missing something here? I was thinking that d3 could be used to traverse and manipulate an existing svg?
I was thinking that d3 could be used to traverse and manipulate an existing SVG
This is pretty much what d3 does best. But when you write:
d3.select('#imgMap')
You are not selecting the SVG (unless you have an SVG with id = "imgMap", which is not your case). You're using an <object>. Thus, you have to write:
var mySVG = d3.select(document.getElementById("imgMap").contentDocument);
And then select your groups using mySVG.
var myGroups = mySVG.selectAll("g");
Have in mind that this selection only works after the object has been loaded.
Source: https://benfrain.com/selecting-svg-inside-tags-with-javascript/
EDIT:
As requested by the OP, this is a basic working demo: https://plnkr.co/edit/RJOznJROiqTpo5dm9M7L?p=preview
In this plunkr, "mysvg.svg" is an external file (in your code, you'll have to provide the correct path). The code finds the SVG:
var mySVG = d3.select(document.getElementById("imgMap").contentDocument);
And then selects the blue circle inside the SVG, moving it to the right:
var myCircle = mySVG.select("#blueCircle");
myCircle.transition().duration(2000).attr("cx", 180);
Pay attention to this: I set a setTimeout of 1000ms, just to make sure that the object is loaded before the code runs.

Tooltip not showing up d3.js

I have simple tooltip question but I couldn't find the solution.
The codes below draw a doughnut chart. When user mouseovers a segment of pie, the tooltip should pop up in the middle of doughnut. But I don't know why it does not work here. Can anyone help to point out the problem? Here is JSbins
If I change the line 36 to d3.select(#pieChart), the tooltip works. However, for some reasons, I want the tooltip to append on svg.
Thanks a lot!
Not used JSBin a lot so I used JSFiddle : https://jsfiddle.net/thatoneguy/0qgzLk2L/
You can't append a div to svg so you have to create a container like so :
var svgContainer = d3.select('#pieChart');
And then append the svg to this :
var svg = svgContainer.append('svg')
And now use the container for the tooltips :
var tooltip = svgContainer
.append('div')

How to draw non-scalable text in SVG with Javascript?

I'm using d3 library to create a svg graphic. The problem I have is when I resize the window. The whole graphic resizes meaning that texts (legend and axis) resize as well, to the point where it's unreadable. I need it to keep the same size when resizing.
I've been searching online and I found this solution:
var resizeTracker;
// Counteracts all transforms applied above an element.
// Apply a translation to the element to have it remain at a local position
var unscale = function (el) {
var svg = el.ownerSVGElement;
var xf = el.scaleIndependentXForm;
if (!xf) {
// Keep a single transform matrix in the stack for fighting transformations
xf = el.scaleIndependentXForm = svg.createSVGTransform();
// Be sure to apply this transform after existing transforms (translate)
el.transform.baseVal.appendItem(xf);
}
var m = svg.getTransformToElement(el.parentNode);
m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
xf.setMatrix(m);
};
[].forEach.call($("text"), unscale);
$(window).resize(function () {
if (resizeTracker) clearTimeout(resizeTracker);
resizeTracker = setTimeout(function () { [].forEach.call($("text"), unscale); }, 0);
});
And added it to my code, but it's not working. I debugged it and at this part of the code:
var xf = el.scaleIndependentXForm;
It always returns the same matrix: 1 0 0 1 0 0 and the text keeps resizing as does the rest of the svg elements instead of keeping static.
Could anyone help me, please?
Thanks in advance.
The same thing was happening to me with an SVG generated by SnapSVG until I noted that the example page on which this does work wraps its 'main' SVG tag in another SVG tag before using el.ownerSVGElement.ownerSVGElement rather than el.ownerSVGElement.
Wrapping my SVG in an 'empty' wrapper SVG (note style overflow:visible;) I had much better results!
Edit: oh, wait. Internet Explorer still isn't happy. Seems the author of the solution is aware...

How to use element from defs inside a circle in D3.JS

I have a shape (a drawn cloud) in a g within a defs tag. Unfortunately, I am not able to use this shape inside a circle using d3.js. Here is my code:
JSFiddle
What I am trying to do is to display that shape which is in defs tag inside the circle shown in the SVG. I have tried many times in different ways but I could not use the shape from the defs tag inside the circle. Could anyone please assist me with this issue? Thank you in advance.
A circle can't contain other shapes. According to the MDN docs it may only contain descriptive elements and animation elements. These categories don't include shapes like circle, or use.
Rather than nesting your shapes, you should create a parent g and append the circle and use to that:
// Create a `g`, rather than a `circle`, for each data point
var groups = svg.selectAll(".group").data(data).enter().append("g")
.attr("class", "group");
// Append a `circle` to the new g
groups.append("circle")
.attr("cx",100).attr("cy",100).attr("r",20);
// Append a `use` to the new g
groups.append("use").attr("xlink:href", "#mySymbol");
JSFiddle

Can't select svg element with d3

I am working on a visualization tool that uses a svg image of the brain. Now this svg has paths that are filled with a color. I want to loop over all these paths to set the fill color to white, but for some reason I cannot get the element.
The project can be seen here. The svg is inside a div and I even assigned an identifier brain to the div. The svg itself has an id svg2. So far I've tried the following:
function clearBrainColors() {
var brain = d3.select("#svg2");
console.log(brain);
var paths = brain.selectAll("path");
console.log(paths.length);
brain.selectAll('path').each(function(d,i) { console.log(this); });
}
But it outputs null in the array[0] component of the selection and 0 with paths.length.
I've also tried to use lines such as
var brain = d3.select("#brain svg"); and var brain = d3.select("#brain svg#svg2"); but those do not work either.
So, how can I select the brain svg using d3?
Decided to put the svg inline as it apparently speeds things up.
The code I used to fill the svg is now:
$("#svg2").find("path").each(function(){
$(this).css({ fill: "#ff0000" });
});
You can try setTimeOut() , following example
setTimeOut(function() {
var brain = d3.select("#svg2");
console.log(brain);
}, 1000);
this could be the svg is generate on the spot, d3 unable get at that moment.
Hope this help :)

Categories