Comparing two files with the congressional districts.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.states {
fill: #ccc;
stroke: #fff;
}
</style>
<body>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-request.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="d3-composite-projections.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geoAlbersUsaTerritories();;
var path = d3.geoPath()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("path")
.datum({type: "Sphere"})
.attr("d", path)
.style("fill","#eee");
d3.json("us_congress.json", function(error, congress) {
d3.json("us_territories.json", function(error, us) {
svg.append("path")
.attr("class", "us")
.datum(topojson.feature(us, us.objects.us))
.attr("d", path)
.style("fill","#f33");
svg.append("path")
.attr("class", "us")
.datum(topojson.feature(congress, congress.objects.cgd114p010g))
.attr("d", path)
.style("fill","#33f")
.style("opacity",0.5);
});
});
</script>
import {epsilon} from "./math";
import {geoConicConformal as conicConformal} from "d3-geo";
import {path} from "d3-path";
// The projections must have mutually exclusive clip regions on the sphere,
// as this will avoid emitting interleaving lines and polygons.
function multiplex(streams) {
var n = streams.length;
return {
point: function(x, y) { var i = -1; while (++i < n) {streams[i].point(x, y); }},
sphere: function() { var i = -1; while (++i < n) {streams[i].sphere(); }},
lineStart: function() { var i = -1; while (++i < n) {streams[i].lineStart(); }},
lineEnd: function() { var i = -1; while (++i < n) {streams[i].lineEnd(); }},
polygonStart: function() { var i = -1; while (++i < n) {streams[i].polygonStart(); }},
polygonEnd: function() { var i = -1; while (++i < n) {streams[i].polygonEnd(); }}
};
}
// A composite projection for Spain, configured by default for 960×500.
export default function() {
var cache,
cacheStream,
iberianPeninsule = conicConformal().rotate([5, -38.6]), iberianPeninsulePoint,
canaryIslands = conicConformal().rotate([5, -38.6]), canaryIslandsPoint,
point, pointStream = {point: function(x, y) { point = [x, y]; }};
/*
var iberianPeninsuleBbox = [[-11, 46], [4, 35]];
var canaryIslandsBbox = [[-19.0, 28.85], [-12.7, 28.1]];
*/
function conicConformalSpain(coordinates) {
var x = coordinates[0], y = coordinates[1];
return point = null,
(iberianPeninsulePoint.point(x, y), point) ||
(canaryIslandsPoint.point(x, y), point);
}
conicConformalSpain.invert = function(coordinates) {
var k = iberianPeninsule.scale(),
t = iberianPeninsule.translate(),
x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;
/*
//How are the return values calculated:
var c0 = canaryIslands(canaryIslandsBbox[0]);
var x0 = (c0[0] - t[0]) / k;
var y0 = (c0[1] - t[1]) / k;
console.info("p0 canary islands", x0 + ' - ' + y0);
var c1 = canaryIslands(canaryIslandsBbox[1]);
var x1 = (c1[0] - t[0]) / k;
var y1 = (c1[1] - t[1]) / k;
console.info("p1 canary islands", x1 + ' - ' + y1);
*/
return (y >= 0.05346 && y< 0.0897 && x >= -0.13388 && x < -0.0322 ? canaryIslands
: iberianPeninsule).invert(coordinates);
};
conicConformalSpain.stream = function(stream) {
return cache && cacheStream === stream ? cache : cache = multiplex([iberianPeninsule.stream(cacheStream = stream), canaryIslands.stream(stream)]);
};
conicConformalSpain.precision = function(_) {
if (!arguments.length) {return iberianPeninsule.precision();}
iberianPeninsule.precision(_);
canaryIslands.precision(_);
return conicConformalSpain;
};
conicConformalSpain.scale = function(_) {
if (!arguments.length) {return iberianPeninsule.scale();}
iberianPeninsule.scale(_);
canaryIslands.scale(_);
return conicConformalSpain.translate(iberianPeninsule.translate());
};
conicConformalSpain.translate = function(_) {
if (!arguments.length) {return iberianPeninsule.translate();}
var k = iberianPeninsule.scale(), x = +_[0], y = +_[1];
/*
var c0 = iberianPeninsule(iberianPeninsuleBbox[0]);
var x0 = (x - c0[0]) / k;
var y0 = (y - c0[1]) / k;
var c1 = iberianPeninsule(iberianPeninsuleBbox[1]);
var x1 = (x - c1[0]) / k;
var y1 = (y - c1[1]) / k;
console.info('Iberian Peninsula: p0: ' + x0 + ', ' + y0 + ' , p1: ' + x1 + ' - ' + y1);
c0 = canaryIslands.translate([x + 0.1 * k, y - 0.094 * k])(canaryIslandsBbox[0]);
x0 = (x - c0[0]) / k;
y0 = (y - c0[1]) / k;
c1 = canaryIslands.translate([x + 0.1 * k, y - 0.094 * k])(canaryIslandsBbox[1]);
x1 = (x - c1[0]) / k;
y1 = (y - c1[1]) / k;
console.info('Canry Islands: p0: ' + x0 + ', ' + y0 + ' , p1: ' + x1 + ' - ' + y1);
*/
iberianPeninsulePoint = iberianPeninsule
.translate(_)
.clipExtent([[x - 0.06857 * k, y - 0.1288 * k],[x + 0.13249 * k, y + 0.05292 * k]])
.stream(pointStream);
canaryIslandsPoint = canaryIslands
.translate([x + 0.1 * k, y - 0.094 * k])
.clipExtent([[x - 0.1331 * k + epsilon, y + 0.053457 * k + epsilon],[x - 0.0354 * k - epsilon, y + 0.08969 * k - epsilon]])
.stream(pointStream);
return conicConformalSpain;
};
conicConformalSpain.drawCompositionBorders = function(context) {
/*
console.info("CLIP EXTENT: ", canaryIslands.clipExtent());
console.info("UL BBOX:", iberianPeninsule.invert([canaryIslands.clipExtent()[0][0], canaryIslands.clipExtent()[0][1]]));
console.info("UR BBOX:", iberianPeninsule.invert([canaryIslands.clipExtent()[1][0], canaryIslands.clipExtent()[0][1]]));
console.info("LD BBOX:", iberianPeninsule.invert([canaryIslands.clipExtent()[1][0], canaryIslands.clipExtent()[1][1]]));
*/
var ulCanaryIslands = iberianPeninsule([-14.0346750522884, 34.96500729877966]);
var urCanaryIslands = iberianPeninsule([-7.4208899681602025, 35.53698899616862]);
var ldCanaryIslands = iberianPeninsule([-7.314827535125545, 33.54359498636456]);
context.moveTo(ulCanaryIslands[0], ulCanaryIslands[1]);
context.lineTo(urCanaryIslands[0], urCanaryIslands[1]);
context.lineTo(ldCanaryIslands[0], ldCanaryIslands[1]);
};
conicConformalSpain.getCompositionBorders = function() {
var context = path();
this.drawCompositionBorders(context);
return context.toString();
};
return conicConformalSpain.scale(2700);
}