Skip to content

Instantly share code, notes, and snippets.

@mapsense-examples
Last active August 29, 2015 14:21
Show Gist options
  • Save mapsense-examples/28e0992d038047be6dbe to your computer and use it in GitHub Desktop.
Save mapsense-examples/28e0992d038047be6dbe to your computer and use it in GitHub Desktop.
Use Mapsense tiles in Leaflet
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link rel="stylesheet" href="http://leafletjs.com/dist/leaflet.css" media="screen" type="text/css">
<link rel="stylesheet" href="https://developer.mapsense.co/mapsense.css" media="screen" type="text/css">
<script src='http://d3js.org/d3.v3.min.js' type="text/javascript"></script>
<script src='http://d3js.org/topojson.v1.min.js' type="text/javascript"></script>
<script src='http://leafletjs.com/dist/leaflet.js' type="text/javascript"></script>
<script src='L.TileLayer.d3_JSON_mapsense.js' type="text/javascript"></script>
<style>
html, body, #myMap { width: 100%; height: 100%; margin: 0; padding: 0;}
.leaflet-container {
background: transparent;
outline: 0;
}
.tile-background {
fill: none;
}
</style>
</head>
<body>
<div id="myMap"></div>
<script>
var map = L.map('myMap').setView([38, -122], 8);
var the_key = "key-2d5eacd8b924489c8ed5e8418bd883bc";
var mapsense_url = "https://{s}-api.mapsense.co/explore/api/universes/mapsense.earth/{z}/{x}/{y}.topojson?s=10&ringSpan=8&api-key="+the_key;
// Hat Tip http://bl.ocks.org/NelsonMinar/5624141
// 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);
new L.TileLayer.d3_JSON(mapsense_url, {
attribution: '<a target="_blank" href="https://developer.mapsense.co/tileViewer/?tileset=mapsense.earth">©Mapsense ©OpenStreetMap</a>',
// https://developer.mapsense.co/documentation/basemap
mapsenseStyle: "vintage" // choose a basemap style
}).addTo(map);
</script>
</body>
</html>
L.TileLayer.d3_JSON = L.TileLayer.extend({
//extending L.TileLayer to support topoJSON and geoJSON vector sources
//rendering with d3, borrows from zjonsson & https://github.com/glenrobertson/leaflet-tilelayer-geojson/
onAdd: function(map) {
var map_container_svg = d3.select(map._container).select("svg");
L.TileLayer.prototype.onAdd.call(this, map);
this.mapsenseStyle = this.options.mapsenseStyle;
this._path = d3.geo.path().projection({
stream: function(stream) {
// no sampling along great arc
// just a pure projection, without the default d3 projection-stream pipeline
// so, long lines don't make curves, i.e. they obey the mercator projection
return {
point: function(x, y) {
var p = map.latLngToLayerPoint(new L.LatLng(y, x));
stream.point(p.x, p.y);
},
lineStart: stream.lineStart,
lineEnd: stream.lineEnd,
polygonStart: stream.polygonStart,
polygonEnd: stream.polygonEnd,
sphere: stream.sphere
};
}
});
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);
var mapsenseStyle = this.mapsenseStyle;
if (!tile.nodes && !tile.xhr) {
tile.xhr = d3.json(this.getTileUrl(tilePoint), function(data) {
var geoJson;
if (data === '') {
// Ignore empty submissions
} else {
geoJson = topo2Geo(data);
}
tile.xhr = null;
nwPoint = tilePoint.multiplyBy(256);
sePoint = nwPoint.add([256, 256]);
nw = map.unproject(nwPoint);
se = map.unproject(sePoint);
var point = map.latLngToLayerPoint(new L.LatLng(nw.lat, nw.lng));
var tile_coords = "tile_" + point.x + "_" + point.y;
d3.select(map._container).select("svg")
.append("clipPath")
.attr("id", tile_coords)
.attr("style", "fill: none; stroke: pink; transform: translate(" + point.x + "px, " + point.y + "px); -webkit-transform: translate(" + point.x + "px, " + point.y + "px);")
.append("rect")
.attr("width", "256")
.attr("height", "256");
d3.select(map._container).select("svg")
.append("rect")
.attr("style", "transform: translate(" + point.x + "px, " + point.y + "px); -webkit-transform: translate(" + point.x + "px, " + point.y + "px);")
.attr("width", "256")
.attr("height", "256")
.attr("class", "mapsense-"+self.mapsenseStyle +" tile-background");
tile.nodes = d3.select(map._container).select("svg").append("g");
// tile.nodes is now a bunch of appended g's
var grp = tile.nodes.selectAll("path")
.data(geoJson.features)
.enter()
.append("g")
.attr("class", "groupr");
grp.append("path")
.attr("d", self._path)
.attr("clip-path", "url(#" + tile_coords + ")")
.attr("class", self.options.class)
.attr("class", function(d) { // this data is a bunch of features
var zoomClass = "_" + Math.floor(map.getZoom());
var classes = ['mapsense-'+self.mapsenseStyle];
if (d.properties) {
if (d.properties) {
if (d.properties.layer)
classes.push(d.properties.layer);
if (d.properties.natural)
classes.push(d.properties.natural);
if (d.properties.sub_layer)
classes.push(d.properties.sub_layer);
} else {
classes.push('unknown');
}
classes = classes.join(' ');
return classes;
} else {}
});
});
}
}
});
function topologyFeatures(topology) {
function convert(topology, object, layer, features) {
var featureOrCollection = topojson.feature(topology, object),
layerFeatures;
if (featureOrCollection.type === "FeatureCollection") {
layerFeatures = featureOrCollection.features;
} else {
layerFeatures = [featureOrCollection];
}
layerFeatures.forEach(function(f) {
f.properties.layer = layer;
});
features.push.apply(features, layerFeatures);
}
var features = [];
for (var o in topology.objects) {
convert(topology, topology.objects[o], o, features);
}
return features;
}
function topo2Geo(tj) {
var gj = {
type: "FeatureCollection",
features: topologyFeatures(tj)
};
return gj;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment