function globe(attitude, options = {}) {
const margin = 10;
const width = 400;
const height = 400;
const context = DOM.context2d(width, height);
const extent = [
[margin, margin],
[height - margin, width - margin]
];
const projection = d3
.geoOrthographic()
.fitExtent(extent, { type: "Sphere" })
.rotate(attitude.angles());
const path = d3.geoPath(projection, context);
const horizon = d3.geoCircle().center([lon, lat]).radius(90);
const sunPos = sun(new Date(), lat, lon);
function drawGlobe() {
context.strokeStyle = "#000";
context.fillStyle = "#ddd";
context.beginPath();
context.fillStyle = "#eee";
path(world);
context.fill();
context.beginPath();
context.strokeStyle = "#000";
context.lineWidth = 0.25;
path(d3.geoGraticule10());
context.stroke();
drawLocation();
drawSunPath();
context.beginPath();
context.strokeStyle = "#000";
path({ type: "Sphere" });
context.lineWidth = 1;
context.stroke();
}
function drawLocation() {
context.fillStyle = "red";
context.strokeStyle = "red";
context.lineWidth = 1;
context.beginPath();
path({ type: "Point", coordinates: [lon, lat] });
context.fill();
context.beginPath();
path(horizon());
context.stroke();
}
function drawSunPath() {
context.beginPath();
context.strokeStyle = "orange";
path({
type: "Polygon",
coordinates: [
todaySunPosition.map((d) => [
d.azimuth_deg + 180,
-1 * (90 - lat - d.altitude_deg)
])
]
});
context.stroke();
context.beginPath();
context.fillStyle = "orange";
path({
type: "Point",
coordinates: [
(sunPos.azimuth * 180) / Math.PI + 180,
-1 * (90 - lat - sunPos.altitude_deg)
]
});
context.fill();
}
function render() {
context.save();
context.clearRect(0, 0, width, height);
drawGlobe();
}
d3.select(context.canvas)
.style("cursor", "grab")
.call(
drag(projection, options)
.on("drag.render", render)
.on("end.render", render)
);
return d3.select(context.canvas).call(render).node();
}