|
<html xmlns="http://www.w3.org/1999/xhtml"> |
|
<head> |
|
<title>Satellite Projection Explorer</title> |
|
<meta charset="utf-8" /> |
|
</head> |
|
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> |
|
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script> |
|
<script src="http://d3js.org/queue.v1.min.js"></script> |
|
<script src="http://d3js.org/colorbrewer.v1.min.js"></script> |
|
<style> |
|
|
|
</style> |
|
<body onload="satelliteMap();"> |
|
<div id="controls"> |
|
</div> |
|
<div id="vizcontainer"> |
|
<svg style="width:500px;height:500px;border:1px lightgray solid;" /> |
|
<div style="position:absolute;top:30px;left:10px;" id="settings" /> |
|
</div> |
|
|
|
|
|
<footer> |
|
<script> |
|
function satelliteMap() { |
|
queue() |
|
.defer(d3.json, "world_g.json") |
|
.defer(d3.csv, "cities.csv") |
|
.await(function(error, file1, file2) { createMap(file1, file2); }); |
|
|
|
function createMap(countries, cities) { |
|
expData = countries; |
|
width = 500; |
|
height = 500; |
|
projection = d3.geo.satellite() |
|
.scale(350) |
|
.translate([250,250]) |
|
.rotate([0, 0, 0]) |
|
.center([0,0]) |
|
.tilt(30) |
|
.distance(1.5) |
|
.clipAngle(45) |
|
geoPath = d3.geo.path().projection(projection); |
|
|
|
var mapZoom = d3.behavior.zoom().translate(projection.translate()).scale(projection.scale()).on("zoom", zoomed); |
|
d3.select("svg").call(mapZoom); |
|
|
|
var xRotate = d3.scale.linear() |
|
.domain([0, width]) |
|
.range([-180, 180]); |
|
|
|
var yRotate = d3.scale.linear() |
|
.domain([0, height]) |
|
.range([90, -90]); |
|
|
|
d3.select("svg").on("mousedown", startRotating).on("mouseup", stopRotating); |
|
|
|
function startRotating() { |
|
d3.select("svg").on("mousemove", function() { |
|
var p = d3.mouse(this); |
|
projection.rotate([xRotate(p[0]), yRotate(p[1]), projection.rotate()[2]]); |
|
zoomed(); |
|
}); |
|
} |
|
|
|
function stopRotating() { |
|
d3.select("svg").on("mousemove", null); |
|
} |
|
function gammaRotate(direction) { |
|
currentRotate = projection.rotate(); |
|
console.log(currentRotate) |
|
if (direction == "less") { |
|
projection.rotate([currentRotate[0],currentRotate[1],currentRotate[2] - 5]) |
|
} |
|
else { |
|
projection.rotate([currentRotate[0],currentRotate[1],currentRotate[2] + 5]) |
|
} |
|
zoomed(); |
|
} |
|
function tiltAdjust(direction) { |
|
currentTilt = projection.tilt(); |
|
if (direction == "less") { |
|
projection.tilt(currentTilt - 5) |
|
} |
|
else { |
|
projection.tilt(currentTilt + 5) |
|
} |
|
zoomed(); |
|
} |
|
|
|
function distanceAdjust(direction) { |
|
currentDist = projection.distance(); |
|
if (direction == "less") { |
|
projection.distance(currentDist - .1) |
|
} |
|
else { |
|
projection.distance(currentDist + .1) |
|
} |
|
zoomed(); |
|
} |
|
function zoomed() { |
|
var currentRotate = projection.rotate()[0] |
|
projection.scale(mapZoom.scale()); |
|
d3.selectAll("path.graticule").attr("d", geoPath); |
|
d3.selectAll("path.countries").attr("d", geoPath); |
|
|
|
d3.selectAll("circle.cities") |
|
.attr("cx", function(d) {return projection([d.y,d.x])[0]}) |
|
.attr("cy", function(d) {return projection([d.y,d.x])[1]}) |
|
.style("display", function(d) {return parseInt(d.y) + currentRotate < 45 && parseInt(d.y) + currentRotate > -45 ? "block" : "none"}) |
|
var curSettings = "Scale :" + projection.scale() + " Rotate: " + projection.rotate() + " Distance: " + projection.distance() + " Tilt: " + projection.tilt(); |
|
d3.select("#settings").html(curSettings); |
|
|
|
|
|
} |
|
|
|
function zoomButton(zoomDirection) { |
|
if (zoomDirection == "in") { |
|
var newZoom = mapZoom.scale() * 1.5; |
|
var newX = ((mapZoom.translate()[0] - (width / 2)) * 1.5) + width / 2; |
|
var newY = ((mapZoom.translate()[1] - (height / 2)) * 1.5) + height / 2; |
|
} |
|
else if (zoomDirection == "out") { |
|
var newZoom = mapZoom.scale() * .75; |
|
var newX = ((mapZoom.translate()[0] - (width / 2)) * .75) + width / 2; |
|
var newY = ((mapZoom.translate()[1] - (height / 2)) * .75) + height / 2; |
|
} |
|
|
|
mapZoom.scale(newZoom).translate([newX,newY]) |
|
zoomed(); |
|
} |
|
|
|
d3.select("#controls").append("button").on("click", function () {zoomButton("in")}).html("Zoom +"); |
|
d3.select("#controls").append("button").on("click", function () {zoomButton("out")}).html("Zoom -"); |
|
d3.select("#controls").append("button").on("click", function () {gammaRotate("less")}).html("Gamma -"); |
|
d3.select("#controls").append("button").on("click", function () {gammaRotate("more")}).html("Gamma +"); |
|
d3.select("#controls").append("button").on("click", function () {tiltAdjust("less")}).html("Tilt -"); |
|
d3.select("#controls").append("button").on("click", function () {tiltAdjust("more")}).html("Tilt +"); |
|
d3.select("#controls").append("button").on("click", function () {distanceAdjust("less")}).html("Distance -"); |
|
d3.select("#controls").append("button").on("click", function () {distanceAdjust("more")}).html("Distance +"); |
|
|
|
featureSize = d3.extent(countries.features, function(d) {return geoPath.area(d)}); |
|
countryColor = d3.scale.quantize().domain(featureSize).range(colorbrewer.Reds[7]); |
|
|
|
var graticule = d3.geo.graticule(); |
|
|
|
d3.select("svg").append("path") |
|
.datum(graticule) |
|
.attr("class", "graticule line") |
|
.attr("d", geoPath) |
|
.style("fill", "none") |
|
.style("stroke", "lightgray") |
|
.style("stroke-width", "1px"); |
|
|
|
d3.select("svg").selectAll("path.countries").data(countries.features) |
|
.enter() |
|
.append("path") |
|
.attr("d", geoPath) |
|
.attr("class", "countries") |
|
.style("fill", function(d) {return countryColor(geoPath.area(d))}) |
|
.style("stroke-width", 1) |
|
.style("stroke", "black") |
|
.style("opacity", .5) |
|
.on("mouseover", centerBounds) |
|
.on("mouseout", clearCenterBounds) |
|
|
|
d3.select("svg").selectAll("circle").data(cities) |
|
.enter() |
|
.append("circle") |
|
.attr("class", "cities") |
|
.style("fill", "black") |
|
.style("stroke", "white") |
|
.style("stroke-width", 1) |
|
.attr("r", 3) |
|
.attr("cx", function(d) {return projection([d.y,d.x])[0]}) |
|
.attr("cy", function(d) {return projection([d.y,d.x])[1]}) |
|
|
|
function centerBounds(d,i) { |
|
thisBounds = geoPath.bounds(d); |
|
thisCenter = geoPath.centroid(d); |
|
d3.select("svg") |
|
.append("rect") |
|
.attr("class", "bbox") |
|
.attr("x", thisBounds[0][0]) |
|
.attr("y", thisBounds[0][1]) |
|
.attr("width", thisBounds[1][0] - thisBounds[0][0]) |
|
.attr("height", thisBounds[1][1] - thisBounds[0][1]) |
|
.style("fill", "none") |
|
.style("stroke-dasharray", "5 5") |
|
.style("stroke", "black") |
|
.style("stroke-width", 2) |
|
.style("pointer-events", "none") |
|
|
|
d3.select("svg") |
|
.append("circle") |
|
.attr("class", "centroid") |
|
.attr("r", 5) |
|
.attr("cx", thisCenter[0]).attr("cy", thisCenter[1]) |
|
.style("pointer-events", "none") |
|
} |
|
function clearCenterBounds() { |
|
d3.selectAll("circle.centroid").remove(); |
|
d3.selectAll("rect.bbox").remove(); |
|
} |
|
} |
|
|
|
} |
|
</script> |
|
</footer> |
|
</body> |
|
</html> |