|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> |
|
<script src="//d3js.org/topojson.v1.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/2.0.2/turf.min.js"></script> |
|
|
|
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.js'></script> |
|
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.css' rel='stylesheet' /> |
|
|
|
|
|
<style> |
|
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } |
|
|
|
#load { |
|
position: absolute; |
|
width: 45%; |
|
background-color: rgba(255, 255, 255, 0.6); |
|
font-family: Monospace; |
|
margin: 10px; |
|
padding: 5px; |
|
border-radius: 3px; |
|
-webkit-user-select: none; |
|
-moz-user-select: none; |
|
user-select: none; |
|
line-height: 24px; |
|
} |
|
#meta { |
|
|
|
} |
|
#url { |
|
margin-top: 10px; |
|
width: calc(100% - 55px); |
|
} |
|
|
|
.example { |
|
font-size: 10px; |
|
font-weight: bold; |
|
margin: 5px; |
|
cursor: pointer; |
|
} |
|
.example:hover { |
|
text-decoration: underline; |
|
} |
|
|
|
#map { |
|
width: 100%; |
|
height: 100%; |
|
position: absolute; |
|
} |
|
svg { |
|
width: 100%; |
|
height: 100%; |
|
position: absolute; |
|
} |
|
|
|
path { |
|
stroke: #111; |
|
fill: #ff7; |
|
fill-opacity: 0.3; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<div id="map"> |
|
</div> |
|
<div id="load"> |
|
<input id="url"> |
|
<button id="loadurl">Load</button> |
|
<br>or <span id="examples"></span> |
|
<br> |
|
<input id="loadfile" type="file"> |
|
<br> |
|
<div id="meta"> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
//Setup mapbox-gl map |
|
mapboxgl.accessToken = 'pk.eyJ1IjoiZW5qYWxvdCIsImEiOiJjaWhtdmxhNTIwb25zdHBsejk0NGdhODJhIn0.2-F2hS_oTZenAWc0BMf_uw' |
|
var map = new mapboxgl.Map({ |
|
container: 'map', // container id |
|
style: 'mapbox://styles/enjalot/cihmvv7kg004v91kn22zjptsc', |
|
center: [0,30], |
|
zoom: 0.8, |
|
|
|
}) |
|
map.addControl(new mapboxgl.Navigation()); |
|
// Setup our svg layer that we can manipulate with d3 |
|
var container = map.getCanvasContainer() |
|
var svg = d3.select(container).append("svg") |
|
/* |
|
var bbox = document.body.getBoundingClientRect(); |
|
var canvas = d3.select(container).append("canvas").node() |
|
canvas.width = bbox.width; |
|
canvas.height = bbox.height; |
|
var ctx = canvas.getContext('2d'); |
|
*/ |
|
|
|
/* |
|
function project(d) { |
|
return map.project(getLL(d)); |
|
} |
|
function getLL(d) { |
|
return new mapboxgl.LngLat(+d.lon, +d.lat) |
|
}*/ |
|
function getD3() { |
|
var bbox = document.body.getBoundingClientRect(); |
|
var center = map.getCenter(); |
|
var zoom = map.getZoom(); |
|
// 512 is hardcoded tile size, might need to be 256 or changed to suit your map config |
|
var scale = (512) * 0.5 / Math.PI * Math.pow(2, zoom); |
|
|
|
var d3projection = d3.geo.mercator() |
|
.center([center.lng, center.lat]) |
|
.translate([bbox.width/2, bbox.height/2]) |
|
.scale(scale); |
|
|
|
return d3projection; |
|
} |
|
|
|
var path = d3.geo.path() |
|
.projection(getD3()) |
|
/* |
|
.projection(function(lonlat, i) { |
|
var p = map.project(new mapboxgl.LngLat(lonlat[0], lonlat[1])) |
|
return [p.x, p.y]; |
|
})*/ |
|
//.context(ctx) |
|
|
|
function render() { |
|
path.projection(getD3()) |
|
svg.selectAll("path").attr("d", path) |
|
} |
|
// re-render our visualization whenever the view changes |
|
map.on("viewreset", function() { |
|
render() |
|
}) |
|
map.on("move", function() { |
|
render() |
|
}) |
|
|
|
// render our initial visualization |
|
render() |
|
|
|
|
|
// Prep the data loading UI |
|
|
|
var examples = [ |
|
{"name": "World countries", url: "http://enjalot.github.io/wwsd/data/world/ne_50m_admin_0_countries.topojson"}, |
|
{"name": "California streams", url:"http://enjalot.github.io/wwsd/data/USA/california-streams.topojson"}, |
|
{"name": "London tube stations", url: "http://enjalot.github.io/wwsd/data/UK/london_stations.topojson"} |
|
] |
|
d3.select("#examples").selectAll("a.example") |
|
.data(examples) |
|
.enter().append("a").classed("example", true) |
|
.text(function(d) { return d.name}) |
|
.on("click", function(d) { |
|
d3.select("#url").node().value = d.url; |
|
loadUrl(d.url) |
|
}) |
|
d3.select("#loadurl").on("click", loadUrl); |
|
d3.select("#url").on("keydown", function() { |
|
if(d3.event.code === "Enter") { |
|
loadUrl() |
|
} |
|
}) |
|
d3.select("#loadfile").node() |
|
.addEventListener('change', loadFile, false); |
|
|
|
var load = d3.select("#load").node() |
|
load.addEventListener("dragover", handleDragOver, false) |
|
load.addEventListener("drop", loadFile, false); |
|
|
|
function handleDragOver(evt) { |
|
evt.stopPropagation(); |
|
evt.preventDefault(); |
|
evt.dataTransfer.dropEffect = 'copy'; |
|
} |
|
function loadFile(evt) { |
|
evt.stopPropagation(); |
|
evt.preventDefault(); |
|
d3.select("pre#out").text("LOADING") |
|
|
|
var files; |
|
if(evt.dataTransfer) { |
|
files = evt.dataTransfer.files; |
|
} else { |
|
files = evt.target.files; |
|
} |
|
var reader = new FileReader(); |
|
reader.onload = function(e) { |
|
convert(JSON.parse(e.target.result)) |
|
} |
|
reader.readAsText(files[0]) |
|
} |
|
|
|
function convert(topo) { |
|
console.log("topojson:", topo) |
|
var keys = Object.keys(topo.objects); |
|
d3.select("#meta").html(keys.length + " objects: " + keys.join("<br>")) |
|
|
|
// clear the SVG |
|
svg.selectAll("*").remove(); |
|
|
|
var boundsList = []; |
|
keys.forEach(function(key) { |
|
var geo = topojson.feature(topo, topo.objects[key]) |
|
// https://github.com/d3/d3/wiki/Geo-Paths#bounds |
|
//boundsList.push(d3.geo.bounds(boundsList)) |
|
var envelope = turf.envelope(geo).geometry.coordinates[0] |
|
boundsList.push([envelope[0], envelope[2]]) |
|
|
|
console.log("geojson", key, envelope, geo) |
|
renderJSON(geo) |
|
}); |
|
// TODO: calculate the total bounds of all objects |
|
// left,bottom right,top |
|
var bounds = boundsList[0]; |
|
console.log("bounds", bounds); |
|
if(bounds[0][1] <= -90) bounds[0][1] = -89; |
|
if(bounds[1][1] <= -90) bounds[1][1] = -89; |
|
map.fitBounds(bounds) |
|
} |
|
|
|
function loadUrl(url) { |
|
if(!url) { |
|
url = d3.select("#url").node().value; |
|
} |
|
d3.select("#meta").text("LOADING") |
|
d3.json(url, function(err, topo) { |
|
if(err) { |
|
d3.select("#meta").text("ERROR:" + err.message) |
|
return; |
|
} |
|
convert(topo) |
|
}) |
|
} |
|
|
|
function renderJSON(geo, pretty) { |
|
svg.append("path") |
|
.datum(geo) |
|
.attr("d", path); |
|
} |
|
|
|
</script> |
|
</body> |