d3 Tree - How to auto adjust node spacing when zooming - d3.js

I have a d3 tree with zoom and pan functionality. The tree can have a great number of child nodes for any parent. This can result in vertically squashed up nodes.
I would like the nodes to automatically adjust their spacing when zooming out, especially the vertical spacing.
The appending d3 svg and the zoom part of the d3 code:
var svg = d3.select("#tree_container")
.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.call( d3.behavior.zoom().on( "zoom", function () {
svg.attr( "transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")" )
} ) )
.append("g");
Fiddle

Would it be enough to set the node sizes? Then d3 will automatically adjust positions of the nodes.
var radius = 10;
var tree = d3.layout.tree()
.size([height, width])
.nodeSize([radius*2+3]);
...
function update(source) {
...
nodeUpdate.select("circle")
.attr("r", radius)
As Fiddle

Related

D3 Pie Chart rotate only the arcs

My chart needs a label in the center of the donut that should not rotate when clicked.
https://codepen.io/scratchy303/pen/dyXMzrz
Can I append the label in a sibling "g"roup and rotate the arcs group?
Can I translate just the arcs rather than rotating the entire SVG?
What's the simplest solution?
var svg = d3.select("#pieChart").append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox', '0 0 ' + Math.min(width, height) + ' ' + Math.min(width, height))
.attr('preserveAspectRatio', 'xMinYMin')
.append("g")
.attr("transform", "translate(" + radius + "," + height / 2 + ")")
.style("filter", "url(#drop-shadow)");
svg.append("g")
.append("text")
.attr("text-anchor", "middle")
.text("Donut Name");
I found a solution by counter-rotating my text. My biggest hurdle was simply traversing my SVG in D3.
//start by selecting the parent "g"roup and then you can select the text
d3.select(i.parentNode).select(".donut-label")
.transition()
.duration(1000)
.attr("transform", "rotate(" + (-angle) + ")");

Add brush on top of d3 barchart

I am trying to add a brush on top of a barchart in d3. Currently I am using barchart for my example:
https://bl.ocks.org/mbostock/1134768
This is the example of the brush that I want to implement: http://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
I can only find examples where the bush is below the chart and not on the main chart itself. Can anyone explain to me how to put the brush on top of the barchart or point me in the direction of an example that I could follow?
In the Brush & Zoom example you are referring to, there are following lines:
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
...
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
These are specifying positions of the chart area, brush area and zoom area. You can just tweak margin and margin2 values which are specified at the beginning of the script, or explicitly set up a different transformation here.
You need to have margin.top > margin2.top, and tweak bottom margins too.

D3 clipping issues on zoom

I would like to use zoom behaviour in a simple d3 graph. The thing is that whenever I zoom in, the "main" group elements take up the whole svg space, which causes other existing elements such as axes and texts to get overlapped. I have read that clipping can be used to solve this problem but I didn't manage to get it working properly.
The following image (zoom in was applied) shows the problem:
Related example with what I have tried so far can be found here.
I was finally able to solve this problem. Key points were:
Use proper svg element for clipping, normally rect does the job with corresponding width/height (same as your "drawing" area).
Transform all elements drawn within the clip path (region), and not the parent group.
In code (omitting irrelevant parts), the result is:
// Scales, axis, etc.
...
// Zoom behaviour & event handler
let zoomed = function () {
let e = d3.event;
let tx = Math.min(0, Math.max(e.translate[0], width - width*e.scale));
let ty = Math.min(0, Math.max(e.translate[1], height - height*e.scale));
zoom.translate([tx,ty]);
main.selectAll('.circle').attr('transform', 'translate(' + [tx,ty] + ')scale(' + e.scale + ')');
svg.select('.x.axis').call(xAxis);
svg.select('.y.axis').call(yAxis);
}
let zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1,8])
.on('zoom', zoomed);
const svg = d3.select('body').append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.attr('pointer-events', 'all')
.call(zoom);
const g = svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Set clip region, rect with same width/height as "drawing" area, where we will be able to zoom in
g.append('defs')
.append('clipPath')
.attr('id', 'clip')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
const main = g.append('g')
.attr('class', 'main')
.attr('clip-path', 'url(#clip)');
let circles = main.selectAll('.circle').data(data).enter();

Removing single elements of svg in d3.js

I have the following code in d3.js
var svg = d3.select(".Canvas").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 + ")");
svg.append("g").attr("class", "x axis").attr("transform",
"translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").call(yAxisMajor).append("text")
.attr("transform", "rotate(-90)").attr("y", 6).attr("dy",
".71em").style("text-anchor", "end");
I tried the following to remove only the y-axis, not the whole svg:
d3.select(".Canvas").selectAll("svg").selectAll("g").select(".y axis").remove();
Why is the code not working?
Here is a little demo with a couple of simple ways to do it (see my comments in the fiddle).
d3.select("svg > g > #the_one_circle")
.transition().duration(1000)
.attr("r",1)
.remove();
Note how the svg and g elements are still there after removing the circle.
Because when you set class attribute as y axis , you actually set two classes. So in order to select and match both class names you need to call select with .y.axis. So that the result should be:
d3.select(".canvas").selectAll("svg").selectAll("g").select(".y.axis").remove();
at least worked for me, demo.

how to zoom svg semantic graph when the mouse is under svg instead of node

I'm working on collapsible tree graph zoom. Whenever i wanna zoom i have to keep mouse pointer on node(circle) then only i am able to do zoom in and zoom out. But it should be able to that when mouse is any where in graph.
zoom function call is following:
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(d3.behavior.zoom().x(x).y(y).scaleExtent([1,8]).on("zoom",zoom));
I am following this example link for zoom in and zoom out : http://jsfiddle.net/6kEpp/37/
Any help would be much appreciated.
Just append rectangle to the SVG that's it.
svg.append('svg:rect')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.attr('fill', 'white');

Resources