How can I select my own, custom central-meridian for a d3-map-projection?
As an absolute newbie I started with this example from Mike Bostock:
http://bl.ocks.org/3734333
It shows a Miller-Projection of the world with a central meridian of 0 degrees.
How do I center this (and other projections) in d3 to a custom meridian, eg. 10 degrees east from Greenwich?
I tried using projection.center([0,-10]), but this does not work.
thanks
projection.rotate([longitude,lattitude]) does the trick, eg. .rotate([-10,0]) sets the central meridan to 10 degrees east of greenwich
EDIT 1:
BUT: Now I have this thick, fat line at 180 degrees, which I want to get rid of.
EDIT 2:
we can style this with the following css-rule
.foreground {
fill: none;
stroke: color;
stroke-width: xy px;
}
use the same color for stroke and the same pixel-width for stroke-width then for the graticule
Related
I have a graph of several nodes and edges. I used a layout algorithm (elkjs) to calculate the position of the nodes and edges. The graph is fairly large, with 268 nodes and 276 edges, such that:
svg width: 800, height: 600; graph width: 1844, height: 3007
As such, I had to do the requisite math to calculate pan offsets and scaling so it would fully fit, centered in the viewport:
translate(225.228, 15) scale(0.1896)
I programmatically transition it into place over 2500ms - it works fine and fits nicely.
But then I wish to switch to a subgraph, picking a node to see only it and its descendants. This particular example subgraph is near the bottom of the graph, so the starting position of its y-values are relatively large. After I call the layout algorithm again to get the new positions, the repositioned graph is smaller:
svg width: 800, height: 600; graph width: 874, height: 459
I then do the join/enter/update/exit thing to update the positions over a duration (and remove the other elements not in the subgraph), and I also do the math again for pan offsets and scaling:
translate(20, 100.4348) scale(0.8696)
Here's the problem: while it does end up in the right place, it pans off-screen before panning back on-screen:
I think I see why: the re-positioning transition has the same duration (2500ms) as the panning/scaling, and something about that all combined has that undesirable effect. I'm able to keep the subgraph on-screen by making the positioning happen faster:
rects
.transition().duration(1500) // instead of 2500
.attr('x', (d) => d.x ?? 0)
.attr('y', (d) => d.y ?? 0)
but that's of course not a universal solution, and it kind of moves around haphazardly. I'd rather have a way to interpolate the re-positioning with the translate so it smoothly grows and pans to be centered without going off-screen. Is this possible? I'm aware of d3.interpolate and scaleExtent/translateExtent but am stumped on how to use them - so far I haven't figured out how to account for both repositioning and translate/scale at the same time.
Other relevant bits of code:
<svg
style={{ borderStyle: "Solid", borderWidth: "1px" }}
width="800"
height="600"
onClick={onClickHandler} <!-- this just switches to the subgraph -->
>
<g />
</svg>
const gr = d3.select('g');
const rects = gr.selectAll<SVGSVGElement, ElkNode>('rect').data(elkGraph.children, (d) => d.id);
// update, enter, exit logic omitted; see above for position update
// offset and scale logic omitted
gr.transition().duration(2500)
.attr('transform', `translate(${xCenterOffset}, ${yCenterOffset}) scale(${scaleFactor})`)
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.
Have a graph that is very long. And I have the x-axis on the top of the graph. Was wondering if it is possible to have a floating x-axis so when the user scrolls down the graph the x-axis stays on the screen for the user to see?
Thank you for your help
In most case in d3js,
developers create a single svg element. But you can separate them; eg. x/y axis and data drawing area. And then You can assign this svg field statically via css to be constant.
var axisSvg = d3js.select('axisSvg').append('svg').attr('class','axisSvg);
var mainSvg = d3js.select('mainSvg').append('svg').attr('class','maingSvg);
and in css
.axisSvg{
position: fixed;
bottom: 0;
right: 0;
width: 300px;
}
What am I doing wrong to rotate around center
I set transform-origin of each is right in the center of square
Look here pls
https://jsfiddle.net/yqx90or9/1/
group.style.transformOrigin = '100px 100px'
group.style.transform = 'rotate(90deg)'
The problem is this line:
transition: all 1s linear 1s;
When you change the style, you are changing the transform, but you are also changing the transform-origin. So both get animated. The result is your weird behaviour. Change it to:
transition: transform 1s linear 1s;
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.