Skip to content

Instantly share code, notes, and snippets.

@jthomassie
Last active August 29, 2015 13:56
Show Gist options
  • Save jthomassie/9223158 to your computer and use it in GitHub Desktop.
Save jthomassie/9223158 to your computer and use it in GitHub Desktop.
World map - orthographic
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.water {
fill: #ddd;
}
.graticule {
fill: none;
stroke: #444;
stroke-width: 0.6;
stroke-opacity: 0.4;
}
.land {
fill: #444;
fill-opacity: 0.6;
stroke: #444;
stroke-opacity: 0.7;
stroke-width: 1.5;
}
.countries path {
fill: #c6b27b;
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: #700000;
opacity: 0.8;
}
.noclick {
pointer-events:none;
}
</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>
var width = 960,
height = 500;
var projection = d3.geo.orthographic()
.scale(245)
.translate([width/2, height/2])
.precision(0.1)
.rotate([52.8, -49.6])
.clipAngle(90);
// scales for fading/sizing labels/points
var opacityScale = d3.scale.linear()
.domain([200, 150])
.range([1,0]);
var ptSizeScale = d3.scale.linear()
.domain([500, 150])
.range([12,7]);
var path = d3.geo.path().projection(projection).pointRadius(2);
var graticule = d3.geo.graticule();
d3.select(window)
.on("mousemove", mouseMove)
.on("mouseup", mouseUp);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.on("mousedown", mouseDown)
.call(d3.behavior.zoom()
.translate(projection.translate())
.scale(projection.scale())
.scaleExtent([50,500])
.on("zoom", function() {
reZoom();
})
);
// queue for loading topojson and places data
queue()
.defer(d3.json, "world-110m.json")
.defer(d3.json, "world-places.json")
.await(ready);
function ready(error, world, places) {
// shading def
var globe_shading = svg.append("defs")
.append("radialGradient")
.attr("id", "globe_shading")
.attr("cx", "50%")
.attr("cy", "40%");
globe_shading.append("stop")
.attr("offset","50%")
.attr("stop-color", "#fff")
.attr("stop-opacity","0.2");
globe_shading.append("stop")
.attr("offset","100%")
.attr("stop-color", "#253d56")
.attr("stop-opacity","0.4");
// water sphere
svg.append("path")
.datum({type: "Sphere"})
.attr("class", "water noclick")
.attr("d", path);
// 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 noclick")
.attr("d", path);
// shading sphere
svg.append("path")
.datum({type: "Sphere"})
.attr("class","noclick")
.style("fill", "url(#globe_shading)");
// country shapes
svg.append("g").attr("class", "countries")
.selectAll("path")
.data(topojson.object(world, world.objects.countries).geometries)
.enter().append("path")
.attr("class", "countries")
.attr("d", path)
.on("mouseover", function(d) {
console.log("country id: " + d.id);
});
// place points
svg.append("g").attr("class","points noclick")
.selectAll("text")
.data(places.features)
.enter().append("path")
.attr("class", "point")
.attr("d", path);
// place labels
svg.append("g").attr("class","labels noclick")
.selectAll("text")
.data(places.features)
.enter().append("text")
.attr("class", "label")
.text(function(d) {
return d.properties.name;
});
reDraw();
}
function positionLabels() {
var centerPos = projection.invert([width/2,height/2]);
var arc = d3.geo.greatArc();
var s = projection.scale();
// labels
svg.selectAll(".label")
.attr("text-anchor",function(d) {
var x = projection(d.geometry.coordinates)[0];
if (x < (width/2) - 20) {
return "end";
} else if (x < (width/2) + 20) {
return "middle";
} else {
return "start";
}
})
.attr("transform", function(d) {
var loc = projection(d.geometry.coordinates),
x = loc[0],
y = loc[1],
xoffset = 6,
yoffset = -3;
if (x < width/2) {
xoffset = -6;
}
if (x < (width/2) - 20) {
yoffset = -1;
} else if (x < (width/2) + 20) {
yoffset = -6;
} else {
yoffset = -1;
}
return "translate(" + (x + xoffset) + "," + (y + yoffset) + ")";
})
.style("opacity", function() {
return opacityScale(s);
})
.style("font-size", function() {
return ptSizeScale(s);
})
.style("display",function(d) {
var dist = arc.distance({source: d.geometry.coordinates, target: centerPos});
if (dist > 1.57) {
return 'none';
} else {
return 'inline';
}
});
// points
svg.selectAll(".point")
.style("opacity", function() {
return opacityScale(s);
});
}
function reDraw() {
svg.selectAll("path").attr("d", path);
positionLabels();
// console.log("Map center: ", -projection.rotate()[1], -projection.rotate()[0]);
}
function reZoom() {
if (d3.event) { projection.scale(d3.event.scale); }
svg.selectAll("*").attr("d", path);
positionLabels();
// console.log("Map scale: ", d3.event.scale);
}
// window mousemove
function mouseMove() {
if (m0) {
// limit vertical rotation between 55 & -55
var m1 = [d3.event.pageX, d3.event.pageY],
o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6];
if (o1[1] > 55) {
o1[1] = 55;
}
if (o1[1] < -55) {
o1[1] = -55;
}
projection.rotate(o1);
reDraw();
}
}
// window mouseup
function mouseUp() {
if (m0) {
mouseMove();
m0 = null;
}
}
// svg mousedown
var m0, o0;
function mouseDown() {
m0 = [d3.event.pageX, d3.event.pageY];
o0 = projection.rotate();
d3.event.preventDefault();
}
</script>
</body>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
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