How to scale a TopoJSON map in d3.js - d3.js

In this JSBin, I have a d3.js chloropleth; unlike with a chart, when I change the height and width only the canvas size changes. How do I get the map to scale down as well?

Have a look at the "Let's Make a Map" Tutorial.
You want to define a projection for your path, depending on its type (likely albersUSA in your case):
var projection = d3.geo.albersUsa()
.scale(800)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
You will need to translate the map as needed.

Related

Zoom world map in D3 upto particular level Around a given latitude and longitude

Is there any way that I can focus into d3 world Map around a specific latitude and longitude on load of file.
Here is working plunker in which I can zoom around a d3 world Map.
plunker
Below code is used to zoom in for click.
function clicked() {
currScale2 = projection.scale();
if(beforeClickValue == 0)
beforeClickValue = 150;
beforeClickValue = beforeClickValue + 100;
projection.scale(beforeClickValue);
g.selectAll("path").attr("d", path);
}
I need to zoom in near or around Kenya, if I provide a particular location in Kenya, eg:
Latitude 0.55378653650984688
Longitude 35.661578039749543
If your centering point is determined by a feature
If your point is a feature centroid, then you can automatically center your map using that feature:
There are a few ways to achieve this, one would be to set your projection to be centered on your features:
projection.fitSize([width,height],geoJSONKenyaTurkana);
fitSize takes the width and height of a bounding box - your svg - and sets the scale and translate of the projection to maximize the size of the features within that bounding box. .fitExtent will allow a bit more flexibility regarding margins:
projection.fitExtent([[10,10],[width-10,height-10]],geoJSONKenyaTurkana);
This will provide margins of 10 pixels: the first coordinate is the top left of the bounding box, while the second coordinate is the bottom right.
After setting your projection to be centered with either method, then you can append the features - your zoom constraints, however, will be relative to this starting point - as you have zoomed in on the projection. Here's a plunkr with this approach (using fitSize):
https://plnkr.co/edit/E7vqcwwISmmxUarCsWvw?p=preview
I've used your featureCollection as the feature, but you could center it on an individual feature in the feature collection.
Alternatively, and possibly more in line with your title, you can use a zoom identity to set the intitial zoom factor with d3.zoom, this manipulates the svg rather than the projection and uses your zoom function:
var bounds = path.bounds(geoJSONKenyaTurkana),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = .9 / Math.max(dx / width, dy / height),
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.call(_zoom.transform, d3.zoomIdentity
.scale(scale)
.translate(translate[0]/scale,translate[1]/scale)
);
This gives us something that looks like this:
https://plnkr.co/edit/CpL4EDUntz853WzrjtU0?p=preview
If you want to manually set a centering point
If however, you want to set your map to be centered according to a manually set point, you can accomplish this much the same way as above: modifying the projection, or modifying the zoom:
To modify the projection, you can use .center() which takes a coordinate and centers the map on this point:
projection.center([longitude,latitude])
Of course, points don't have area, so you will have to set the scale factor yourself, the value will depend on what you want to show:
projection.center([longitude,latitude]).scale(k);
Larger values are more zoomed in.
Alternatively, to manipulate the zoom function, we can use something like:
var x = projection([35.661578039749543,0.55])[0],
y = projection([35.661578039749543,0.55])[1],
scale = 20,
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.call(_zoom.transform, d3.zoomIdentity
.scale(scale)
.translate(translate[0]/scale,translate[1]/scale)
);
As with setting the projection to center on a specific point, you'll need to set a scale value manually. Here I've arbitrarily chosen 20.

How can I add space between features in d3 geo projections

I have a simple d3 geojson projection here. I am using the following for my scaling...
var projection = d3.geo.albersUsa()
.translate([$scope.width / 2, $scope.height / 2]);
Is there a way to add a margin between the state "features" in this projection. So say I want 10px between the borders of every state.

D3 - Centering Map Using Lat/Lon Origin

This is now driving me insane. I've read pretty much all the posts on this, and still cannot work out how to do it efficiently, i.e. not trial and error.
I have a map of Sweden, and I basically want to zoom into the map using a lat/lon position as the center point (14.4W, 57.2N). My projection variable settings are as follows:
var projection = d3.geo.albers()
.center([0, 57.2])
.rotate([14.4, 0])
.parallels([50, 60])
.scale(900 * 3)
.translate([width / 2, height / 2]);
At the default scale (150), the map centers properly. When I try to scale up however, I don't understand why the 14.4W, 57.2N position is not remaining in the center of the canvas?
Can anyone please shed some light? The full Gist code is here Sweden map Gist and the block is here Sweden map block

Combining semantic zooming and quadtree brushing in D3

I am trying to combine the implementation of a semantic zoom with a brush selection tool with a quadtree on a scatterplot in D3.
The idea is that the zoom is active by default. On input selection, A brush is created and the mousedown event of the zoom is deactivated. To speed the brushing, I would like to organize the data that is visible (i.e. the data that has been zoomed on) in a quadtree (c.f. http://bl.ocks.org/mbostock/4343214). But I have no idea how to create the quad tree from the zoom extent only.
I tried creating the quadtree as such:
var scaleX = d3.scale.linear()
.domain(...)
.range(...);
var scaleY = d3.scale.linear()
.domain(...)
.range(...);
// var data is an array of Objects containing the coordinates (x,y)
var dataCoords = data.map(function(d){return [scaleX(d.x) scaleY(d.y)];});
/******
Define d3.zoom.extent which does not exist (contrary to d3.brush.extent())
*******/
var s= d3.event.scale;
var t = d3.event.translate;
//top left corner
var tl = ...;
//bottom right corner
var br = ...;
d3Zoom.extent = [tl, br];
/******
Create quadtree from extent
*******/
var quadtree = d3.geom.quadtree()
.extent(d3Zoom.extent)(dataCoords);
But it does not work. The only way I managed to get a quadtree was to pre-create it using the full svg as extent, before I zoom:
var quadtree = d3.geom.quadtree()
.extent([[-1, -1], [size + 1, size + 1]])(dataCoords);
When I pre-create the quadtree before zooming on the entire data, and zoom afterward, the quadtree desynchronizes with the newly zoomed data because the values in data depend on the axes scale which are updated during the zoom event (semantic zooming).
I haven't been able to combine http://bl.ocks.org/mbostock/4343214 and Zooming and brushing in d3 force directed graph, and I haven't found anything relevant in http://techslides.com/over-2000-d3-js-examples-and-demos or http://bl.ocks.org or SO.
Could someone please give me a fiddle that shows how to brush on a quadtree that contains only the subset of the data that is zoomed upon?

d3 create a custom compressed projection based on the mercator projection

How do i create a custom projection based on the mercator projection which is compressed / scaled in the y-Axis ?
Right now I am using a TopoJson with this projection
var projection = d3.geo.mercator()
.rotate([96, 0])
.center([-.6, 38.7])
.scale(1070)
.translate([width / 2, height / 2]);
Do I have to use the d3.geo.projectionMutator or d3.geo.stream ?

Resources