Emulating Luis Sevillano's QGIS/Illustrator-produced globes with D3 and Canvas.
It uses a Canvas radial gradient to get the 'atmosphere' effect.
license: mit | |
border: none |
Emulating Luis Sevillano's QGIS/Illustrator-produced globes with D3 and Canvas.
It uses a Canvas radial gradient to get the 'atmosphere' effect.
<!DOCTYPE html> | |
<meta charset="utf-8" /> | |
<body> | |
<link href='https://fonts.googleapis.com/css?family=Roboto:400,400italic' rel='stylesheet' type='text/css'> | |
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script src="https://d3js.org/topojson.v1.min.js"></script> | |
<script src="https://unpkg.com/rbush@1.4.3/rbush.js"></script> | |
<script src="https://unpkg.com/spamjs@1.1.0/spam.min.js"></script> | |
<script type='text/javascript'> | |
var graticule = d3.geo.graticule(); | |
// Canvas radial gradient | |
var x = 960 / 2, | |
y = 500 / 2, | |
// Radii of the start glow. | |
innerRadius = 60, | |
// Radii of the end glow. | |
outerRadius = 480, | |
// Radius of the entire circle. | |
radius = 480; | |
// Canvas doesn't support letter spacing :___) | |
// https://www.cs.tut.fi/~jkorpela/chars/spaces.html | |
var circles = [ | |
{ name: "S W I T Z E R L A N D", coordinates: [8.424757, 46.94344] } | |
]; | |
// SIX-PER-EM SPACE | |
var continents = [ | |
{ name: "A M E R I C A", coordinates: [-80.262723, 40.26839] }, | |
{ name: "A F R I C A", coordinates: [5.889621, 5.409892] }, | |
{ name: "A S I A", coordinates: [80.041964, 35.059898] } | |
]; | |
// THIN spaces | |
var oceans = [ | |
{ name: "A T L A N T I C", coordinates: [-38.934598, 22.964389] }, | |
{ name: "O C E A N", coordinates: [-36.571317, 16.993163] } | |
]; | |
d3.json("world.json", function(error, d) { | |
topojson.presimplify(d); | |
var map = new StaticCanvasMap({ | |
element: "body", | |
width: 960, | |
height: 500, | |
projection: d3.geo | |
.orthographic() | |
.clipAngle(90) | |
.precision(0.1) | |
.scale(240) | |
.rotate([0, -45, 0]), | |
data: [ | |
{ | |
features: topojson.feature(d, d.objects["countries"]), | |
static: { | |
prepaint: function(parameters) { | |
parameters.context.beginPath(); | |
parameters.path({ type: "Sphere" }); | |
parameters.context.lineWidth = 2; | |
parameters.context.strokeStyle = "rgb(198, 197, 197)"; | |
parameters.context.stroke(); | |
var gradient = parameters.context.createRadialGradient( | |
x, | |
y, | |
innerRadius, | |
x, | |
y, | |
outerRadius | |
); | |
gradient.addColorStop(0, "rgb(230, 239, 239)"); | |
gradient.addColorStop(1, "rgb(200, 200, 200)"); | |
parameters.context.fillStyle = gradient; | |
parameters.context.fill(); | |
parameters.context.beginPath(); | |
parameters.path(graticule()); | |
parameters.context.lineWidth = 0.2; | |
parameters.context.strokeStyle = "rgba(30,30,30, 0.1)"; | |
parameters.context.stroke(); | |
}, | |
paintfeature: function(parameters, d) { | |
parameters.context.lineWidth = 0.5 / parameters.scale; | |
parameters.context.strokeStyle = "rgba(0,0,0, 0.3)"; | |
parameters.context.stroke(); | |
if (d.properties.sovereignt === "Switzerland") { | |
parameters.context.fillStyle = "orange"; | |
} else { | |
parameters.context.fillStyle = "#f1ede6"; | |
} | |
parameters.context.fill(); | |
}, | |
postpaint: function(parameters) { | |
for (var i in circles) { | |
parameters.context.beginPath(); | |
parameters.context.textAlign = "center"; | |
var circle = circles[i]; | |
var projectedPoint = parameters.map | |
.settings() | |
.projection(circle.coordinates); | |
parameters.context.arc( | |
projectedPoint[0], | |
projectedPoint[1] / parameters.scale, | |
10 / parameters.scale, | |
0, | |
2 * Math.PI, | |
true | |
); | |
parameters.context.font = "18px Roboto"; | |
parameters.context.fillStyle = "rgba(70, 70, 70, 0.8)"; | |
parameters.context.fillText( | |
circle.name, | |
projectedPoint[0], | |
projectedPoint[1] - 15 | |
); | |
parameters.context.strokeStyle = "rgb(126, 120, 117)"; | |
parameters.context.lineWidth = 1.5 / parameters.scale; | |
parameters.context.stroke(); | |
} | |
for (var i in continents) { | |
parameters.context.beginPath(); | |
parameters.context.textAlign = "center"; | |
var continent = continents[i]; | |
var projectedPoint = parameters.map | |
.settings() | |
.projection(continent.coordinates); | |
parameters.context.font = "16px Roboto"; | |
parameters.context.fillStyle = "rgba(155, 155, 155, 1)"; | |
parameters.context.fillText( | |
continent.name, | |
projectedPoint[0], | |
projectedPoint[1] - 15 | |
); | |
parameters.context.stroke(); | |
} | |
for (var i in oceans) { | |
parameters.context.beginPath(); | |
parameters.context.textAlign = "center"; | |
var ocean = oceans[i]; | |
var projectedPoint = parameters.map | |
.settings() | |
.projection(ocean.coordinates); | |
parameters.context.font = "italic 16px Roboto"; | |
parameters.context.fillStyle = "rgba(122, 148, 149, 0.8)"; | |
parameters.context.fillText( | |
ocean.name, | |
projectedPoint[0], | |
projectedPoint[1] - 15 | |
); | |
parameters.context.stroke(); | |
} | |
} | |
} | |
} | |
] | |
}); | |
map.init(); | |
}); | |
</script> |