Skip to content

Instantly share code, notes, and snippets.

@JonathanGarro
Created June 30, 2023 19:37
Show Gist options
  • Save JonathanGarro/f5557c396c51515e128dc639024dd275 to your computer and use it in GitHub Desktop.
Save JonathanGarro/f5557c396c51515e128dc639024dd275 to your computer and use it in GitHub Desktop.
Spinning Globe with Points in D3.js
<svg viewBox="100 0 650 650" preserveAspectRatio="none"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script>
const width = 750;
const height = 750;
const config = {
speed: 0.01,
verticalTilt: -12,
horizontalTilt: 0
}
let locations = [];
const svg = d3.select('svg').attr('width', width).attr('height', height);
const markerGroup = svg.append('g');
const projection = d3.geoOrthographic();
const initialScale = projection.scale();
const path = d3.geoPath().projection(projection);
const center = [width/2, height/2];
drawGlobe();
drawGraticule();
enableRotation();
function drawGlobe() {
d3.queue()
.defer(d3.json, '/static/data/world-110m.json')
.defer(d3.json, '/static/data/locations.json')
.await((error, worldData, locationData) => {
svg.selectAll(".segment")
.data(topojson.feature(worldData, worldData.objects.countries).features)
.enter().append("path")
.attr("class", "segment")
.attr("d", path)
.style("stroke", "#888")
.style("stroke-width", "1px")
.style("fill", (d, i) => '#e5e5e5')
.style("opacity", ".6");
locations = locationData;
drawMarkers();
});
}
function drawGraticule() {
const graticule = d3.geoGraticule()
.step([10, 10]);
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path)
.style("fill", "#fff")
.style("stroke", "#ccc");
}
function enableRotation() {
d3.timer(function (elapsed) {
projection.rotate([config.speed * elapsed - 10, config.verticalTilt, config.horizontalTilt]);
svg.selectAll("path").attr("d", path);
drawMarkers();
});
}
function drawMarkers() {
const markers = markerGroup.selectAll('circle')
.data(locations);
markers
.enter()
.append('circle')
.merge(markers)
.attr('cx', d => projection([d.longitude, d.latitude])[0])
.attr('cy', d => projection([d.longitude, d.latitude])[1])
.attr('fill', d => {
const coordinate = [d.longitude, d.latitude];
gdistance = d3.geoDistance(coordinate, projection.invert(center));
return gdistance > 1.5 ? 'none' : 'red';
})
.attr('stroke', d => {
const coordinate = [d.longitude, d.latitude];
gdistance = d3.geoDistance(coordinate, projection.invert(center));
return gdistance > 1.5 ? 'none' : 'white';
})
.attr('r', 4);
markerGroup.each(function () {
this.parentNode.appendChild(this);
});
}
svg.append("circle").attr("cx",600).attr("cy",500).attr("r", 6).style("fill", "red")
svg.append("text").attr("x", 620).attr("y", 500).text("SIMS Member").style("font-size", "12px").attr("alignment-baseline","middle")
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment