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 :)
Related
I have a created simple snapjs sample here https://plnkr.co/edit/CyeVHuuuWrTAy1yKsp4d?p=preview
This is my Script - I am loading an svg and I would like to paint it in green.
Surprisingly not the svg is colored, but the "bigCircle", which I draw as well.
$(document).ready(function() {
var s = Snap("#svg");
var bigCircle = s.circle(150, 150, 100);
Snap.load("world.svg", function (f) {
var world = s.append(f);
world.attr({
fill: "#bada55",
});
bigCircle.drag();
world.drag();
});
})
Thanks for your help!
You need to select the world after you place it. You are trying to do this with:
var world = s.append(f)
But that doesn't return the paths that make up the world. It returns the entire svg. I would add the world first and then select it. I fixed it by adding this line:
world=s.select('[id="layer1"]')
I saw that the world is all grouped under that id in your svg. Once it's selected, you can apply color/drag like you wanted. Here's the plunker: https://plnkr.co/edit/t4JmZMz4JPJ0dDb95aQc?p=preview
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...
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");
}
I have s1,s2,s3,s4,...s40 SVG image files in deployment subfolder .i want to load each image with replacing other with the help of cursor key controls/mouse clicks on parts of html text.Is it possible through d3.js?
Yes it is possible using d3.js.
// There are probably better ways of loading the SVG, but this is one example I found
d3.xml("test.svg", "image/svg+xml", function(xml) {
d3.select("body").node().appendChild(xml.documentElement);
svg=d3.select("body").select("svg");
console.log(svg[0][0])
slides = svg_slides(svg,1500);
setTimeout(function() { svg_interact(svg);console.log("OK")},100);
// Lets test the slide scales - put a bouncing ball on slide id 3
s = slides[3];
circle = svg.append("svg:circle")
.attr("cx",s.scale_x(500)).attr("cy",s.scale_y(500))
.attr("r",20)
.style("fill","steelblue");
next = 500;
function bounce() {
next = -next;
circle.transition().duration(2500).attr("cx",s.scale_x(500+next))
.each("end",bounce);
}
bounce();
});
See the demo here.. http://bl.ocks.org/ZJONSSON/raw/1254855/
You can find the detailed explanation and code snippet here.. http://bl.ocks.org/ZJONSSON/1254855
Is there any accurate way to get the real size of a svg element that includes stroke, filters or other elements contributing to the element's real size from within Javascript?
I have tried pretty much everything coming to my mind and now I feel I'm coming to a dead end :-(
Updated question to add more context (Javascript)
You can't get the values directly. However, you can get the dimensions of the bounding rectangle:
var el = document.getElementById("yourElement"); // or other selector like querySelector()
var rect = el.getBoundingClientRect(); // get the bounding rectangle
console.log( rect.width );
console.log( rect.height);
It is supported at least in the actual versions of all major browser.
Check fiddle
Both raphael js http://dmitrybaranovskiy.github.io/raphael/ and d3 js http://d3js.org/ have various methods to find the size of an svg object or sets of svg object. It depends on if it's a circle, square, path, etc... as to which method to use.
I suspect you are using complex shapes, so in that case bounding box would be your best bet http://raphaeljs.com/reference.html#Element.getBBox
(Edit: updated reference site.) http://dmitrybaranovskiy.github.io/raphael/reference.html#Element.getBBox
Here is an example using D3.js:
Starting with a div:
<div style="border:1px solid lightgray;"></div>
The javascript code looks like this:
var myDiv = d3.select('div');
var mySvg = myDiv.append('svg');
var myPath = mySvg.append('path');
myPath.attr({
'fill': '#F7931E',
'd': 'M37,17v15H14V17H37z M50,0H0v50h50V0z'
});
// Get height and width.
console.log(myPath.node().getBBox());
If it is an SVG used as a CSS background image and you're using React you can use background-image-size-hook.
import { useBackgroundImageSize } from 'background-image-size-hook'
const App = () => {
const [ref, svg] = useBackgroundImageSize()
console.log(svg) // { width, height, src }
return <SVGBackgroundImageComponent ref={ref} />
}
You didn't specify any programming language. So I can suggest to use Inkscape.
In the file menu you find document's properties and in the first page there's "resize page to content" command. In this way you remove all the white space around your draw and you see the real size. After width and height values apprear inside the header of svg.
I know that Inkscape supports scripting and command line operations but I don't know if it's possible to do the trimming operatation in this way. But if it's possible you can do that from every programming language.