How to use a svg inside a svg? - javascript

I am using D3.js and i try to create a svg inside an svg.
For example my first svg is this:
var svg = d3.selectAll('body')
.append('svg')
.attr('width',500)
.attr('height',500);
Then i want to create a second svg inside this first one and i want it to appear at the upper right corner of my first svg. How is that possible? I thought about the attributes of width = 100 and height = 100 for the second svg. The reason for this question is, that i use the force-layout in D3.js and it can be realy big depending on the input of data. So i want to put the graph itself in the first big svg and other informations like texts in the smaller second svg. If a solution with div elements could be better, please let me know.

Just append another SVG within the first.
var svg = d3.selectAll('body')
.append('svg')
.attr('width',500)
.attr('height',500);
var innerSVG = svg.append('svg')
.attr('width',100)
.attr('height',100);

Related

In D3, how does one place text inside shapes that already have text attached to them?

I am currently working on the following d3 example where I'd like to place text inside of the arcs, similar to this example. However, whenever I try to append text to anything, the text just doesn't display. I've looked at the developer console, and it appears to be there, but it won't visually display on the screen. I used all the code provided in the first example, except I tried to add the following the the arc elements:
("the d3 element").enter().append("svg:text").text("???")
("the d3 element").enter().append("text").text("???")
("the d3 element").append("svg:text").text("???")
("the d3 element").append("text").text("???")
Aside from cutting off some of the styling changes, it seems like no matter where I put any of this code, it just doesn't want to work for me. I would appreciate and help!
"whenever I try to append text to anything, the text just doesn't display": Text cannot be appended to most svg elements. You can append text to the svg itself or a g, but you cannot append it to a path, rect, circle, etc.
One of the most common methods of dealing with this is to use g elements to place a shape and text while binding data to the g. Using a transform on theg will translate shape and text - great for things like circles and rectangles.
There are several other approaches you can use to overlay text on svg elements:
Use the positioning attributes of an element to set the x and y attributes of text so that you can place text over top of an element.
Use a path as a text path to place text (as in your example)
Use utility methods such as centroid (for arcs or geopaths for example)
Find the bounding box of elements and place elements using this information.
These options help place, but won't make sure that the text falls within the bounds of a shape - that is different complication.
For arcs, one option is to use a circular path as a text-path where the circle has a radius between that of the inner and outer radius of your arc - then place the text using a text offset that reflects the start angle - or make an arc for each piece of text. The general mechanism is shown below (note it can't use a circle element as svg textPaths must follow paths):
var svg=d3.select("body")
.append("svg")
.attr("height",400)
.attr("width",400)
.attr("transform","translate(200,200)")
var arc = d3.arc()
.innerRadius(50)
.outerRadius(100)
.startAngle(0)
.endAngle(2);
var arcText = d3.arc()
.innerRadius(75)
.outerRadius(75)
.startAngle(0)
.endAngle(2);
var arc = svg.append("path")
.attr("d",arc)
.attr("fill","steelblue")
var textPath = svg.append("path")
.attr("d",arcText)
.attr("id","textpath")
.attr("fill","none")
.attr("stroke","black");
var text = svg.append("text")
.append("textPath")
.attr("xlink:href","#textpath")
.text("title")
.attr("startOffset", "25%") // the bottom of the arc is from 50%-100%, the top from 0 to 50%
.style("text-anchor","middle")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
The above mechanism is very similar to the example you link to - it appends text using the arcs as text paths. The example you reference uses text paths of the visible arc(donut) segments themselves - and offsets the x,y positions to move the text into the arc itself (as opposed to on the arc).
Note that I've used v4, as opposed to v3 as in the linked example.

Align text node centrally(horizontally) inside group element

I have this group element and a text node inside it:
var legend = svg_container.append('g');
var legend_text = legend.append('text').attr('y', 0)
//other elements inside 'g'
This is just part of the code. In actuality, I have other child nodes inside the group element created on the fly after the text node(these other elements decide the width of the group element).
How do I position the text node centrally inside the group element?
To center it, you can use the text attribute text-anchor="middle" with the x and y attributes for positioning:
legend_text.attr("text-anchor","middle");
legend_text.attr("x", 0);
legend_text.attr("y", 0);
Here, your text will be fixed to the center origin of your group legend.
In fact, it won't be perfectly centered, to do so, you should set y to the half of the font-size attribute of your text.
Hoping I've correctly understood your problem !
EDIT: With your indication, I see two solutions :
My favorite one would include a modification of the legend group, by adding him a transform="translate(x,y)" attribute,
where the x and y are the center of your svg element. This one may not work with the rest of your code, but I find that doing so in general is a clean way to have multiple drawings living together in a single svg.
The other one is simplier by far, and I think will answer to your problem for now :
You replace the x and y values by the center of your legend group. The little problem here is the calculation of thoses values, because you can't read them directly from the element.
In fact, a g element doesn't have width or height attributes, it's only a container for applying attributes for a group of svg elements. That's why I recommend using my first solution.
Another way of centering it in the group using bbox
//make a g
var svg = d3.select("body").append("svg").attr("width", "900")
.attr("height", "900").append("g");
//add circle to it
svg.append("circle").attr("cx", 50).attr("cy", 50).attr("r", 30);
svg.append("circle").attr("cx", 250).attr("cy", 150).attr("r", 30);
//get bbox
var bb = svg.node().getBBox();
var centery = bb.y + bb.height/2;
var centerx = bb.x + bb.width/2;
svg.append("text").text("Hello").attr("x",centerx).attr("y", centery)
Working code here

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

Nested SVG elements with Raphael

Trying to implement nested SVG elements with Raphael.
I think this Question is related to
https://groups.google.com/forum/#!topic/raphaeljs/tzdj3y2DDwg
Any solution? Thanks.
Actually, I've maneged to partially implement nested svg approach.
This is a short example:
var outer_svg = Raphael(document.getElementById('container'), paper_width, paper_height);
outer_svg.canvas.setAttribute('id', 'outer_svg');
var inner_svg = Raphael(document.getElementById("outer_svg"), paper_width, paper_height/2);
inner_svg.canvas.setAttribute('y', paper_height/2);
Here we created inner_svg that is half the height of outer_svg and is positioned at the bottom of outer_svg.
The canvas object represent the svg dom element. So if we give it an id attr then we can adress it to be the parent of another svg. And we can set the x,y coords relative to parent svg element.
Now the sad part:seems that canvas doesn't support animation method, so we cannot animate the whole svg child element. Sets don't help here because drawing elements parts that are outside child svg canvas disappear (as they should).

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