Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
TopoJSON vector maps from OSM

Fun with vector maps

Quick TopoJSON vector tile demo map, derived from an earlier GeoJSON demo. Original README follows.

A goofy slippy map of various vector tile data sources. With some fun colours, greetz to Aaron and Mike and Mike and the whole Prettymaps crew.

Sacramento, CASF bay area, CANew Orleans, LABoulder, COAlbuquerque, NMCrater Lake, ORBagdad Cafe, CAHillsboro, KSGalveston Bay, TXCape Cod, MA

Layers used here:

Want to make maps like this? See my vector tiles tutorial.

Tested with Chrome. If the background tiles are pepto-bismol pink instead of gunmetal grey, your browser doesn't support -webkit-filter.

<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0"/>
<title>Leaflet vector tile map of rivers</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
<![endif]-->
<script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>
<script src="http://www.somebits.com/rivers/lib/leaflet-hash.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="TileLayer.d3_topoJSON.js"></script>
<style type="text/css">
html, body { height: 100% }
#map { min-height: 100%; }
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif; font-size: 12px;
overflow: hidden;
background-color: #f00;
}
.leaflet-popup-content-wrapper {
-webkit-border-radius: 5px;
border-radius: 5px;
}
path { stroke-linejoin; round; stroke-linecap: round; fill: none}
path.river { stroke : #24b; }
path.road { stroke: #b42; }
path.water { stroke: #bcf; fill: #abf; }
path.landuse { stroke: #bb2; fill: #cc2; opacity: 0.4 }
path.building { stroke: #f00; fill: #f00; }
img { -webkit-filter: grayscale(100%) brightness(40%) contrast(150%);}
</style>
</head><body>
<div id="map"></div>
<script type="text/javascript">
// Construct map, center if no location provided
var map = L.map('map', { minZoom: 7, maxZoom: 15 } );
var hash = new L.Hash(map);
if (!window.location.hash) {
map.setView([39.28, -121.18], 10);
}
// Make the base map; a raster tile relief map from ESRI
var esriRelief = 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}'
var basemap = L.tileLayer(esriRelief, {
attribution: '<a href="http://www.arcgis.com/home/item.html?id=9c5370d0b54f4de1b48a3792d7377ff2">ESRI shaded relief</a>, <a href="http://www.horizon-systems.com/NHDPlus/NHDPlusV2_home.php">NHDPlus v2</a>, OpenStreetMap',
maxZoom: 13
});
basemap.addTo(map);
// Add a fake GeoJSON line to coerce Leaflet into creating the <svg> tag that d3_geoJson needs
new L.geoJson({"type": "LineString","coordinates":[[0,0],[0,0]]}).addTo(map);
// Land use areas from OpenStreetMap
var landColors = {
"farm": 1,
"meadow": 1,
"scrub": 1,
"forest": 1,
"farmyard": 1,
"farmland": 1,
"wood": 1,
"park": 1,
"cemetery": 1,
"golf_course": 1,
"grass": 1,
"nature_reserve": 1,
"pitch": 1,
"common": 1,
"residential": "#ddd",
"industrial": "#b3c",
"commercial": "#b3c",
"retail": "#b3c",
"parking": "#b3c",
"quarry": "#b3c",
"school": "#b3c",
"hospital": "#b3c",
"college": "#b3c",
"university": "#b3c",
}
function rando(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
new L.TileLayer.d3_topoJSON("http://tile.openstreetmap.us/vectiles-land-usages/{z}/{x}/{y}.topojson", {
class: "landuse",
layerName: "vectile",
style: function(d) {
var c = landColors[d.properties.kind];
if (!c) { c = "#fff"; }
if (c == 1) { // random greens
c = "hsl(" + rando(100, 130) + ", " + rando(50,70) + "%, " + rando(30, 50) + "%)";
}
return "fill: " + c;
}
}).addTo(map);
// Water Areas from OpenStreetMap
new L.TileLayer.d3_topoJSON("http://tile.openstreetmap.us/vectiles-water-areas/{z}/{x}/{y}.topojson", {
class: "water",
layerName: "vectile",
style: ""
}).addTo(map);
// Highways from OpenStreetMap
var roadSizes = {
"highway": "5px",
"major_road": "3px",
"minor_road": "1px",
"rail": "0px",
"path": "0.5px"
};
new L.TileLayer.d3_topoJSON("http://tile.openstreetmap.us/vectiles-highroad/{z}/{x}/{y}.topojson", {
class: "road",
layerName: "vectile",
style: function(d) { return "stroke-width: " + roadSizes[d.properties.kind]; }
}).addTo(map);
</script>
</body></html>
/* Experimental vector tile layer for Leaflet
* Uses D3 to render TopoJSON. Derived from a GeoJSON thing that was
* Originally by Ziggy Jonsson: http://bl.ocks.org/ZJONSSON/5602552
* Reworked by Nelson Minar: http://bl.ocks.org/NelsonMinar/5624141
*
* Todo:
* Make this work even if <svg> isn't in the DOM yet
* Make this work for tile types that aren't FeatureCollection
* Match D3 idioms for .classed(), .style(), etc
* Work on allowing feature popups, etc.
*/
L.TileLayer.d3_topoJSON = L.TileLayer.extend({
onAdd : function(map) {
L.TileLayer.prototype.onAdd.call(this,map);
this._path = d3.geo.path().projection(function(d) {
var point = map.latLngToLayerPoint(new L.LatLng(d[1],d[0]));
return [point.x,point.y];
});
this.on("tileunload",function(d) {
if (d.tile.xhr) d.tile.xhr.abort();
if (d.tile.nodes) d.tile.nodes.remove();
d.tile.nodes = null;
d.tile.xhr = null;
});
},
_loadTile : function(tile,tilePoint) {
var self = this;
this._adjustTilePoint(tilePoint);
if (!tile.nodes && !tile.xhr) {
tile.xhr = d3.json(this.getTileUrl(tilePoint),function(error, tjData) {
if (error) {
console.log(error);
} else {
var geoJson = topojson.feature(tjData, tjData.objects[self.options.layerName]);
tile.xhr = null;
tile.nodes = d3.select(map._container).select("svg").append("g");
tile.nodes.selectAll("path")
.data(geoJson.features).enter()
.append("path")
.attr("d", self._path)
.attr("class", self.options.class)
.attr("style", self.options.style);
}
});
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment