$.getJSON( "https://spreadsheets.google.com/feeds/list/1p0NKYGkH2MHcqzd7olnTbmLEexZ8-Uz7pTaK--1mPvI/1/public/values?alt=json", function(data) { // process google sheet into geojson var devGeojson = { type: 'FeatureCollection', features: [] }; var devs = data.feed.entry; for (var i in devs) { if (devs[i].gsx$latitude.$t) { var feature = { type: 'Feature', properties: { title: '

' + devs[i].gsx$name.$t + '

', 'marker-color': '#227FBB', 'marker-size': 'large', 'marker-symbol': 'rocket', url: 'https://gisdevs.slack.com/team/' + devs[i].gsx$name.$t }, geometry: { type: 'Point', coordinates: [devs[i].gsx$longitude.$t, devs[i].gsx$latitude.$t] } }; devGeojson.features.push(feature); } } (function(w, d3, undefined) { "use strict"; var width, height; function getSize() { width = w.innerWidth, height = w.innerHeight; if (width === 0 || height === 0) { setTimeout(function() { getSize(); }, 100); } else { init(); } } function init() { //Setup path for outerspace var space = d3.geo.azimuthal() .mode("equidistant") .translate([width/2, height/2]); space .scale(space.scale() * 3); var spacePath = d3.geo.path() .projection(space) .pointRadius(1); //Setup path for globe var projection = d3.geo.azimuthal() .mode("orthographic") .translate([width/2, height/2]) .scale(300) .origin([-30,40]) var scale0 = projection.scale(); var path = d3.geo.path() .projection(projection) .pointRadius(2); //Setup path for devs var devPath = d3.geo.path() .projection(projection) .pointRadius(6); //Setup zoom behavior var zoom = d3.behavior .zoom(true) .translate(projection.origin()) .scale(projection.scale()) .scaleExtent([200, 800]) .on("zoom", move); var circle = d3.geo.greatCircle() .origin([-30,40]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .append("g") .call(zoom) .on("dblclick.zoom", null); //Create a list of random stars and add them to outerspace var starList = createStars(1000); var stars = svg.append("g") .selectAll("g") .data(starList) .enter() .append("path") .attr("class", "star") .attr("d", function(d) { spacePath.pointRadius(d.properties.radius); return spacePath(d); }); svg.append("rect") .attr("class", "frame") .attr("width", width) .attr("height", height); //Create the base globe var backgroundCircle = svg.append("circle") .attr('cx', width / 2) .attr('cy', height / 2) .attr('r', projection.scale()) .attr('class', 'globe') .attr("filter", "url(#glow)") .attr("fill", "url(#gradBlue)"); var countryG = svg.append("g"), devG = svg.append("g"), globeFeatures, devFeatures; //Add all of the countries to the globe d3.json("world-countries.json", function(collection) { globeFeatures = countryG.selectAll(".feature") .data(collection.features); globeFeatures.enter().append("path") .attr("class", "feature") .attr("d", function(d) { return path(circle.clip(d)); }); }); // add dev points to the globe //console.log(devGeojson.features); devFeatures = devG.selectAll(".dev") .data(devGeojson.features); devFeatures.enter() .append("path") .attr("class", "dev") .attr("d", function(d) { return devPath(circle.clip(d)); }); //Redraw all items with new projections function redraw() { globeFeatures.attr("d", function(d) { return path(circle.clip(d)); }); devFeatures.attr("d", function(d) { return devPath(circle.clip(d)); }); stars.attr("d", function(d) { spacePath.pointRadius(d.properties.radius); return spacePath(d); }); } function move() { if (d3.event) { var scale = d3.event.scale; var origin = [d3.event.translate[0] * -1, d3.event.translate[1]]; projection.scale(scale); space.scale(scale * 3); backgroundCircle.attr('r', scale); path.pointRadius(2 * scale / scale0); devPath.pointRadius(6 * scale / scale0); projection.origin(origin); circle.origin(origin); //globe and stars spin in the opposite direction because of the projection mode var spaceOrigin = [origin[0] * -1, origin[1] * -1]; space.origin(spaceOrigin); redraw(); } } function createStars(number) { var data = []; for (var i = 0; i < number; i++) { data.push({ geometry: { type: 'Point', coordinates: randomLonLat() }, type: 'Feature', properties: { radius: Math.random() * 1.5 } }); } return data; } function randomLonLat() { return [Math.random() * 360 - 180, Math.random() * 180 - 90]; } } getSize(); }(window, d3)); });