This Faux 3D Shaded Globe example has a faux 3D spherical globe projected onto 2D space and it allows users to rotate the globe about the origin. The globe has individual countries with labels for cities of significant size. This is a rather interesting example in that the visualization contains path elements and text elements both of which get updated if users rotate the globe. The VisDock toolkit has been integrated into this Faux 3D Shaded Globe example built with D3.js (found here) by Derek Watkins. For more information about VisDock, please cick on the link.
Last active
October 26, 2015 18:54
-
-
Save VisDockHub/9082845 to your computer and use it in GitHub Desktop.
Faux 3D Shaded Globe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| .land { | |
| fill: rgb(117, 87, 57); | |
| stroke-opacity: 1; | |
| } | |
| .countries path { | |
| stroke: rgb(80, 64, 39); | |
| stroke-linejoin: round; | |
| stroke-width:.5; | |
| fill: rgb(117, 87, 57); | |
| opacity: .1; | |
| } | |
| .countries path:hover { | |
| fill-opacity:.1; | |
| stroke-width:1; | |
| opacity: 1; | |
| } | |
| .graticule { | |
| fill: none; | |
| stroke: black; | |
| stroke-width:.5; | |
| opacity:.2; | |
| } | |
| .labels { | |
| font: 8px sans-serif; | |
| fill: black; | |
| opacity: .5; | |
| } | |
| .noclicks { | |
| pointer-events:none; | |
| } | |
| .point{ | |
| opacity:.6; | |
| } | |
| </style> | |
| <body> | |
| <link href="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.css" rel="stylesheet" type="text/css"/> | |
| <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 src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/2D.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/IntersectionUtilities.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.utils.js"></script> | |
| <script> | |
| // Lots of code from: | |
| // http://bl.ocks.org/3757125 | |
| // http://bl.ocks.org/3795040 | |
| d3.select(window) | |
| .on("mousemove", mousemove) | |
| .on("mouseup", mouseup); | |
| var width = 960, | |
| height = 500; | |
| VisDock.init("body", {width: 960, height: 700}); | |
| AnnotatedByData.layerTypes = [".country"] | |
| var viewport = VisDock.getViewport(); | |
| var proj = d3.geo.orthographic() | |
| .scale(220) | |
| .translate([width / 2, height / 2]) | |
| .clipAngle(90); | |
| var path = d3.geo.path().projection(proj).pointRadius(1.5); | |
| var graticule = d3.geo.graticule(); | |
| var svg = viewport; | |
| d3.selectAll('svg') | |
| .on("mousedown", mousedown); | |
| queue() | |
| .defer(d3.json, "/VisDockHub/raw/9082845/world-110m.json") | |
| .defer(d3.json, "places.json") | |
| .await(ready); | |
| function ready(error, world, places) { | |
| VisDock.startChrome(); | |
| var ocean_fill = svg.append("defs").append("radialGradient") | |
| .attr("id", "ocean_fill") | |
| .attr("cx", "75%") | |
| .attr("cy", "25%"); | |
| ocean_fill.append("stop").attr("offset", "5%").attr("stop-color", "#ddf"); | |
| ocean_fill.append("stop").attr("offset", "100%").attr("stop-color", "#9ab"); | |
| var globe_highlight = svg.append("defs").append("radialGradient") | |
| .attr("id", "globe_highlight") | |
| .attr("cx", "75%") | |
| .attr("cy", "25%"); | |
| globe_highlight.append("stop") | |
| .attr("offset", "5%").attr("stop-color", "#ffd") | |
| .attr("stop-opacity","0.6"); | |
| globe_highlight.append("stop") | |
| .attr("offset", "100%").attr("stop-color", "#ba9") | |
| .attr("stop-opacity","0.2"); | |
| 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", "#9ab") | |
| .attr("stop-opacity","0") | |
| globe_shading.append("stop") | |
| .attr("offset","100%").attr("stop-color", "#3e6184") | |
| .attr("stop-opacity","0.3") | |
| var drop_shadow = svg.append("defs").append("radialGradient") | |
| .attr("id", "drop_shadow") | |
| .attr("cx", "50%") | |
| .attr("cy", "50%"); | |
| drop_shadow.append("stop") | |
| .attr("offset","20%").attr("stop-color", "#000") | |
| .attr("stop-opacity",".5") | |
| drop_shadow.append("stop") | |
| .attr("offset","100%").attr("stop-color", "#000") | |
| .attr("stop-opacity","0") | |
| svg.append("ellipse") | |
| .attr("cx", 440).attr("cy", 450) | |
| .attr("rx", proj.scale()*.90) | |
| .attr("ry", proj.scale()*.25) | |
| .attr("class", "noclicks") | |
| .style("fill", "url(#drop_shadow)"); | |
| svg.append("circle") | |
| .attr("cx", width / 2).attr("cy", height / 2) | |
| .attr("r", proj.scale()) | |
| .attr("class", "noclicks") | |
| .style("fill", "url(#ocean_fill)"); | |
| svg.append("path") | |
| .datum(topojson.object(world, world.objects.land)) | |
| .attr("class", "land") | |
| .attr("d", path); | |
| svg.append("path") | |
| .datum(graticule) | |
| .attr("class", "graticule noclicks") | |
| .attr("d", path); | |
| svg.append("circle") | |
| .attr("cx", width / 2).attr("cy", height / 2) | |
| .attr("r", proj.scale()) | |
| .attr("class","noclicks") | |
| .style("fill", "url(#globe_highlight)"); | |
| svg.append("circle") | |
| .attr("cx", width / 2).attr("cy", height / 2) | |
| .attr("r", proj.scale()) | |
| .attr("class","noclicks") | |
| .style("fill", "url(#globe_shading)"); | |
| svg.append("g").attr("class","points") | |
| .selectAll("text").data(places.features) | |
| .enter().append("path") | |
| .attr("class", "point") | |
| .attr("d", path); | |
| svg.append("g").attr("class","labels") | |
| .selectAll("text").data(places.features) | |
| .enter().append("text") | |
| .attr("class", "label") | |
| .text(function(d) { return d.properties.name }) | |
| var id = 0 | |
| var country = svg.selectAll(".countries") | |
| .data(topojson.object(world, world.objects.countries).geometries) | |
| .enter().append("g") | |
| .attr("class", "countries") | |
| country.append("path") | |
| .attr("class", "country") | |
| .attr("d", path); | |
| position_labels(); | |
| VisDock.finishChrome(); | |
| } | |
| function position_labels() { | |
| VisDock.startChrome(); | |
| var centerPos = proj.invert([width/2,height/2]); | |
| var arc = d3.geo.greatArc(); | |
| svg.selectAll(".label") | |
| .attr("text-anchor",function(d) { | |
| var x = proj(d.geometry.coordinates)[0]; | |
| return x < width/2-20 ? "end" : | |
| x < width/2+20 ? "middle" : | |
| "start" | |
| }) | |
| .attr("transform", function(d) { | |
| var loc = proj(d.geometry.coordinates), | |
| x = loc[0], | |
| y = loc[1]; | |
| var offset = x < width/2 ? -5 : 5; | |
| return "translate(" + (x+offset) + "," + (y-2) + ")" | |
| }) | |
| .style("display",function(d) { | |
| var d = arc.distance({source: d.geometry.coordinates, target: centerPos}); | |
| return (d > 1.57) ? 'none' : 'inline'; | |
| }) | |
| VisDock.finishChrome(); | |
| } | |
| // modified from http://bl.ocks.org/1392560 | |
| var m0, o0; | |
| function mousedown() { | |
| if (viewport.attr("pointer-events") != "none"){ | |
| VisDock.startChrome(); | |
| m0 = [d3.event.pageX, d3.event.pageY]; | |
| o0 = proj.rotate(); | |
| d3.event.preventDefault(); | |
| VisDock.finishChrome(); | |
| } | |
| } | |
| 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] > 30 ? 30 : | |
| o1[1] < -30 ? -30 : | |
| o1[1]; | |
| proj.rotate(o1); | |
| refresh(); | |
| } | |
| } | |
| function mouseup() { | |
| if (m0) { | |
| mousemove(); | |
| m0 = null; | |
| } | |
| } | |
| function refresh() { | |
| VisDock.startChrome(); | |
| svg.selectAll(".land").attr("d", path); | |
| svg.selectAll(".countries path").attr("d", path); | |
| svg.selectAll(".graticule").attr("d", path); | |
| svg.selectAll(".point").attr("d", path); | |
| position_labels(); | |
| AnnotatedByData.update(); | |
| VisDock.finishChrome(); | |
| } | |
| VisDock.eventHandler = { | |
| getHitsPolygon : function(points, inclusive) { | |
| var shapebound = new createPolygon(points); | |
| return shapebound.intersectPath(d3.selectAll(".country")[0], inclusive) | |
| }, | |
| getHitsLine : function(points, inclusive) { | |
| var shapebound = new createLine(points); | |
| return shapebound.intersectPath(d3.selectAll(".country")[0], inclusive) | |
| }, | |
| getHitsEllipse : function(points, inclusive) { | |
| var shapebound = new createEllipse(points); | |
| return shapebound.intersectPath(d3.selectAll(".country")[0], inclusive) | |
| }, | |
| setColor : function(hits) { | |
| QueryManager.layers[num - 1] = []; | |
| for (var i = 0; i < hits.length; i++) { | |
| var str = hits[i].getAttributeNS(null, "transform"); | |
| var d = hits[i].getAttributeNS(null, "d") | |
| QueryManager.layers[num - 1][i] = d3.select(hits[i].parentNode).append("path").attr("transform", str) | |
| .attr("d", d) | |
| .attr("style", "fill: "+VisDock.color[num - 1] +"; stroke: " + VisDock.color[num - 1] + "; opacity: 0.5; pointer-events: none") | |
| .attr("class", "VisDockPathLayer") | |
| } | |
| }, | |
| changeColor : function(color, query, index) { | |
| var vis = VisDock.utils.getQueryVisibility(index); | |
| for (var i = 0; i < query.length; i++) { | |
| query[i][0][0].setAttributeNS(null, "style", "stroke: " + color + "; fill:none; opacity: " + vis) | |
| } | |
| }, | |
| changeVisibility : function(vis, query, index) { | |
| var color = VisDock.utils.getQueryColor(index); | |
| for (var i = 0; i < query.length; i++) { | |
| query[i][0][0].setAttributeNS(null, "style", "fill: " + color + "; opacity: " + vis) | |
| } | |
| }, | |
| removeColor : function(hits, index) { | |
| for (var i = 0; i < hits.length; i++) { | |
| hits[i].remove(); | |
| } | |
| }, | |
| QueryClick : function(query, index) { | |
| } | |
| } | |
| //Panel.x = 75; | |
| //Panel.y = 100; | |
| //Panel.setTransform(); | |
| BirdView.init(viewport, 960, 700) | |
| d3.select(self.frameElement).style("width", "960px") | |
| d3.select(self.frameElement).style("height", "700px") | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment