function mapcanvas(projection, c, opts) {
const context = c.getContext("2d");
var angle = projection.angle();
projection.angle(angle - 90);
var show_structure=true, show_sphere = true, show_equator, show_land = true
var path = d3.geoPath(projection, context);
if (opts.clip) context.beginPath(), path(opts.clip), context.clip();
function render() {
context.clearRect(0,0,width, c.height);
if (show_sphere)
context.beginPath(), path({type:"Sphere"}), context.fillStyle = "#fefef6", context.fill();
if (show_sphere)
context.beginPath(), path(graticule), context.strokeStyle = "#ccc", context.stroke();
if (show_equator)
context.beginPath(),
path(d3.geoGraticule().step([0,100]).extent([[-179.99, -25], [179.99, 25]])()),
context.strokeStyle = "brown", context.stroke();
if (show_land) {
var l = land.features ? land.features : [ land ];
l.forEach((f, i) => {
context.beginPath(), path(f), context.fillStyle = opts.color(f), context.fill();
})
}
if (show_sphere || show_structure || !show_land)
context.beginPath(), path({type: "Sphere"}), context.strokeStyle = "#000", context.stroke();
// To draw them we need to cancel the rotate
if (show_structure && projection.tree) {
var rotate = projection.rotate();
projection.rotate([0,0,0]);
// run the tree of faces to get all sites and folds
var sites = [], folds = [], i = 0;
function recurse(face) {
var site = d3.geoCentroid({type:"MultiPoint", coordinates:face.face});
site.id = face.id || i++;
sites.push(site);
if (face.children) {
face.children.forEach(function(child) {
folds.push({
type:"LineString",
coordinates: child.shared.map(
e => d3.geoInterpolate(e, face.centroid)(1e-5)
)
});
recurse(child);
});
}
}
recurse(projection.tree());
// sites & numbers
context.beginPath(),
path.pointRadius(10)({type:"MultiPoint", coordinates: sites}),
context.fillStyle = "white", context.strokeStyle = "black",
context.fill(), context.stroke();
sites.forEach(site => {
context.textAlign = "center", context.fillStyle = "black",
context.font = "16px Georgia", context.textBaseline = "middle",
context.fillText(site.id, projection(site)[0], projection(site)[1] - 1);
});
// folding lines
folds.forEach(fold => {
context.beginPath(),
context.lineWidth = 0.5, context.setLineDash([3,4]), context.strokeStyle = "#888",
path(fold), context.stroke(), context.setLineDash([]);
});
// restore the projection’s rotate
projection.rotate(rotate);
}
if (false)
d3.select(context.canvas).on('mousemove', function() {
var gni = projection.invert(d3.mouse(this));
context.beginPath(),
path.pointRadius(2)({type:"Point", coordinates: gni}),
context.fillStyle = "green", context.strokeStyle = "black",
context.fill(), context.stroke();
});
}
(context.canvas.render = render)();
// restore the projection angle
projection.angle(angle);
return context.canvas;
}