Blocos de vetor Mapbox auto-hospedados


81

Conforme apresentado em uma palestra no FOSS4G, o Mapbox Studio permite criar blocos vetoriais do Mapbox e exportá-los como um .mbtilesarquivo.

A biblioteca mapbox-gl.js pode ser usada para estilizar e renderizar dinamicamente blocos vetoriais do Mapbox no lado do cliente (navegador).

A parte que falta: como posso auto-hospedar blocos vetoriais do Mapbox ( .mbtiles) para consumi-los com o mapbox-gl.js?

Eu sei que o Mapbox Studio pode carregar os blocos de vetor no servidor Mapbox e deixá-lo hospedar os blocos. Mas isso não é uma opção para mim, quero hospedar os blocos de vetor no meu próprio servidor.


A abordagem TileStream abaixo acabou sendo um beco sem saída. Veja minha resposta para uma solução funcional com o Tilelive.


Eu tentei o TileStream, que pode exibir imagens de .mbtilesarquivos:

Minha página da web usa o mapbox-gl v0.4.0:

<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>

e cria um mapboxgl.Map em um script JavaScript:

  var map = new mapboxgl.Map({
    container: 'map',
    center: [46.8104, 8.2452],
    zoom: 9,
    style: 'c.json'
  });

O c.jsonarquivo de estilo configura a origem do bloco de vetores:

{
  "version": 6,
  "sprite": "https://www.mapbox.com/mapbox-gl-styles/sprites/bright",
  "glyphs": "mapbox://fontstack/{fontstack}/{range}.pbf",
  "constants": {
    "@land": "#808080",
    "@earth": "#805040",
    "@water": "#a0c8f0",
    "@road": "#000000"
  },
  "sources": {
    "osm_roads": {
      "type": "vector",
      "url": "tile.json"
    }
  },
  "layers": [{
    "id": "background",
    "type": "background",
    "paint": {
      "background-color": "@land"
    }
  }, {
    "id": "roads",
    "type": "line",
    "source": "osm_roads",
    "source-layer": "roads",
    "paint": {
      "line-color": "@road"
    }
  }]
}

... com a seguinte especificação TileJSON em tile.json:

{
  "tilejson": "2.1.0",
  "tiles": [
    "http://localhost:8888/v2/osm_roads/{z}/{x}/{y}.png"
  ],
  "minzoom": 0,
  "maxzoom": 12
}

... que aponta para o meu servidor TileStream em execução em localhost:8888. O TileStream foi iniciado com:

node index.js start --tiles="..\tiles"

... onde a ..\tilespasta contém meu osm_roads.mbtilesarquivo.

Com essa configuração, posso abrir minha página da Web, mas apenas ver a camada de plano de fundo. No rastreio da rede do navegador, posso ver que os blocos são realmente carregados quando aumento o zoom, mas o console de erros JavaScript do navegador contém vários erros no formulário

Error: Invalid UTF-8 codepoint: 160      in mapbox-gl.js:7

Como os blocos vetoriais não são .pngimagens, mas arquivos ProtoBuf, a URL dos blocos http://localhost:8888/v2/osm_roads/{z}/{x}/{y}.pbfrealmente faria mais sentido, mas isso não funciona.

Alguma ideia?

Respostas:


53

Conforme apontado pelo @Greg, em vez do TileStream (minha primeira tentativa), você deve usar o Tilelive para hospedar seus próprios blocos de vetor.

O Tilelive não é um servidor em si, mas uma estrutura de back-end que lida com blocos em diferentes formatos e fontes diferentes. Mas é baseado no Node.js, para que você possa transformá-lo em um servidor de maneira bastante direta. Para ler blocos de uma .mbtilesfonte exportada pelo Mapbox Studio, você precisa do módulo tilelive node-mbtiles .

Nota lateral: O Mapbox Studio atual possui um bug no Windows e no OS X que impede que um .mbtilesarquivo exportado seja exibido no destino escolhido. Solução alternativa: basta pegar o export-xxxxxxxx.mbtilesarquivo mais recente ~/.mapbox-studio/cache.

Eu encontrei duas implementações de servidor ( servidor ten20 lado a lado por alexbirkett e TileServer por hanchao ) que usam o Express.js como servidor de aplicativos da web.

Aqui está minha abordagem minimalista, que é vagamente baseada nessas implementações:

  1. Instale o Node.js
  2. Pegue os pacotes de nós com npm install tilelive mbtiles express
  3. Implemente o servidor no arquivo server.js:

    var express = require('express');
    var http = require('http');
    var app = express();
    var tilelive = require('tilelive');
    require('mbtiles').registerProtocols(tilelive);
    
    //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
    tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
        if (err) {
            throw err;
        }
        app.set('port', 7777);
    
        app.use(function(req, res, next) {
            res.header("Access-Control-Allow-Origin", "*");
            res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
            next();
        });
    
        app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
            var z = req.params[0];
            var x = req.params[1];
            var y = req.params[2];
    
            console.log('get tile %d, %d, %d', z, x, y);
    
            source.getTile(z, x, y, function(err, tile, headers) {
                if (err) {
                    res.status(404)
                    res.send(err.message);
                    console.log(err.message);
                } else {
                  res.set(headers);
                  res.send(tile);
                }
            });
        });
    
        http.createServer(app).listen(app.get('port'), function() {
            console.log('Express server listening on port ' + app.get('port'));
        });
    });

    Nota: Os Access-Control-Allow-...cabeçalhos ativam o compartilhamento de recursos de origem cruzada (CORS), para que as páginas da web veiculadas em um servidor diferente possam acessar os blocos.

  4. Execute-o com node server.js

  5. Configure a página da Web usando o Mapbox GL JS em minimal.html:

    <!DOCTYPE html >
    <html>
      <head>
        <meta charset='UTF-8'/>
        <title>Mapbox GL JS rendering my own tiles</title>
        <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
        <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
        <style>
          body { margin:0; padding:0 }
          #map { position:absolute; top:0; bottom:50px; width:100%; }
        </style>
      </head>
      <body>
        <div id='map'>
        </div>
        <script>
          var map = new mapboxgl.Map({
            container: 'map',
            center: [46.8, 8.5],
            zoom: 7,
            style: 'minimal.json'
          });
        </script>
      </body>
    </html>
  6. Indique a localização da origem do bloco e estilize as camadas com o seguinte minimal.json:

    {
      "version": 6,
      "constants": {
        "@background": "#808080",
        "@road": "#000000"
      },
      "sources": {
        "osm_roads": {
          "type": "vector",
          "tiles": [
            "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
          ],
          "minzoom": 0,
          "maxzoom": 12
        }
      },
      "layers": [{
        "id": "background",
        "type": "background",
        "paint": {
          "background-color": "@background"
        }
      }, {
        "id": "roads",
        "type": "line",
        "source": "osm_roads",
        "source-layer": "roads",
        "paint": {
          "line-color": "@road"
        }
      }]
    }
  7. Servir a página da web e se alegrar.


2
Observe que você precisa de três ///para definir o arquivo mbtiles em:tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
CDavis

@cdavis: Isso parece depender do sistema operacional: Três ///são necessários para Linux e OS X, como por exemplo mbtiles:///usr/local/osm_roads.mbtiles. No Windows, porém, apenas dois //são necessários se você especificar o disco como, por exemplo mbtiles://D/data/osm_roads.mbtiles.
Andreas Bilger

Realmente útil, muito obrigado, me ajudou a servir mbtiles de vetor em 5 '!
Bwyss

Oi Andreas - não consegui fazer isso funcionar - o mapa é exibido, mas é apenas um grande quadrado cinza em branco. Não tenho certeza de onde você conseguiu sua fonte mbtiles. Eu tentei exportar alguns dos mbtiles padrão do tilemill.
Mheavers 28/10/2015

você parece usar localhost: 7777 / v2 / tiles / para o local dos seus tiles, mas de onde você está conseguindo esse caminho? Ou o que você precisa fazer para garantir que o arquivo mbtiles exportado sirva as imagens para esse caminho?
Mheavers

26

A hospedagem dos blocos de vetor por conta própria é relativamente simples. O MBTiles contém arquivos .pbf que devem ser expostos à web. É isso aí.

Provavelmente, o mais fácil é usar um servidor de código aberto simples como o TileServer-PHP e colocar o arquivo MBTiles na mesma pasta que os arquivos do projeto. O TileServer faz toda a configuração de hospedagem para você (CORS, TileJSON, cabeçalhos gzip corretos, etc). Instalação significa apenas descompactar em um servidor da Web habilitado para PHP.

Se você deseja iniciar o TileServer-PHP no seu laptop, pode fazê-lo com o Docker. O contêiner pronto para usar está no DockerHub . No Mac OS X e Windows, ele é executado em alguns minutos com a interface gráfica do usuário Kitematic: https://kitematic.com/ . No Kitematic, procure por "tileserver-php" e inicie a máquina virtual / contêiner pronta para usar com o projeto dentro. Em seguida, clique em "Volumes" e solte na pasta seu arquivo MBTiles. Você recebe uma hospedagem em execução para seus blocos de vetor!

Esses blocos vetoriais podem ser abertos no MapBox Studio como uma fonte ou exibidos com o visualizador MapBox GL JS WebGL.

Tecnicamente, é possível hospedar os blocos vetoriais como uma pasta simples em qualquer servidor Web ou armazenamento em nuvem, ou mesmo no GitHub, se você descompactar o .pbf individual do contêiner MBtiles com um utilitário como mbutil , defina o CORS, TileJSON e gzip corretamente. Abaixo está um projeto do GitHub que demonstra essa abordagem também.

Experimente este visualizador: Visualizador MapBox GL JS

e veja os repositórios relacionados:


1
Essa foi de longe a mais fácil de todas as opções acima para mim, obrigado por postar.
Mheavers

PGRestAPI, parece ótimo, mas falha na instalação para mim. Nunca consigo instalar o PGRestAPI com sucesso. Portanto, este servidor de ladrilhos php é a minha única opção e funciona perfeitamente.
hoogw

Isso é mais interessante: você poderia elaborar a configuração correta do CORS e TileJSON para servir os arquivos pbf? Eu baixei um arquivo pbf em download.geofabrik.de/europe, no entanto, o projeto vinculado contém muitos diretórios com muitos arquivos pbf.
php_nub_qq

12

Não para tocar minha buzina, mas https://github.com/spatialdev/PGRestAPI é um projeto no qual estou trabalhando para hospedar as exportações de mosaicos de vetores .mbtiles do Mapbox Studio.

Ainda precisa de muita documentação, mas, basicamente, solte seus arquivos .mbtiles em / data / pbf_mbtiles e reinicie o aplicativo do nó. Ele lerá essa pasta e oferecerá pontos de extremidade para seus blocos de vetor.

Ele também examinará / data / shapefiles e criará dinamicamente blocos vetoriais de Mapbox dinamicamente, com base no seu .shp. Você também pode apontar para uma instância do PostGIS e obter blocos vetoriais dinâmicos.

Nós os usamos em conjunto com https://github.com/SpatialServer/Leaflet.MapboxVectorTile , uma biblioteca Leaflet / Mapbox Vector Tile em que também estamos trabalhando.


1
PGRestAPI não está mais sendo desenvolvido ativamente infelizmente
raphael

10

Obrigado pela ótima pergunta. Eu não sabia que eles finalmente lançaram uma versão estável dos blocos de vetor. Além disso, você pode ter que trabalhar com essa resposta, pois ela é uma fonte de idéias para suas "alguma idéia?" Pergunta, questão. Ainda não tenho um estúdio de corrida.

Eu acho que um dos problemas que você está enfrentando é que você está usando um arquivo tilejson. Você precisa de um serviço tilejson para usar esse tipo de arquivo. Portanto, acredito que você precisa alterar sua seção de fontes para um URL in-line. Experimentar

"sources": {
"osm_roads": {
  "type": "vector",
  "url": "http://localhost:8888/v2/osm_roads/{z}/{x}/{y}.png"
 }
},

ou

"sources": { 
"osm_orads": {
  "type": "vector",
  "tiles": [
    "http://localhost:8888/v2/osm_roads/{z}/{x}/{y}.png"
  ],
  "minzoom": 0,
  "maxzoom": 12
 }
},

Quando eles usam mapbox://como protocolo, é uma notação de alias / abreviação para seus serviços. A seção de fontes foi discutida brevemente em torno das 8:40 do vídeo.

Uma etapa do novo processo de mosaico vetorial é selecionar os dados vetoriais, ajustando o que você deseja nos dados. A outra etapa é trazer os dados vetoriais de volta para o MapBox Studio e renderizar os dados / criar uma folha de estilos. osm_roads seria o primeiro passo, enquanto o arquivo c.json é a folha de estilos. Você pode precisar de um vivo telha servidor versos um fluxo de azulejo como discutido em torno 15:01 do vídeo. O vídeo diz que você precisa de metadados adicionais no arquivo xml.

A singularidade aqui é que você faz referência ao .pbf e à folha de estilos em outro lugar, mas a URL que você fornece são os arquivos .png dos blocos resultantes, gerados a partir dos dados vetoriais.

Você não diz, se você tem uma chave MapBox. Para sua própria hospedagem, acredito que você precisará copiar os estilos e glifos do github para o seu próprio servidor. Observe novamente que existe um mapbox: // protocol na tag glyphs. Essas duas tags podem não ser necessárias porque você está processando linhas simples e polígonos e não POIs por meio de ícones. Vale a pena dar uma olhada.

Finalmente, o vídeo diz que você pode levar uma camada vetorial gerada de volta ao estúdio para estilizá-la. Você pode referenciar sua camada vetorial e aplicar seu estilo id: background e id: roads no estúdio primeiro. O vídeo diz que o tile live é o servidor nos bastidores do MapBox Studio. A idéia aqui é garantir que você tenha todos os problemas da etapa dois entendidos e corrigidos antes de tentar exibir os blocos vetoriais finais renderizados dinamicamente.


Ok, obrigado @Greg por suas idéias. Irá investigar mais e voltar com minhas descobertas.
Andreas Bilger

4

https://github.com/osm2vectortiles/tileserver-gl-light é muito mais fácil de usar do que as principais soluções mencionadas - não é necessário mexer nos arquivos JSON. Você acabou de executá-lo com

tileserver-gl-light filename.mbtiles

e então está servindo as peças para você. Ele funciona com os estilos predefinidos do Mapbox GL, como bright-v9; depois de executar o servidor, basta apontar o que estiver consumindo os blocos para

http: // localhost: 8080 / styles / bright-v9.json



1

Super mais tarde, mas agora o GeoServer serve pbf's (formato de bloco vetorial)


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.