Published
Edited
Aug 1, 2018
Fork of Base map
Importers
Insert cell
Insert cell
Insert cell
Insert cell
map = function(projection, opts) {

if (!projection) {
projection = d3.geoOrthographic();
}
else if (typeof projection == "string") {
projection = (d3["geo" + projection[0].toUpperCase() + projection.slice(1)])();
}
opts = Object.assign({
inertia: true,
zoom: true,
width: 1000,
heightratio: function(ratio) {return Math.sqrt(ratio * 0.6)},
color: function(n) {return "blue"; }
},opts)
var c = this;
if (!c && projection.rotate && opts.rotate) {
projection.rotate(opts.rotate);
}

var path = d3.geoPath(projection);
var bounds = path.bounds({type:"Sphere"}),
ratio = (bounds[1][1] - bounds[0][1]) / (bounds[1][0] - bounds[0][0]),
height = opts.width* opts.heightratio(ratio);
//* ;
//opts.width * opts.heightratio(ratio);

projection.fitExtent([[2,2],[width-2, height-2]], {type:"Sphere"});
if (opts.svg) {
if (c && c.getContext) c = false;
c = c || DOM.svg(width, height);
mapsvg(projection, c, opts);
}
else {
if (c && !c.getContext) c = false;
if (!c) c = DOM.context2d(width, height).canvas;
mapcanvas(projection, c, opts);
}

c.projection = projection;
if (opts.inertia && d3.geoInertiaDrag) {
let sel = d3.select(c)
.style('cursor', '-webkit-grab')
.style('cursor', '-moz-grab')
.style('cursor', 'grab');
d3.geoInertiaDrag(
sel,
function() { c.render(); }, /* allow overloading map.render */
c.projection
);
invalidation.then(() => sel.on(".drag", null));
}

/* not ready
if (opts.zoom) {
d3.select(c).call(zoom)
}
*/
return c;
}
Insert cell
Insert cell
function mapcanvas(projection, c, opts) {

const context = c.getContext("2d");
var angle = projection.angle();
//FROM AIROCEAN
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();
//projection.fitExtent([[2,2],[width-2, height-2]], {type:"Sphere"});

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();
// Polyhedral projections expose their structure as projection.tree()
// 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;
}
Insert cell
Insert cell
Insert cell
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