OSM Vector Tiles

Using OpenStreetMap vector tiles.

A simple vector tiles map with Mapzen vector tiles. Note: TopoJSON vector tiles are not optimized for rendering - they might clip geometries exactly at the tile boundary instead of adding a buffer, and use geographic coordinates instead of tile relative pixel coordinates in view projection.

<!DOCTYPE html>
<html>
  <head>
    <title>OSM Vector Tiles</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v3.20.0/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v3.20.0/build/ol.js"></script>
    <style>
      .map {
        background: #f8f4f0;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <script>
      var key = 'Your Mapzen API key from https://mapzen.com/developers';

      var attribution = [new ol.Attribution({
        html: '&copy; OpenStreetMap contributors, Who’s On First, Natural Earth, and openstreetmapdata.com'
      })];
      var format = new ol.format.TopoJSON();
      var tileGrid = ol.tilegrid.createXYZ({maxZoom: 19});
      var roadStyleCache = {};
      var roadColor = {
        'major_road': '#776',
        'minor_road': '#ccb',
        'highway': '#f39'
      };
      var buildingStyle = new ol.style.Style({
        fill: new ol.style.Fill({
          color: '#666',
          opacity: 0.4
        }),
        stroke: new ol.style.Stroke({
          color: '#444',
          width: 1
        })
      });

      var map = new ol.Map({
        layers: [
          new ol.layer.VectorTile({
            source: new ol.source.VectorTile({
              attributions: attribution,
              format: format,
              tileGrid: tileGrid,
              url: 'https://tile.mapzen.com/mapzen/vector/v1/water/{z}/{x}/{y}.topojson?api_key=' + key
            }),
            style: new ol.style.Style({
              fill: new ol.style.Fill({
                color: '#9db9e8'
              })
            })
          }),
          new ol.layer.VectorTile({
            source: new ol.source.VectorTile({
              attributions: attribution,
              format: format,
              tileGrid: tileGrid,
              url: 'https://tile.mapzen.com/mapzen/vector/v1/roads/{z}/{x}/{y}.topojson?api_key=' + key
            }),
            style: function(feature) {
              var kind = feature.get('kind');
              var railway = feature.get('railway');
              var sort_key = feature.get('sort_key');
              var styleKey = kind + '/' + railway + '/' + sort_key;
              var style = roadStyleCache[styleKey];
              if (!style) {
                var color, width;
                if (railway) {
                  color = '#7de';
                  width = 1;
                } else {
                  color = roadColor[kind];
                  width = kind == 'highway' ? 1.5 : 1;
                }
                style = new ol.style.Style({
                  stroke: new ol.style.Stroke({
                    color: color,
                    width: width
                  }),
                  zIndex: sort_key
                });
                roadStyleCache[styleKey] = style;
              }
              return style;
            }
          }),
          new ol.layer.VectorTile({
            source: new ol.source.VectorTile({
              attributions: attribution,
              format: format,
              tileGrid: tileGrid,
              url: 'https://tile.mapzen.com/mapzen/vector/v1/buildings/{z}/{x}/{y}.topojson?api_key=' + key
            }),
            style: function(f, resolution) {
              return (resolution < 10) ? buildingStyle : null;
            }
          })
        ],
        target: 'map',
        view: new ol.View({
          center: ol.proj.fromLonLat([-74.0064, 40.7142]),
          maxZoom: 19,
          zoom: 15
        })
      });
    </script>
  </body>
</html>