globe = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("class", "globe");
var path = d3.geoPath()
.projection(projectionOrthographic);
var linearGradient = svg.append("defs").append("linearGradient")
.attr("id", "mygrad")
.attr("x1", "0%")
.attr("x2", "50%")
.attr("y1", "0%")
.attr("y2", "100%");
linearGradient.append("stop")
.attr("offset", "0%")
.style("stop-color", linear_gradient_colors[0])
.style("stop-opacity", 1)
linearGradient.append("stop")
.attr("offset", "100%")
.style("stop-color", linear_gradient_colors[1])
.style("stop-opacity", 1)
var globe_bg = svg.append("rect")
.attr("rx",1200)
.attr("ry",1200)
.attr("x", (width/2) - projectionOrthographic.scale())
.attr("y", (height/2) - projectionOrthographic.scale())
.attr("width", projectionOrthographic.scale()*2)
.attr("height", projectionOrthographic.scale()*2)
.style("fill", "url(#mygrad)")
.attr("class", "globe-bg");
// make dictionary of country to cumulative value
// This is done for convenience access to cumulative value
var world_covid_dict_csv = {};
world_covid_csv.map((e,i) => { world_covid_dict_csv[e.country]=e.cumulative});
/**
// uncomment to add graticule to Orthographic projection
var graticule = d3.geoGraticule().step([20, 20]);
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", path)
.style("fill", "#fff")
.style("stroke", "#ccc");
**/
// add paths of the world map to svg
svg.selectAll(".country")
.data(countries.filter(function(d){return d.properties.name != "Antarctica";}))
.enter().append("path")
.attr('stroke-linejoin', 'round')
.style("fill", function(d) {
if (world_covid_dict_csv[d.properties.name.split(' ').join('_')] != undefined){
return colorScale(world_covid_dict_csv[d.properties.name.split(' ').join('_')]);
}
else {
return "white"
}
})
.attr("class", "country")
.style("stroke", "orange")
.style("stroke-width", "0.3px")
.attr("d", path);
// add legend to svg
svg.append("g")
.attr("class", "legend_auto")
.style('font-size', 12)
.style('font-family', 'sans-serif')
.attr("transform", `translate(10,${height-120})`)
.call(legend_svg)
svg.selectAll('.label')
.attr("transform", "translate(20, 13)")
var timer;
var isOrthographic = true;
svg.append("text")
.attr("x", width/2)
.attr("y", 50)
.text("CHANGE PROJECTION TO MERCATOR")
.attr("text-anchor", "middle")
.style("font-family", "sans-serif")
.on("mouseover", function() { d3.select(this).style("text-decoration", "underline") })
.on("mouseout", function() { d3.select(this).style("text-decoration", "none") })
.on("click", function() {
d3.select(this)
.text(isOrthographic ?
"CHANGE PROJECTION TO MERCATOR" : "CHANGE PROJECTION TO ORTHOGRAPHIC")
.attr("fill", "black");
if (isOrthographic == false){
svg.select('.legendTitle')
.attr("fill", "black");
svg.selectAll('.label')
.attr("fill", "black");
transition_projection("orthographic");
}
else{
timer.stop();
transition_projection("mercator");
d3.select(this)
.attr("fill", "white");
svg.select('.legendTitle')
.attr("fill", "white");
svg.selectAll('.label')
.attr("fill", "white");
}
isOrthographic = !isOrthographic;
})
// enable rotation
enableRotation();
function enableRotation() {
if (isOrthographic == true){
transition_projection("orthographic");
timer = d3.timer(timerFunc);
}
else {
timer.stop();
projectionOrthographic.rotate();
svg.selectAll("path").attr("d", path);
transition_projection("mercator");
}
}
// function that rotates the projection
function timerFunc(elapsed) {
if (isOrthographic){
mutable elapsedTime = (config.speed * elapsed) % 360;
projectionOrthographic.rotate([(config.speed * elapsed)%360, config.verticalTilt, config.horizontalTilt]);
svg.selectAll("path").attr("d", path);
}
}
function transition_projection(projectionToTransition){
if (projectionToTransition == "mercator"){
projectionOrthographic.rotate([360, config.verticalTilt, config.horizontalTilt]);
// first transition = rotate (reset) orthographic projection to its default position
// why do this: the rotation of the Orthographic projection affects the position (coordinate position // [x,y]) of the Mercator projection
// you can comment out the first transition and .attr("d", path) too see what I'm saying
var first_transition = d3.transition()
.duration(500)
.ease(d3.easeLinear);
var second_transition = d3.transition()
.duration(500)
.ease(d3.easeCubicInOut);
svg.selectAll("path")
.transition(first_transition)
.attr("d", path)
.transition(second_transition)
.attrTween("d", projectionTween(projectionOrthographic, projectionMercator));
svg.select(".globe-bg")
.transition(second_transition)
.delay(500)
.attr("rx",0)
.attr("ry",0)
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
}
else
{
svg.selectAll("path").transition("mercator-to-ortho")
.duration(1000).ease(d3.easeCubicInOut)
.attrTween("d", projectionTween(projectionMercator, projectionOrthographic));
svg.select(".globe-bg")
.transition("mercator-to-ortho")
.duration(750)
.ease(d3.easeCubicInOut)
.attr("rx",200)
.attr("ry",200)
.attr("x", (width/2) - projectionOrthographic.scale())
.attr("y", (height/2) - projectionOrthographic.scale())
.attr("width",projectionOrthographic.scale()*2)
.attr("height",projectionOrthographic.scale()*2)
.style("fill", "url(#mygrad)")
.on("end", timerRestart);
}
}
function timerRestart(){
timer.restart(timerFunc);
}
yield svg.node();
}