How to properly rotate text labels in a D3 sunburst diagram - javascript

In the following D3 sunburst :
http://jsfiddle.net/maxl/eabFC/
.attr("transform", function(d) {
return "rotate(" + (d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180 + ")";
});
The labels in the left quadrants are upside down, I would like to perform a rotation on them so that the text reads from left to right.
The transformation should only apply to the arcs from approximately 100 degree to 270 degree.

Following this example: http://www.jasondavies.com/coffee-wheel/
I've edited your jsfiddle here: http://tributary.io/inlet/4127332/
You are going to have to deal with your long labels and the above example shows how to do multi-line.
Also note that you are using an old version of d3, it is no longer necessary to call d3.layout separately. Here is the link to new shiny version of d3:
<script src="http://d3js.org/d3.v3.js"></script>

Related

Zooming issues with Force Directed

I've generated a D3 visualization (a force directed graph) that requires zooming and panning. I've got 2 problems however when it comes to zooming, and I can't find any decent examples on how I might overcome these problems:
The first problem is I've followed all the examples I can find about zooming, which involves adding groupings and adding a rectangle to ensure that the entire area is zoomeable. If I style the rectangle a slightly opaque blue then I get SVG that looks like this when I zoom out:
The problem with this is that I can zoom in/out absolutely fine while I've got my mouse over the blue rectangle area. The problem is I want this to be fully opaque, which means that when I zoom right out, it's very easy to place the cursor outside of this box and then you're unable to zoom in. Is there a way I can make the SVG itself zoomeable or pick up on these events?
This is how I go about generating the various layers and the zoomed function:
function zoomed() {
group2.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
svg = d3.select(target)
.attr("pointer-events", "all")
.append("svg");
group = svg.append('svg:g')
.call(d3.behavior.zoom().on('zoom', zoomed))
.on("dblclick.zoom", null);
group2 = group.append("g");
rect = group2.append('svg:rect')
.style("opacity", 0.3)
.attr('width', width)
.attr('height', height);
The second problem I have is that I'm trying to automatically size my text based on this http://bl.ocks.org/mbostock/1846692 example. When I've tried this however I seem to be getting text that renders really poorly. It seems to suffer from:
Being difficult to read
Not appearing contained within the circle
Being so small the entire thing compresses (image 2)
var texts = planets.append("text")
.text(function(d) { return d.name; })
.style("font-size", "24px") // initial guess
.style("font-size", function(d) {
return Math.min( 2 * d.size, (2 * d.size - 8) / this.getComputedTextLength() * 24) + "px";
})
.attr("dx", function(d) { return -d.size; })
.attr("dy", ".35em")
.style("fill", "white");
I thought that SVG would just handle this, I understand that some of the font-sizes can come out small, but if you zoom in should that not all sort itself out?
I've got a JSFiddle http://jsfiddle.net/IPWright83/vo7Lpefs/22/ to demonstrate.
I've not yet managed to work out a resolution to my first issue (regarding the zooming box) however I did manage to track down the text rendering issue.
This was actually because the each circle/node had a stroke property to provide the white border. This was also applying to the text element, and when the font was very small the stroke was much larger than the overall fill of the text. Removing the stroke from the text elements ensured that they rendered even when very small.

how to get the radial gradient to start from the centre of the pie chart?

In my pie chart with grid lines, I have integrated a radial gradient. The problem is that it there is a gradient for every pie. I actually want a gradient which is common and it originates from the center of the pie chart.
I tried:
var arc = d3.svg.arc()
.attr('fill', 'url(#gradient)')
.outerRadius(function(d) { return 50 + (radius - 50) * d.data.percent / 100; })
.innerRadius(20);
but it didnt help.
How to get the radial gradient to start from the centre of the pie chart?
jsFiddle
In your JSFiddle you are using the wrong attributes. RadialGradient does not have x1, x2, etc. It has cx, cy and so on.
On your <radialGradient> tag, add an attribute called gradientUnits and set its value to "userSpaceOnUse".
This means that the gradient attribute percentages (cx, cy, etc.) will be considered for the entire SVG instead of just for a particular shape. Then adjust the values as needed.
Here is the working solution: http://jsfiddle.net/kqfnuavq/

Rotating an SVG element 360 degrees does nothing

I'm using d3.js. I'm trying to rotate an SVG element 360 degrees, so that it spins once and returns to it's original position.
Rotating it 3/4 of the way like this works fine:
thing
.transition()
.attr('transform', 'rotate(270,640,426)')
.duration(6000);
But trying to animate the complete rotation does nothing:
thing
.transition()
.attr('transform', 'rotate(360,640,426)')
.duration(6000);
I think d3 (or maybe this a more general fact about svg transform attribute) sees that the end is the same as the beginning and just takes the shortcut by doing nothing. Similarly, if I do 365 degrees, it only moves +5 degrees.
A. Why is this?
B. What's the right way to do it?
D3 normalizes the SVG transforms; this is the cause for the effect you're seeing. You can do this however with a custom tween function:
function rotTween() {
var i = d3.interpolate(0, 360);
return function(t) {
return "rotate(" + i(t) + ")";
};
}
Complete example here.

D3.js and dragdealer JS

I am using dragdealer JS with D3.js. What i am doing is that when You drag the slider made by dragdealer JS the elements made by D3.js will move like a picture slider.
Here is the code which which i wrote : code.
Now there are two problems with this code:
1) This code is working in FireFox but not in Chrome & IE 10?
2) How to configure the slider so that on one slide, only one tile will move into the view and only one will move out?
The number of tiles or rectangles are not fixed. There can be any number of tiles depending on the user.
Code:
var width = 4000,
height = 200,
margin = 2,
nRect = 20,
rectWidth = (width - (nRect - 1) * margin) / nRect,
svg = d3.select('#chart').append('svg')
.attr('width', width);
var data = d3.range(nRect),
posScale = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width - rectWidth]);
console.log(rectWidth)
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', posScale)
.attr('width', rectWidth)
.attr('height', height);
function redraw(x)
{
svg.transition()
.ease("linear")
.attr("transform", "translate(" + -(x*rectWidth) + ")" );
console.log(-(x*rectWidth));
}
var step = nRect/2;
new Dragdealer('magnifier',
{
steps: step,
snap: true,
animationCallback: function(x, y)
{ console.log(x*10)
redraw(x*step);
}
});
i am trying to devise a way so that the value of steps will change according to the number of tiles.
Please help me.
You had a few problems that I've fixed here: http://jsfiddle.net/SqKZv/1/
In Chrome your svg element needed the height property set
In Chrome/IE, it doesn't appear that you can apply the transform attribute to your SVG element, I'm actually surprised this works in FireFox. I wrapped all of your rect elements in a g element and transformed that.
D3 does dragging very well by itself, so you don't need Dragdealer to do this. In addition to d3.behavior.drag, you can check out d3.svg.brush, specifically these examples of snapping to get what you want:
Brush Snapping http://bl.ocks.org/mbostock/6232537
Brush Snapping II http://bl.ocks.org/mbostock/6232620
You may also want to try out the new D3 feature called brush: https://github.com/mbostock/d3/wiki/SVG-Controls
Here is an example I made using brush to implement a similar feature as you mentioned.
https://github.com/CSE512-14W/a3-chaoyu-aniket

Does d3.js support dynamic Sunbursts

I would like to create a mashup of the functionalities as seen from
http://bl.ocks.org/4063423 and http://philogb.github.com/jit/static/v20/Jit/Examples/Sunburst/example2.html
I would like to use d3.js or at least a pure javascript solution but a solution that will respond to mouse clicks to display more information about the selected section.
Zooming in and out is not mandatory, but if I can achieve it, it will be good.
Now my question, Is there a framework that can support this or do I have to mash them up on my own.
Disclaimer: google was not that helpful!
It is easy to do with D3 alone: http://bl.ocks.org/4678148 If you click any element, the element will be focused and transitioned to 90 deg with the selected class set on it.
Also, the legend text on the top right changes to the name of the element selected. The part of code which achieves this coupling is:
d3.selectAll("path").on("click", function (d, i) {
var newAngle = - (d.x + d.dx / 2);
innerG
.transition()
.duration(1500)
.attr("transform", "rotate(" + (180 / Math.PI * newAngle) + ")");
// Set the class "selected" on the chosen element.
path
.classed("selected", function (x) { return d.name == x.name; });
// Update the text box with the right context
// This can be arbitrarily complex to show as many details about the
// object as required.
textBox.data(["Clicked: " + d.name])
.text(String);
});
Update
For the zoomable behavior such that the clicked element transitions to the center, you can use almost the same code as used as here or here. I have made small changes to the code to show how to extract information about which item was clicked: http://bl.ocks.org/4747342
The change in code required is simpler than before:
d3.selectAll("path").on("click", function (d, i) {
// Zooming
path.transition()
.duration(750)
.attrTween("d", arcTween(d));
// Update the text box with the right context
// This can be arbitrarily complex to show as many details about the
// object as required.
textBox.data(["Clicked: " + d.name])
.text(String);
});

Categories

Resources