How can I add space between features in d3 geo projections - d3.js

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.

Related

Drawing state borders with d3 not working as expected

Here's an example of my problem. Eventually this is going to have county/zipcode info drawn on it.
I create a projection and a geo path:
var projection = d3.geo.albersUsa()
.scale(width * 1.3)
.translate([width / 2, height / 2]);
var path = d3.geo.path().projection(projection);
However when I try to add state borders... this happens:
#state-borders {
fill: none;
stroke: #333;
stroke-width: 1.5px;
stroke-linejoin: round;
stroke-linecap: round;
pointer-events: none;
}
svg.append('path')
.datum(topojson.mesh(states, states.objects.states, function(a, b) { return a !== b; }))
.attr('id', 'state-borders')
.attr('d', path);
I've looked at other examples and they all seem to be doing something similar, I can't figure out what I am doing wrong. Its almost like the stroke-livejoin isnt working at all.
Your geographic data is already projected; it does not need to be projected again. A projection takes unprojected points on a 3d globe and projects them to a 2d space, doing this on data that is already 2d won't work.
Your data doesn't comprise of 3d points (with a coordinate space measured in degrees), but rather has 2d points (with a coordinate space measured in pixels). So we can just use an identity transform as there is no need to modify/project/transform the coordinates. In d3v4+ we could use:
var path = d3.geoPath(); // default projection is an identity
But with d3v3, the default projection of a geo path is AlbersUsa. So we need to explicitly state we don't want a projection:
var path = d3.geo.path().projection(null);
This gives us a working fiddle.
That this file is pre-pojected is not immediately self evident. Generally a map that looks like a ball of yarn is a good indicator that you are projecting already projected data.
Now we may have new problems, working with pre-projected geometry can make sizing difficult, more so in d3v3 - this file is intended for a 960x600 viewport. To automatically scale and center a map based on its features see this quesion, several of the answers are meant for v3 of d3 (a,b). But this gets much easier with the fitSize method that you can use in d3v4+, as described in this answer. And for more of a discussion of working pre-projected geometry there is this question. If you intend on overlaying features on top of the preprojected geometry you are probably best to find an unprojected US topo/geojson to simplify things, as discussed here.

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?

How to scale a TopoJSON map in 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.

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