Set backgroud image from the javascript not working - javascript

In my javascript I have my div svg as following:
var svg = d3.select("#"+settings.id).append("svg")
.attr("id", "svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
And then I added
document.getElementById('svg').style.backgroundImage = 'url(myimageUrl)';
But it didnt work

you are not passing a variable to, it looks like myimageurl should contain a string with the image name like "picture.jpg" if so, you may not pass the variable in quotes, because its a string then.
document.getElementById('svg').style.backgroundImage = 'url('+myimageUrl+')';
another interpretion of the question may be :
it depends on where or better when you execute the line that changes the background color.
when you ecexute it before the svg-variable is inserted to the dom it wont find the id of the element, so be sure to run it after that.

Related

d3.js Get Legend Outside of Chart

I am trying to get the legend of my chart outside of the charting area.
Here are the margins:
var margin = {top: 50, right: 200, bottom: 50, left: 40};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
First I create the svg:
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
So, from my understanding, I now have the svg canvas element and a g inside of it which holds the chart. I am trying to add more to the right margin, so I can get some space between the svg canvas and the g appended to it, which holds the chart. Then I want to put my legend in that empty space.
Here is where I add my legend:
//add legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("height", 300)
.attr("width", 200)
.attr("transform", "translate(-1000,50");
Even though I am appending to the SVG element, it is appending to the g within the svg element. So, no matter how much I translate it or try to get it to go more right on the screen, it never goes past the width of the inner g.
When troubleshooting, I see that the outer SVG element has a height of 960 and width of 500. The g appended to that has a transform/translate of 40,50. The width ends up being 839px by 433.223px (not sure I understand this). The outer svg has a bunch of space to the right now because of the margin built in.
So I'm trying to either increase the width of the g appended to the svg so I can put my legend as a child of the g and move it to the empty space created by the margin. Or, I'm trying to create another g that is a sibling to the first g and then I can use the empty space created by the margin.
I can't get either to work and don't know which way is best.
Notice that the var svg is being assigned to a <g> nested inside the <svg>
svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g") // <-- This is what svg is currently being assigned to
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
And so, when you later execute var legend = svg.append("g"), you're actually appending the legend as a child of the aforementioned <g>. And that's what you described seeing in the dev tools.
One implication is that the translate() transform you applied to the outer <g> affects the inner <g> (i.e. the translation of the innter <g> of legend is added to that of the outer <g>).
Likely, you want split things up like so:
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var inner = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Then change your code to draw the existing chart into inner rather than svg.
As a result, var legend = svg.append("g") will append legend as a sibling of inner, and any translation you apply to legend would be relative to the svg's top left (as opposed to inner's top left, which is translated by margin)
And likely you want to translate legend like so:
var legend = svg.append("g")
.attr("transform", "translate(" + width - margin.right + "," + margin.top + ")");
That moves the legend to the right end of the chart, MINUS margin.right. That way, you can tweak margin.right to create enough room for legend.
Finally, note that calling
legend
.attr("height", 300)
.attr("width", 200)
doesn't do anything, because for svg <g>, there isn't a way to explicitly set the width and height. Those wouldn't mean much anyway, because svg doesn't have a the "flow" behavior of html layouts. The width and height shown in dev tools are the implicit bounds resulting from the bounds of the children of the <g>. (If needed, there's a way to get those computed bounds in javascript, using the getBBox() function).
by looking at the code you provided, you are actually attaching the legend var to your group "g", instead of "svg", var legend = svg.append("g")
in this line you are telling d3 to get your legend variable to "g" which is append to svg, if i understand correctly you should try something like this:
var legend = svg.selectAll(".legend")
.enter().append("g")
to create another group "g" for your legends.
i apologize for my bad english.

SVG element produced by JavaScript script jumps out from the div

I have created GANTT chart using D3 Gannt Chart (http://bl.ocks.org/dk8996/5449641). I embed it to an div that I wish to position as following:
<div id="gantt" class="container">
<div id="gantt-deep">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="js/lib/gantt-chart-d3v2.js"></script>
<script type="text/javascript" src="js/gantt.js"></script>
</div>
</div>
The problem is that when I run the code the SVG created by the script jumps out of the div as seen in the following code when looked in Firefox:
<div id="gantt" class="container">
<div id="gantt-deep">
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript">
<script src="js/lib/gantt-chart-d3v2.js" type="text/javascript">
<script src="js/gantt.js" type="text/javascript">
</div>
</div>
<svg class="chart" width="990" height="490">
<g class="gantt-chart" width="990" height="490" transform="translate(150, 20)">
</svg>
My question is how do I position that svg element that is created?
In gnatt-chart-d3v2.js that was included in the example you provided there's the following line:
var svg = d3.select("body")
.append("svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "gantt-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + ", " + margin.top + ")");
From what I can tell this appends an svg element to the body. That's why the svg "jumps" out of your div - because it is appended to the body, not inserted where you include the script tags.
A possible solution to this would be to change "body" to whatever element you want to append the svg to, in your case it would be #gantt-deep, as you want to target the div with id gantt-deep.
This is a one-time solution, because it modifies the source code which doesn't allow for inserting an svg wherever. If you need another chart then you'd have to pass in a parameter to that gnatt function to indicate where you want it.
Actually, here's the modified version of gnatt-chart-d3v2.js:
// some code here
function gantt(tasks, element) { // modified this line
initTimeDomain();
initAxis();
var svg = d3.select(element) // modified this line
.append("svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "gantt-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("transform", "translate(" + margin.left + ", " + margin.top + ")");
// leave the rest untouched
And then when you initiate the chart call the function with another parameter, for instance gantt(tasks, "#gantt-deep");
I didn't test this, but it should work.

D3: Select SVG attribute and change it

if I have an SVG...
var canvasBars = d3.select("#chart1").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate("+margin.left+","+margin.top+")");
If I modify the width variable (used to calculate the width attribute) How do I then select the width attribute and modify it with this new width variable?
this does not seem to work:
canvasBars.attr("width", width + margin.left + margin.right);
Your other option is to ensure the former 'canvasBars' variable is actually the canvas.
var svgSelection = d3.select("#chart1").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
var baseGroup = svgSelection.append("g")
.attr("transform", "translate("+margin.left+","+margin.top+")");
Your former 'canvasBars' I have renamed to 'svgSelection'. If you want to modify the "canvas" directly, your former idea will now work.
svgSelection.attr("width", width + margin.left + margin.right);

Set background for d3.js collabsible tree

I create a collabsible tree like in this example (http://bl.ocks.org/mbostock/4339083). I tried to change the background color of the SVG. Therefor I use a "rect" element before inserting the "g" element:
svg = d3.select("#"+targetDIVName).append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "svg_graph")
.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "green") //for example
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
With this method the graph is hidden. Is there any solution to set the "rect" element as background and get the graph visible?
Thank You
SVG elements are drawn in the order in which they are added. So if you want the rect to be in the background, add it as the first element after creating the SVG.
To get a solid background colour, you could alternatively use the viewport-fill attribute, which is not supported by all browsers though.

d3 ignore SVG on selectAll

Still learning d3.js.
I would like to ignore the selection of an SVG panel when using .selectAll("svg").
I am building a visualization comprising four SVG panels. The top SVG panel is used to display header/title information for the visualization.
var svgHeader = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("g");
The next two SVG panels are dynamically created using a range of two numbers representing two years.
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(2012, 2013))
.enter().append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", 200)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("g");
The final SVG contains detail information as the user interacts with the visualization.
Problem: I want to exclude the first SVG panel from the .selectAll("svg") which is used to create the two middle panels. I would like to dynamically build SVG panels and have them locate underneath the previously created header SVG.
Is there any way to exclude the header SVG when dynamically creating the middle panels?
I think the best way you should be going about this is taking advantage of classes and adding an appropriate class to the different svgs and then selecting based on the class rather than the svg. This way you know what each of the svgs represent and you can easily reference them.'
var svgHeader = d3.select("body")
.append("svg")
.attr("class", "svgHeader")
.attr("width", width + margin.left + margin.right)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("g");
And then the other two you add a different class name
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(2012, 2013))
.enter().append("svg")
.attr("class", "data")
.attr("width", width + margin.left + margin.right)
.attr("height", 200)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("g");
Now you can do d3.selectAll("svg.data") and select only svg elements with the class data
Alternatively, you can embed your svg elements in different divs. Assuming you have a div whose id is 'center-div' the following snippet returns you only the svgs contained in it.
d3.selectAll("#center-div svg")
Please also consider that you can append whatever DOM element via d3, so divs can be dinamically generated.

Categories