Skip to content

Commit

Permalink
Make .angle() a first class method of projectionMutator
Browse files Browse the repository at this point in the history
  • Loading branch information
Fil committed Mar 9, 2018
1 parent 6c1c0d6 commit 0dbb7a7
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 3 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ A convenience method for [*projection*.fitSize](#projection_fitSize) where the h

A convenience method for [*projection*.fitSize](#projection_fitSize) where the width is automatically chosen from the aspect ratio of *object* and the given contraint on *height*.

<a href="#projection_angle" name="projection_angle">#</a> <i>projection</i>.<b>angle</b>([<i>angle</i>]) [<>](https://github.com/d3/d3-geo/blob/master/src/projection/index.js#L109 "Source")

If *angle* is specified, sets the projection’s angle to the specified *angle* in degrees and returns the projection. This parameter defines the orientation of the map (usually, the East direction at the *center* — disregarding the projection’s *rotate*). If *angle* is not specified, returns the projection’s current angle (between -180 and 180 degrees).

#### Azimuthal Projections

Azimuthal projections project the sphere directly onto a plane.
Expand Down
Binary file added img/angleorient30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions src/projection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import clipCircle from "../clip/circle";
import clipRectangle from "../clip/rectangle";
import compose from "../compose";
import identity from "../identity";
import {degrees, radians, sqrt} from "../math";
import {cos, degrees, radians, sin, sqrt} from "../math";
import {rotateRadians} from "../rotation";
import {transformer} from "../transform";
import {fitExtent, fitSize, fitWidth, fitHeight} from "./fit";
Expand All @@ -24,6 +24,14 @@ function transformRotate(rotate) {
});
}

function angleTransform(angle) {
angle *= radians;
return {
c: cos(angle),
s: sin(angle)
};
}

export default function projection(project) {
return projectionMutator(function() { return project; })();
}
Expand All @@ -34,6 +42,7 @@ export function projectionMutator(projectAt) {
x = 480, y = 250, // translate
dx, dy, lambda = 0, phi = 0, // center
deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
angle = 0, t = angleTransform(angle), // angle
theta = null, preclip = clipAntimeridian, // clip angle
x0 = null, y0, x1, y1, postclip = identity, // clip extent
delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
Expand All @@ -42,6 +51,7 @@ export function projectionMutator(projectAt) {

function projection(point) {
point = projectRotate(point[0] * radians, point[1] * radians);
if (t.s) point = [point[0] * t.c + point[1] * t.s, -point[0] * t.s + point[1] * t.c];
return [point[0] * k + dx, dy - point[1] * k];
}

Expand All @@ -51,7 +61,9 @@ export function projectionMutator(projectAt) {
}

function projectTransform(x, y) {
return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
var point = project(x, y);
if (t.s) point = [point[0] * t.c + point[1] * t.s, -point[0] * t.s + point[1] * t.c];
return [point[0] * k + dx, dy - point[1] * k];
}

projection.stream = function(stream) {
Expand Down Expand Up @@ -90,6 +102,10 @@ export function projectionMutator(projectAt) {
return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
};

projection.angle = function(_) {
return arguments.length ? (angle = ((+_ % 360) + 360 + 180) % 360 - 180, t = angleTransform(angle), recenter()) : angle;
};

projection.precision = function(_) {
return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
};
Expand Down
1 change: 1 addition & 0 deletions test/compare-images
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ for i in \
gnomonic \
mercator \
naturalEarth1 \
angleorient30 \
orthographic \
stereographic \
transverseMercator; do
Expand Down
18 changes: 18 additions & 0 deletions test/projection/angle-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var tape = require("tape"),
d3 = require("../../");

tape("test angles", function(test) {
var projection = d3.geoGnomonic().scale(1).translate([0, 0]);
test.deepEqual(projection([0,0]), [0,0]);
test.equal(projection([10,0])[1], 0);
projection.angle(30);
test.deepEqual(projection([0,0]), [0,0]);
test.equal(projection.angle(), 30);
test.inDelta(projection([10,0])[1], 0.08816349, 1e-6);
projection.angle(180);
test.inDelta(projection([10,0])[1], 0, 1e-12);
test.equal(projection.angle(), -180);
projection.angle(5702);
test.equal(projection.angle(), -58);
test.end();
});
9 changes: 8 additions & 1 deletion test/render-world
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ var world = require("./data/world-50m.json"),
// case "littrow": outline = graticule.extent([[-90, -60], [90, 60]]).outline(); break;
// }

var projection;

if (projectionSymbol == 'geoAngleorient30')
projection = d3_geo.geoEquirectangular().clipAngle(90).angle(30).precision(0.1).fitExtent([[0,0],[width,height]], {type:"Sphere"});
else
projection = d3_geo[projectionSymbol]().precision(0.1);

var path = d3_geo.geoPath()
.projection(d3_geo[projectionSymbol]().precision(0.1))
.projection(projection)
.context(context);

context.fillStyle = "#fff";
Expand Down

0 comments on commit 0dbb7a7

Please sign in to comment.