Public
Edited
Sep 23, 2023
Fork of Base map
1 fork
Insert cell
Insert cell
Insert cell
map(d3.geoOrthographic(), {
svg: true,
height: 150,
show_equator: true,
//width: 200,
rotate: [0, -90],
inertia: true
})
Insert cell
EXAMPLE = map(d3.geoOrthographic(), {
//svg: true,
rotate: [0, -90],
inertia: true,
show_equator: true,
show_structure: true,
background: "white"
})
Insert cell
EXAMPLE2 = map(d3.geoAirocean(), {
show_equator: true,
show_structure: true,
background: "white"
})
Insert cell
Insert cell
Insert cell
mapsvg = function(projection, c, opts) {
const svg = d3.select(c);
const path = d3.geoPath(projection);

if (opts.clip) {
var defs = svg.append("defs");
defs
.append("path")
.datum(opts.clip)
.attr("id", "clipOpt")
.attr("d", path);
defs
.append("clipPath")
.attr("id", "clip")
.append("use")
.attr("xlink:href", "#clipOpt");
}

svg
.append("path")
.datum({ type: "Sphere" })
.attr("stroke", "black")
.attr("fill", "#fefef2");

svg
.append("path")
.datum(graticule)
.attr("stroke", "black")
.attr("stroke-width", 0.2)
.attr("fill", "none");

var l = land.features
? land
: {
type: "FeatureCollection",
features: land
};

svg
.append("g")
.selectAll("path")
.data(l.features)
.enter()
.append("path")
.attr("id", d => d.properties.name)
.attr("fill", "black");

function render() {
svg
.selectAll("path")
.attr("d", path)
.attr("clip-path", "url(#clip)");
}

c.path = path;
(c.render = render)();

return c;
}
Insert cell
width
Insert cell
function mapcanvas(
projection,
c,
{
background = "#fefef2",
clip = false,
keepcanvas = false,
show_structure = false,
show_sphere = true,
show_equator = false,
show_land = true,
fill = () => "black",
...opts
} = {}
) {
const context = c.getContext("2d");

var path = d3.geoPath(projection, context);

if (clip) context.beginPath(), path(clip), context.clip();

function render() {
if (!keepcanvas) context.clearRect(0, 0, c.width, c.height);
if (show_sphere) {
context.beginPath();
path({ type: "Sphere" });
if (background) {
context.fillStyle = background;
context.fill();
}

context.beginPath(),
path(graticule),
(context.strokeStyle = "#ccc"),
context.stroke();
}
if (show_land) {
var l = land.features ? land.features : [land];
l.forEach((f, i) => {
context.beginPath(),
path(f),
(context.fillStyle = fill(f, i)),
context.fill();
});
}
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_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 (event) {
var gni = projection.invert(d3.pointer(event, this));
context.beginPath(),
path.pointRadius(2)({ type: "Point", coordinates: gni }),
(context.fillStyle = "green"),
(context.strokeStyle = "black"),
context.fill(),
context.stroke();
});
}

context.canvas.path = path;
(context.canvas.render = render)();

return context.canvas;
}
Insert cell
d3 = require("d3-selection@3", "d3-geo@3", "d3-fetch@3", "d3-geo-projection@4", "d3-geo-polygon@1.8", "d3-inertia@0.4")
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