I have a D3 map that I have created on a codepen. Below is the link
http://codepen.io/redixhumayun/full/VPepqM/
I have included some basic zooming and panning onto it. However, when I zoom I want the dots to re-scale to account for the zoom, not just stay the same size. I want them to separate out over the greater area that will be provided after zooming in.
I'm not sure what exactly I should be looking for, which is why I am having a hard time finding it.
Here is the code for the zoom I have currently implemented
var zoom = d3.zoom()
.on('zoom', zoomed);
svg.call(zoom);
//defining the zoomed function here
function zoomed() {
map.attr('transform', d3.event.transform)
meteorite.attr('transform', d3.event.transform);
}
If you want the circles representing the meteorites to stay at their original size, regardless the zoom, this is a possible solution:
Rename your circles' variable:
var meteorites = meteorite.selectAll('circle')
//etc..
And set their radii and stroke according to the zoom:
meteorites.attr('r', function(d) {
return weight_scale(d.properties.mass) / d3.event.transform.k
})
.attr("stroke-width", 1 / d3.event.transform.k);
Here is the CodePen: http://codepen.io/anon/pen/VPapPa?editors=1010
PS: because of scope issues, I had to move some functions.
Related
Hi I am trying really hard to solve this problem. Initially I have an svg-element and inside of it a g-element to make zooming in D3 also possible in Safari. I append a D3 Force-Directed Graph to that g-element after generating it. Zooming works perfectly fine so far.
The Force-Directed Graphis generated as preserved here: https://observablehq.com/#d3/disjoint-force-directed-graph
Initial svg-element created:
svg.value = d3
.select("#network")
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.append("g");
Adding the chart:
d3.select("#network").selectAll("svg g > *").remove();
d3.select("#network").select("svg g").node().append(chart);
And the zoom-function afterwards:
const svgZoom = d3.select("#network svg");
const g = d3.select("#network svg g");
svgZoom.call(
d3
.zoom()
.on("zoom", function () {
g.attr("transform", d3.zoomTransform(this));
})
);
Now the issue is that the graph always gets cut. I already tried visibility:visible on each of those elements, still not working. Even if I set a viewBox much bigger than the actual content, or if I set the size of the graph to a minimum, the graph will always get cut to a rectangle.
What I want to accomplish is add the graph full-size and by zooming out the overflowing elements get visible. I do not want to get the height and width of the container and minimize the size of each graph drawn, because some graphs are much bigger than the other ones and I want to keep the initial size of the nodes.
How it currenty looks
Without Zooming Out
Zooming Out
The graph itself cuts the boundaries, adding overflow:visible to the Force-Directed Graph solved the problem.
I am a novice at D3 and I was trying to implement zoom/pan functionality on my scatter plot. Unfortunately, after following a tutorial, whenever I zoom on the visualization, the axes ticks disappear but the visualization doesn't readjust. Could someone explain what I'm doing wrong?
//Adding zoom and pan interaction to visualization
var zoom = d3.zoom()
.scaleExtent([.5, 20])
.extent([0, 0], [width, height])
.on("zoom", zoomed);
// This add an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(zoom);
function zoomed(){
// recover the new scale
var newX = d3.event.transform.rescaleX(xScale);
var newY = d3.event.transform.rescaleY(yScale);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
//update positions
dotGraph.selectAll("circle")
.attr("cx", d => newX(d.installs))
.attr("cy", d => newY(d.reviews));
}
The full code is located here: https://jsfiddle.net/wkLr7hob/
Thanks.
If you comment out the extent portion of your code you'll see the zoom working as expected¹, minus the enforcement of an extent.
You're not providing a valid extent to zoom.extent(), you pass two arrays:
.extent([0, 0], [width, height])
Instead of one [[0,0],[width,height]],
But this still doesn't fix the extent of the zoom behavior, I believe you are looking for translateExtent which limits the panning extent of the chart - however, if we use [[0,0],[width,height]], zooming out to 0.5 is not possible: the extent shown would be greater than the translate extent. So we might as well set the minimum scale to 1.
Doing that we get this.
¹ Also, in the zoom function, you're selecting all circles in dotGraph, but dotGraph is a selection of circles already - so we can drop the selectAll("circle") method in the zoom function. Otherwise the circles won't update.
I am new to d3v4 and working on a chart where i need to show little rectangle on certain date matching to its title on yaxis. The problem i am facing is rectangles in the chart area not drawing equal to the yaxis point labels, i have tried changing the y value by hardcoding, it works fine but the point is the number of data object will change in real time like it could be any number of objects in an array. Here is the plunker
To draw the graph dynamically with limited data objects i've created few buttons on top of chart so that rectangles in the chart can draw equal to y-axis labels.
Any help is much appreciated.
You are using a band scale: that being the case, you should not change the y position, which should be just...
.attr('y', function(d) {
return yScale(d.title);
})
.. and you should not hardcode the height: use the bandwidth() instead:
.attr('height', yScale.bandwidth())
The issue now is setting the paddingInner and paddingOuter of the scale until you have the desired result. For instance:
var yScale = d3.scaleBand().domain(data.map(function(d) {
return d.title
}))
.range([height - 20, 0])
.paddingInner(0.75)
.paddingOuter(.2);
Here is the plunker with those changes: https://plnkr.co/edit/ZxGCeDGYwDGzUCYiSztQ?p=preview
However, if you still want (for whatever reason) hardcode the height or the width of the rectangles, use a point scale instead, and move the y position by half the height.
I'm coding a dimple based bubble chart, which for some z-values removes a bubble and draws a big red X instead, which is an svg path created by line interpolation like this:
var points = [{"x":x-edgeSize,"y":y+edgeSize},
{"x":x,"y":y},
{"x":x+edgeSize,"y":y-edgeSize},
{"x":x,"y":y},
{"x":x-edgeSize,"y":y-edgeSize},
{"x":x,"y":y},
{"x":x+edgeSize,"y":y+edgeSize},
{"x":x,"y":y}];
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
var path = graphSelection.append("path").attr("d",lineFunction(points))
.attr("stroke",color)
.attr("stroke-width",lineWidth);
Now, I want it to be responsive and I followed dimple's example for responsive charts:
Dimple - Responsive sizing and now all the sizes and bounds are by % and I'm calling draw on resize:
this.chart.draw(this.delay,true);
The problem is that the red Xs don't move by themselves, obviously.
So I tried to move it independently on resize, but I don't know the right coordinates until the transition ends - which makes it a 2 step transition.
Will adding the X-path to series.shapes help? will it move along with the other bubbles?
Is there a standard way of doing this?
Thanks
I have a zoomable map of the world with a single point on it (in reality there are multiple points from a separate resource but I have simplified it). The block is here.
When I try and zoom in it jumps to a certain scale and then usually doesn't allow any more zooming movements. I have experimented with various different values for the transition, scale and scaleExtent taken from this example and this one (with the latter being very close to what I want overall) but nothing has worked. It seems to get quite close to the actual size at height/6 for minimum zoom but still behaves badly.
I suspect the main problem is with scaleExtent. I actually want the minimum zoom to be the size of the map and so it isn't possible to pan around unless zoomed in.
The other problem is, as you can see in the bl.ock that the circle disappears when you zoom. I want the circle to maintain position and size (so it doesn't get bigger when I zoom).
Can any one help with
The zoom problem on the map, so the map minimum zoom is the actual size map and I can zoom in to about 6x that
Preventing the map from panning unless zoomed in
Maintaining the size and position of the circle on the map
I've put an example of what I think you're after on this bl.ock which is based on the first example you pointed to. It looks as though this line .scaleExtent([height, height*6]) is limiting the scale (well that the purpose of it) to something that was incompatible with your expectations and the initial scale you set, so when you zoom in past a certain level (in this case height) you get stick between height and height * 6.
If you set your minimum zoom and your initial zoom I think you'll get around some of your issues.
The issue with the dots was that they weren't referenced in the redraw function, so when you zoomed d3 / the browser didn't know what to do with them. In my example I've put the following snippet in to address this:
g.selectAll("circle")
.attr("cx", function (d,i) { return projection(d)[0]; })
.attr("cy", function (d,i) { return projection(d)[1]; })
.attr("r", "10px")
.style("fill", "red");