d3.js - scaling bubble chart app - javascript

I have a bubble force chart application, and I've created various instances of it. However I can not seem to scale the bubbles in relation to the height/width of the svg.
http://jsfiddle.net/pPMqQ/138/
I've placed an inverse on the heights/widths to alter the viewport - but it doesn't feel like the right approach to me. Does anyone have any experience as to how to correct this?
var inverseHeight = 1/h * 100000;
var inverseWidth = 1/w * 100000;
var svg = d3.select(selector)
.append("svg")
.attr("class", "bubblechart")
.attr("width", parseInt(w + padding,10))
.attr("height", parseInt(h + padding,10))
.attr('viewBox', "0 0 "+parseInt(inverseWidth,10)+" "+parseInt(inverseHeight,10))
.attr('perserveAspectRatio', "xMinYMid")
.append("g")
.attr("transform", "translate(" + (w/4) + "," + (h/4) + ")");

I've tried to scale the actual bubbles
http://jsfiddle.net/pPMqQ/143/
var scale = methods.width*.005;
Its producing an ideal effect - but the chart is not always central.

Related

d3.js Donut chart only draws a single cutoff slice inside a react component

I have made a piechart in javascript and I'm now trying to bring it inside a react component.
However, it only draws a single slice and that one isn't even complete it's cutoff.
Here are images of the cut off slice from the react component and how it looks just rendering in html.
I am not sure why.
This is my function drawing it:
function drawDonut(inputData: DealNumbers[]) {
const radius = Math.min(width, height) / 2;
const color = d3.scaleOrdinal(d3.schemeCategory10);
const arc = d3.arc()
.outerRadius(radius - margin.top)
.innerRadius(radius - radius * 0.5);
const pie = d3
.pie()
.padAngle(0)
.value((d) => d.deals);
svg
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${(width / 2) + margin.left}, ${(height / 2) + margin.top})`);
svg
.selectAll('.arc')
.data(pie(inputData))
.enter()
.append('g')
.attr('class', 'arc')
.append('path')
.attr('d', arc)
.style('fill', (d) => color(d.data.name));
It is pretty much the same except that I'm using a svg view box and I pass width and height as props instead of hardcoding it.
It draws perfectly fine from a javascript.
Thanks for any hints and tips you are able and take the time to give!
Best Regards,
Oliver
The issue was with the view box (moving the origin from 0,0 to -width, -height worked), a workaround for some reason I have had to copy intermediate variables
const pwidth = width
const pheight = height
and use these instead of width. Then I don't need to adjust the viewboxs origin. Which is a bit strange to say the least.
I won't accept this answer here as I have no idea why.
But adding it so someone else may find an answer if they're looking for it.

D3 force graph doesn't pan or zoom as expected

I've built a D3 force graph largely based on these really helpful examples.
I wanted to add pan and zoom functionality, which I tried to do using another example (looks like I can only include two links, but Google "d3 force zoom eyaler" to find it).
Unfortunately, when I zoom out on a graph that is larger than the initial SVG, I get something like this:
Result of dragging and dropping
Here's the relevant code:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().scaleExtent([0.5,2]).on("zoom", redraw));
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
How can I change the pan and zoom behaviour so that it scrolls and makes it possible to see the rest of the graph, rather than just allowing me to move the square that was originally visible?
OK, looks like I worked it out... you need to perform the transform on a <g> rather than on the SVG itself. So:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().scaleExtent([0.5,2]).on("zoom", redraw));
var g = svg.append("g"); // add <g>
function redraw() {
g.attr("transform", // perform transform on g, not svg
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
Just putting this here in case anyone else made the same mistake!

d3 v4: Clip path not updating after pan and zoom

I have a rect holding a clip path, which I'm applying to a group (holding a tree). I have a zoom function bound to the rect which transforms the group, which works fine. I've applied the clip path to the group, and when it first renders it looks like it should. However, after panning or zooming, the drawn tree extends beyond the bounds of the clip path while maintaining its previously-clipped appearance.
var svg = d3.select(this.$.chart);
var svg2 = svg.select("svg");
var main = svg2.append("g")
.attr("class","main")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var treeContainer = svg2.append('g')
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")")
var treeBaseRect = treeContainer.append("rect") // the rectangle which holds the clip path and zoom actions for the tree.
.attr("width", width + margin2.right)
.attr("height", height2)
.style("fill", "#eee")
.style("pointer-events", "all")
.call(d3.zoom().scaleExtent([0.1, 3]).on("zoom", function () {
svgGroup.attr("transform", d3.event.transform)
}));
treeContainer.append('defs').append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width + margin2.right)
.attr("height", height2);
var svgGroup = treeContainer.append("g")
.attr("clip-path","url(#clip)");
Here's some screenshots. First one shows the initial render, which is fine (the clip area is the darker grey rectangle):
Then after doing a scroll zoom or pan, note how the tree is still 'originally' clipped, and not being clipped properly outside of the gray area:
And this is my clip path rect in the DOM structure:
You can tell that the clip rect is still where it's meant to be, but the tree is completely ignoring it. No idea why.
Apparently I hadn't added enough groups. The easy solution was to add another append("g") to the svgGroup I was creating, for a last line looking like this:
var svgGroup = treeContainer.append("g")
.attr("clip-path","url(#clip)")
.append("g");

D3js zoom does not work

I can not make zoom work. Tried everything.
My goal:
zoom on mouse scroll
drag the tree by a mouse
The code is here:
svg = d3.select("#tree-container")
.append("svg").attr("width", width)
.attr("height", height)
.call(zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw))
.append("g")
.attr("transform", "translate(" + 350 + "," + 20 + ")");
jsFiddle
P.S. sorry for spaggeti code
It's the declaration of your redraw function that causes the problem -- if you declare it as a function, it works fine:
function redraw() {
// etc
}
Complete example here.

getting svg elements bounded by a region - javascript

Im using d3.js to draw a scatterplot in javascript and this is my first javascript program. The user can draw a click n drag SVGRectangle to calculate the average of the points that get bounded by the rectangle. I have implemented the rectangle drawing part, I'm stuck with the part where I have to determine which points (SVGCircles) are inside the rectangle. Im trying to get all the circle elements in an array allCircles, and then filtering out the circles that are in the rectangle region. However I cannot figure out how to get the coordinates of the circles. The way I did it below doesnt seem to work.
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 + ")");
var allCircles = svg.selectAll("circle.circles"); //circles is the class for all points
//I have to do the following line coz for some reason the entire array comes as one single //element
allCircles = allCircles[0];
for (var j = 0; j < allCircles.length; j++) {
if (allCircles[j].top > startY && allCircles[j].left > startX
&& (allCircles[j].height + allCircles[j].top) < rectHeight + startY
&& (allCircles[j].width + allCircles[j].left) < rectWidth + startX) {
selectedCircles.push(allCircles[j]);
}
}
Any fixes, suggestions, hints, links would be appreciated as Im really short on time !
When selecting objects with D3, you can't access those attributes directly -- use the .attr() function. That is, instead of allCircles[j].top you would do d3.select(allCircles[j]).attr("top") or allCircles[j].getAttribute("top"). Note that you need to have set those attributes explicitly.
The D3 way to do something like that would be to use the .filter() function on your selection, i.e. something like
svg.selectAll("circle.circles")
.filter(function(d) { return d.top > startY && /* etc */; })
.each(function(d) {
// do something with the selected circles
});

Categories