Skip to content

Instantly share code, notes, and snippets.

@asika32764
Forked from jthomassie/arc-places.json
Created June 13, 2023 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asika32764/cc0c45108891a1e86a19b48fc550ae88 to your computer and use it in GitHub Desktop.
Save asika32764/cc0c45108891a1e86a19b48fc550ae88 to your computer and use it in GitHub Desktop.
d3 globe arcs
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.graticule {
fill: none;
stroke: #ccc;
stroke-width: 0.7;
stroke-opacity: 1.0;
}
.edge {
fill: none;
stroke: #444;
stroke-width: 0.8;
stroke-opacity: 1.0;
}
.land {
fill: #ccc;
fill-opacity: 0.6;
stroke: #999;
stroke-opacity: 1.0;
stroke-width: 1.0;
}
.countries path {
fill: #ddd;
fill-opacity: 0.4;
stroke: #444;
stroke-linejoin: round;
stroke-width: 0.4;
stroke-opacity: 0.2;
}
.countries path:hover {
fill-opacity: 0.6;
stroke-width: 1.1;
stroke-opacity: 0.5;
}
.labels {
font: 12px sans-serif;
fill: #444;
}
.point{
fill: #444;
stroke: #444;
stroke-width: 1;
stroke-opacity: 1;
}
.noclick {
pointer-events:none;
}
.arcs {
opacity:.1;
stroke: gray;
stroke-width: 3;
}
.flyers {
stroke-width:1;
opacity: .6;
stroke: darkred;
}
.arc, .flyer {
stroke-linejoin: round;
fill:none;
}
.arc { }
.flyer { }
.flyer:hover { }
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
var width = 960,
height = 500;
var center = [50.0, -40.0];
var proj = d3.geo.orthographic()
.translate([width / 2, height / 2])
.scale(220)
.precision(0.3)
.rotate(center)
.clipAngle(90);
var sky = d3.geo.orthographic()
.translate([width / 2, height / 2])
.clipAngle(90)
.scale(280);
var path = d3.geo.path().projection(proj).pointRadius(2);
var graticule = d3.geo.graticule();
var swoosh = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; })
.interpolate("basis");
var links = [],
arcLines = [];
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.on("mousedown", mousedown);
queue()
.defer(d3.json, "world-110m.json")
.defer(d3.json, "arc-places.json")
.await(ready);
function ready(error, world, places) {
var ocean_fill = svg.append("defs").append("radialGradient")
.attr("id", "ocean_fill")
.attr("cx", "75%")
.attr("cy", "25%");
// water sphere
svg.append("path")
.datum({type: "Sphere"})
.attr("class", "water noclick")
.attr("d", path)
.style("fill", "#fff");
// graticule
svg.append("path")
.datum(graticule)
.attr("class", "graticule noclick")
.attr("d", path);
// land shape
svg.append("path")
.datum(topojson.object(world, world.objects.land))
.attr("class", "land noclicks")
.attr("d", path);
// edge sphere
svg.append("path")
.datum({type: "Sphere"})
.attr("class", "edge noclick")
.attr("d", path);
svg.append("g")
.attr("class","points")
.selectAll("text").data(places.features)
.enter().append("path")
.attr("class", "point")
.attr("d", path);
// spawn links between cities as source/target coord pairs
places.features.forEach(function(a) {
places.features.forEach(function(b) {
if (a !== b) {
links.push({
source: a.geometry.coordinates,
target: b.geometry.coordinates
});
}
});
});
// build geoJSON features from links array
links.forEach(function(e,i,a) {
var feature = { "type": "Feature", "geometry": { "type": "LineString", "coordinates": [e.source,e.target] }};
arcLines.push(feature);
});
svg.append("g").attr("class","arcs")
.selectAll("path").data(arcLines)
.enter().append("path")
.attr("class","arc")
.attr("d",path);
svg.append("g").attr("class","flyers")
.selectAll("path").data(links)
.enter().append("path")
.attr("class","flyer")
.attr("d", function(d) {
// return swoosh(flying_arc(d));
var ddd = "M";
var pts = flying_arc(d);
for (var i = 0; i < pts.length; i++ ) {
if(i == 1) {
ddd += "C";
}
ddd += pts[i][0];
ddd += ",";
ddd += pts[i][1];
if(i < pts.length-1) {
ddd += " ";
}
}
//console.log(ddd);
return ddd;
});
proj.rotate(center);
sky.rotate(center);
refresh();
}
function flying_arc(pts) {
var source = pts.source,
target = pts.target;
var mid = location_along_arc(source, target, 0.35);
var mid2 = location_along_arc(source, target, 0.65);
var result = [
proj(source),
sky(mid),
sky(mid2),
proj(target)
];
//console.log(proj(source));
return result;
}
function refresh() {
svg.selectAll(".land").attr("d", path);
svg.selectAll(".point").attr("d", path);
svg.selectAll("path").attr("d", path);
svg.selectAll(".arc")
.attr("d", path)
.attr("opacity", function(d) {
return fade_at_edge(d);
});
svg.selectAll(".flyer")
.attr("d", function(d) {
return swoosh(flying_arc(d));
})
.attr("opacity", function(d) {
return fade_at_edge(d);
});
}
function fade_at_edge(d) {
var centerPos = proj.invert([width/2,height/2]),
arc = d3.geo.greatArc(),
start, end;
// function is called on 2 different data structures..
if (d.source) {
start = d.source,
end = d.target;
} else {
start = d.geometry.coordinates[0];
end = d.geometry.coordinates[1];
}
var start_dist = 1.57 - arc.distance({source: start, target: centerPos}),
end_dist = 1.57 - arc.distance({source: end, target: centerPos});
var fade = d3.scale.linear().domain([-0.1, 0]).range([0, 0.1]) ;
var dist = start_dist < end_dist ? start_dist : end_dist;
return fade(dist);
}
function location_along_arc(start, end, loc) {
var interpolator = d3.geo.interpolate(start,end);
return interpolator(loc);
}
// modified from http://bl.ocks.org/1392560
var m0, o0;
function mousedown() {
m0 = [d3.event.pageX, d3.event.pageY];
o0 = proj.rotate();
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = [d3.event.pageX, d3.event.pageY]
, o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6];
o1[1] = o1[1] > 55 ? 55 :
o1[1] < -55 ? -55 :
o1[1];
console.log(o1);
proj.rotate(o1);
sky.rotate(o1);
refresh();
}
}
function mouseup() {
if (m0) {
mousemove();
m0 = null;
}
}
</script>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment