Published
Edited
Oct 8, 2020
Importers
1 star
Insert cell
Insert cell
Insert cell
// A composite projection for the Netherlands, configured by default for 960×500.
function geoConicConformalNetherlands() {
var cache,
cacheStream,
netherlandsMainland = d3.geoConicConformal().rotate([-5.50, -52.20]).parallels([0, 60]),
netherlandsMainlandPoint,
bonaire = d3.geoMercator().center([-68.25, 12.20]),
bonairePoint,
sabaSintEustatius = d3.geoMercator().center([-63.10, 17.50]),
sabaSintEustatiusPoint,
point,
pointStream = {
point: function (x, y) {
point = [x, y];
},
};

function conicConformalNetherlands(coordinates) {
const [x, y] = coordinates;
return (
(point = null),
(netherlandsMainlandPoint.point(x, y), point) ||
(bonairePoint.point(x, y), point) ||
(sabaSintEustatiusPoint.point(x, y), point)
);
}

conicConformalNetherlands.invert = function (coordinates) {
var k = netherlandsMainland.scale(),
t = netherlandsMainland.translate(),
x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;

return (y >= -0.0067 && y < 0.0015 && x >= -0.0232 && x < -0.0154
? bonaire
: y >= -0.022 && y < -0.014 && x >= -0.023 && x < -0.014
? sabaSintEustatius
: netherlandsMainland
).invert(coordinates);
};

conicConformalNetherlands.stream = function (stream) {
return cache && cacheStream === stream
? cache
: (cache = multiplex([
netherlandsMainland.stream((cacheStream = stream)),
bonaire.stream(stream),
sabaSintEustatius.stream(stream),
]));
};

conicConformalNetherlands.precision = function (_) {
if (!arguments.length) return netherlandsMainland.precision();

netherlandsMainland.precision(_);
bonaire.precision(_);
sabaSintEustatius.precision(_);
return reset();
};

conicConformalNetherlands.scale = function (_) {
if (!arguments.length) return netherlandsMainland.scale();

netherlandsMainland.scale(_);
bonaire.scale(_);
sabaSintEustatius.scale(_);
return conicConformalNetherlands.translate(netherlandsMainland.translate());
};

conicConformalNetherlands.translate = function (_) {
if (!arguments.length) return netherlandsMainland.translate();

const k = netherlandsMainland.scale(),
x = +_[0],
y = +_[1];

netherlandsMainlandPoint = netherlandsMainland
.translate(_)
.clipExtent([
[x - 0.0245 * k, y - 0.0260 * k],
[x + 0.0230 * k, y + 0.0260 * k],
])
.stream(pointStream);

bonairePoint = bonaire
.translate([x - 0.0186 * k, y - 0.00325 * k])
.clipExtent([
[x - 0.0232 * k + epsilon, y - 0.0067 * k + epsilon],
[x - 0.0154 * k - epsilon, y + 0.0015 * k - epsilon],
])
.stream(pointStream);

sabaSintEustatiusPoint = sabaSintEustatius
.translate([x - 0.0185 * k, y - 0.017 * k])
.clipExtent([
[x - 0.023 * k + epsilon, y - 0.022 * k + epsilon],
[x - 0.014 * k - epsilon, y - 0.014 * k - epsilon],
])
.stream(pointStream);

return reset();
};

function reset() {
cache = cacheStream = null;
return conicConformalNetherlands;
}

conicConformalNetherlands.drawCompositionBorders = function (context) {
// console.table({
// "Clip extent": ["Bonaire", bonaire.clipExtent()],
// "UL BBOX:": netherlandsMainland.invert([bonaire.clipExtent()[0][0], bonaire.clipExtent()[0][1]]),
// "UR BBOX:": netherlandsMainland.invert([bonaire.clipExtent()[1][0], bonaire.clipExtent()[0][1]]),
// "LD BBOX:": netherlandsMainland.invert([bonaire.clipExtent()[1][0], bonaire.clipExtent()[1][1]]),
// "LL BBOX:": netherlandsMainland.invert([bonaire.clipExtent()[0][0], bonaire.clipExtent()[1][1]])
// })
var ulbonaire = netherlandsMainland([3.30573, 52.5562]);
var urbonaire = netherlandsMainland([4.0430, 52.5720]);
var ldbonaire = netherlandsMainland([4.0646, 52.1017]);
var llbonaire = netherlandsMainland([3.3382, 52.0861]);

var ulsabaSintEustatius = netherlandsMainland([3.2620, 53.4390]);
var ursabaSintEustatius = netherlandsMainland([4.1373, 53.4571]);
var ldsabaSintEustatius = netherlandsMainland([4.1574, 52.9946]);
var llsabaSintEustatius = netherlandsMainland([3.2951, 52.9768]);

context.moveTo(ulbonaire[0], ulbonaire[1]);
context.lineTo(urbonaire[0], urbonaire[1]);
context.lineTo(ldbonaire[0], ldbonaire[1]);
context.lineTo(ldbonaire[0], ldbonaire[1]);
context.lineTo(llbonaire[0], llbonaire[1]);
context.closePath();

context.moveTo(ulsabaSintEustatius[0], ulsabaSintEustatius[1]);
context.lineTo(ursabaSintEustatius[0], ursabaSintEustatius[1]);
context.lineTo(ldsabaSintEustatius[0], ldsabaSintEustatius[1]);
context.lineTo(ldsabaSintEustatius[0], ldsabaSintEustatius[1]);
context.lineTo(llsabaSintEustatius[0], llsabaSintEustatius[1]);
context.closePath();
};
conicConformalNetherlands.getCompositionBorders = function () {
var context = d3.path();
this.drawCompositionBorders(context);
return context.toString();
};

return conicConformalNetherlands.scale(9500);
}
Insert cell
projection = compositeProjections.geoConicConformalNetherlands()
Insert cell
path = d3.geoPath(projection)
Insert cell
// 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(); }
};
}

Insert cell
Insert cell
Insert cell
Insert cell
compositeProjections = require("d3-composite-projections@1.4.0")
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more