Eu estava procurando por uma solução sólida que me permitisse criar um mapa da Web e sobrepor polígonos vetoriais sem levar uma eternidade para carregar esses dados, com o objetivo de permitir que cada polígono exiba uma cor diferente em um evento de foco.
Tanto quanto sei, existem 3 opções específicas para conseguir isso através do canvas, SVG, Flash.
Parece que o Flash seria a melhor solução se funcionasse em iphones / ipads da apple, pois parece fornecer a renderização mais rápida e a exibição mais limpa. O Canvas parece ser a segunda melhor opção, mas leva MUITO tempo se você tiver centenas de polígonos sendo exibidos em um mapa, enquanto o SVG leva mais tempo para renderizar.
Eu quase perdi a esperança em encontrar uma solução para este problema , mas hoje me deparei com uma empresa chamada GISCloud http://www.giscloud.com (atualmente em beta com inscrição gratuita).
Em alguns casos, essa empresa conseguiu descobrir uma maneira incrível de renderizar centenas de vetores em um mapa quase em tempo real. Fiquei impressionado com a abordagem deles e minha pergunta para a comunidade diz respeito a como podemos replicar sua abordagem para uso com as tecnologias existentes, como folheto, camada aberta, cera ...
Dê uma olhada em si mesmo, assistindo a esta incrível demonstração: http://www.giscloud.com/map/284/africa
Passe o mouse sobre qualquer um dos polígonos da página e teste os controles de zoom para ver se esses polígonos são realmente vetores.
O que eu notei examinando solicitações com o firebug é que o mapa está solicitando arquivos json específicos. Parece que, dependendo do nível / área de zoom, vários arquivos json estão sendo solicitados.
Também devo mencionar aqui que, uma vez que o giscloud carrega os dados na página, passar o mouse sobre um vetor muda imediatamente a cor sem criar uma nova solicitação.
EXEMPLOS:
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/4/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/4.json
Estou assumindo que a estrutura do URL segue a lógica do serviço de ladrilhos padrão (por exemplo, a terceira a última pasta é o nível de zoom ...).
De qualquer forma, analisei os dados reais desses arquivos json e parece que a lógica que eles estão usando segue algum tipo de lógica pela qual eles criam seus vetores apenas com base nesses valores de dados:
- width / height: eles definem a largura e a altura dos dados servidos em cada solicitação json
- pixels: aqui eles definem valores de pixels que, suponho, se relacionam de alguma forma com algumas coordenadas gerais de pixels x / y para níveis de pontos generalizados? Suponho que, de alguma forma, eles tenham uma maneira de simplificar automaticamente a região, dependendo do nível de zoom. Estou assumindo que eles usam coordenadas de pixels. Acho que eles estão reduzindo drasticamente o tamanho dos dados que precisam ser carregados em comparação com os dados de lat / long.
- styles: aqui eles definem dois valores de CSS RGB. "F" representando a cor do arquivo de polígono e "S" representando a cor da borda do polígono.
- geom: aqui é onde eu suponho que eles estejam de alguma forma definindo especificamente cada polígono dentro do bloco que está sendo carregado, onde esses dados estão sendo definidos com base na janela do contêiner de mapa. O que também é interessante é que cada entrada possui um valor "S" que, suponho, é usado como um atributo opcional ou valor do link do recurso, e no final de cada entrada aqui há uma área que parece definir um ID por vetor específico, juntamente com o ID da camada que, suponho, é utilizado para, de alguma forma, unir os dados de cada solicitação de bloco json que está sendo chamada.
Também estou assumindo que eles de alguma forma descobriram uma maneira de determinar e dividir automaticamente os dados que precisam ser carregados para cada bloco, dependendo do tamanho dos dados que precisariam ser carregados para o bloco solicitado.
Aqui está um detalhamento extraído de uma dessas solicitações:
{"width":256,"height":256,"tile":
{"pixels":
[0,6461,-1,0,5,148,0,509,-1,10715,-1,1,-1,251,-1,1,-1,1,-1,251,-2,3,-1,255,-1,249,-2,5,-2,247,-1,509,-3,251,-1,2,-2,253,-2,252,-2,254,-1,255,-1,254,-1,255,-1,1276,-2,13,-1,233,-1,2,-1,253,-1,1,-1,255,-1,247,-1,1306,-1,1533,-1,1269,-1,1276,-1,2303,-1]},
"styles":
[{"f":"rgb(99,230,101)","s":"rgb(5,148,0)","lw":"0"}],
"geom":
[
{"s":0,"p":[4,143,5,144,3,146,1,146,2,143,4,143],"c":"layer1156_5098"},
{"s":0,"p":[-2,143,0,140,2,141,2,144,1,146,-2,144,-2,143],"c":"layer1156_5067"},
{"s":0,"p":[7,143,5,144,4,143,2,143,2,141,5,138,6,139,5,141,7,143],"c":"layer1156_5051"},
{"s":0,"p":[10,141,11,137,12,137,14,137,12,142,9,143,9,142,10,141],"c":"layer1156_5041"},
{"s":0,"p":[1,136,0,140,-2,143,-2,136,1,136],"c":"layer1156_5038"},
{"s":0,"p":[8,143,5,141,5,137,8,136,10,137,10,141,8,143],"c":"layer1156_5033"},
{"s":0,"p":[5,137,2,141,0,140,1,136,1,136,2,135,3,136,5,137],"c":"layer1156_5028"},
{"s":0,"p":[10,134,12,136,11,138,8,135,10,134],"c":"layer1156_5020"},
{"s":0,"p":[-2,133,0,136,-2,136,-2,133],"c":"layer1156_5005"},
{...}
...
]
}
Como podemos replicar o mesmo tipo (ou similar) de velocidade usando postgis (que eu também pareço usar)?
fonte
Respostas:
Eu já vi essa técnica usada no passado. Foi-me explicado por Zain Memon (da Trulia), que ajudou a dar alguma contribuição quando Michal Migurski estava criando o TileStache. Zain examinou o assunto enquanto explicava sua demonstração do Trulia que usa essa técnica em uma de nossas reuniões mais antigas do SF GeoMeetup há algum tempo . De fato, se você estiver em SF na próxima semana (esta é minha tentativa idiota de plugue, ele tocará nisso , fique à vontade para aparecer :)
OK, agora para a explicação.
Primeiro, você está olhando um pouco no lugar errado quando olha os arquivos json acima.
Deixe-me explicar (o mais curto possível), por quê.
Os blocos estão sendo passados da mesma maneira que os blocos renderizados regulares, não é grande coisa lá, sabemos como fazer isso e, portanto, não preciso explicar isso.
Se você o inspecionar no Firebug, verá que também obtém um monte de imagens que parecem estar em branco, como esta .
Por que está em branco? Não é. Os pixels contêm dados - mas não dados de imagem visível tradicionais. Eles estão usando uma técnica muito inteligente para transmitir dados codificados nos próprios pixels.
O que vem ocorrendo na última década é que as pessoas trocam dados de legibilidade e portabilidade de formatos em detrimento da eficiência do armazenamento.
Veja este exemplo de dados de amostra xml:
OK, quantas mordidas para transferir isso? Desde que tenhamos utf8 (1 byte por caractere ao lidar com este conteúdo). Bem, temos cerca de 176 caracteres (sem contar tabulações ou espaços), o que torna esses 176 bytes (isso está sendo otimista por várias razões que vou omitir por uma questão de simplicidade). Lembre-se, isso é por 2 pontos!
Ainda assim, algum espertinho que não entende do que está falando, em algum lugar, alegará que "json oferece uma maior compressão".
Tudo bem, vamos colocar o mesmo absurdo xml do json:
Quantos bytes aqui? Diga ~ 115 caracteres. Eu até trapacei um pouco e o tornei menor.
Digamos que minha área cubra 256x256 pixels e que eu esteja em um nível de zoom tão alto que cada recurso seja renderizado como um pixel e eu tenha tantos recursos, que esteja cheio. Quantos dados eu preciso para mostrar que 65.536 recursos?
54 caracteres (ou bytes utf - e até estou ignorando algumas outras coisas) por entrada "característica" multiplicada x 65.536 = 3.538.944 ou cerca de 3,3MB
Eu acho que você conseguiu a foto.
Mas é assim que transportamos dados em uma arquitetura orientada a serviços. Porcaria inchada legível.
E se eu quisesse transportar tudo em um esquema binário que eu mesmo me inventei? Diga que, em vez disso, codifiquei essas informações na imagem de banda única (ou seja, preto e branco). E eu decidi que 0 significa vendido e 1 significa disponível e 2 significa que eu não sei. Caramba, em um byte, tenho 256 opções que posso usar - e só estou usando 2 ou três delas para este exemplo.
Qual é o custo de armazenamento disso? 256x256x 1 (apenas uma banda). 65.536 bytes ou 0,06 MB. E isso nem leva em consideração outras técnicas de compressão que recebo gratuitamente de várias décadas de pesquisa em compressão de imagens.
Nesse ponto, você deve estar se perguntando por que as pessoas simplesmente não enviam dados codificados em formato binário em vez de serializar para json? Bem, primeiro, o javascript é uma droga para o transporte de dados binários , e é por isso que as pessoas não fazem isso historicamente.
Um trabalho impressionante foi usado por algumas pessoas quando os novos recursos do HTML5 foram lançados, principalmente o canvas . Então, o que é essa incrível solução alternativa? Acontece que você pode enviar dados pelo fio codificado no que parece ser uma imagem e, em seguida, pode inserir essa imagem em uma tela HTML5, que permite manipular os pixels diretamente ! Agora você tem uma maneira de capturar esses dados, decodificá-los no lado do cliente e gerar os objetos json no cliente.
Pare um momento e pense sobre isso.
Você tem uma maneira de codificar uma enorme quantidade de dados com referência geográfica significativa em um formato altamente compactado, ordens de magnitude menores do que qualquer outra coisa feita tradicionalmente em aplicativos da Web e manipulá-los em javascript.
A tela HTML nem precisa ser usada para desenhar, é usada apenas como um mecanismo de decodificação binária!
É disso que trata todas as imagens que você vê no Firebug. Uma imagem, com os dados codificados para cada bloco que é baixado. Eles são super pequenos, mas têm dados significativos.
Então, como você os codifica no lado do servidor? Bem, você precisa generalizar os dados no lado do servidor e criar um bloco significativo para cada nível de zoom que tenha os dados codificados. Atualmente, para fazer isso, você precisa fazer o seu próprio - não existe uma solução de código aberto pronta para uso, mas você tem todas as ferramentas necessárias para fazer isso disponível. O PostGIS fará a generalização através do GEOS, o TileCache pode ser usado para armazenar em cache e ajudá-lo a acionar a geração dos blocos. No lado do cliente, você precisará usar o HTML5 Canvas para transmitir os "blocos falsos" especiais e, em seguida, usar o OpenLayers para criar objetos javascript reais do lado do cliente que representam os vetores com efeitos de passagem do mouse.
Se você precisar codificar mais dados, lembre-se de que sempre pode gerar imagens RGBA por pixel (que fornece 4 bytes por pixel ou 4.294.967.296 números que você pode representar por pixel ). Eu posso pensar em várias maneiras de usar isso :)
Atualização : Respondendo à pergunta QGIS abaixo.
QGIS, como a maioria dos outros GIS es de mesa , não possui um conjunto fixo de níveis de zoom. Eles têm a flexibilidade de aplicar zoom em qualquer escala e apenas renderizar. Eles podem mostrar dados de fontes baseadas em WMS ou em blocos? Claro que podem, mas na maioria das vezes eles são realmente burros quanto a isso: aplique zoom em uma extensão diferente, calcule a caixa delimitadora, calcule as peças necessárias, agarre-as e mostre-as. Na maioria das vezes, eles ignoram outras coisas, como caches de cabeçalho http que permitiriam que eles não precisassem buscar novamente. Às vezes, eles implementam um mecanismo de cache simples (armazene o bloco, se você pedir, verifique o bloco, não peça). Mas isto não é o suficiente.
Com essa técnica, os ladrilhos e os vetores precisam ser recarregados em todos os níveis de zoom . Por quê? Porque os vetores foram generalizados para acomodar os níveis de zoom.
Quanto ao truque de colocar os blocos em uma tela HTML5 para que você possa acessar os buffers, isso não é necessário. O QGIS permite que você escreva código em Python e C ++, ambas as linguagens têm excelente suporte para lidar com buffers binários, portanto, essa solução alternativa é realmente irrelevante para esta plataforma.
* ATUALIZAÇÃO 2 **:
Havia uma pergunta sobre como criar os blocos vetoriais generalizados em primeiro lugar (etapa 1 do bebê antes de poder serializar os resultados em imagens). Talvez eu não tenha esclarecido o suficiente. O Tilestache permitirá que você crie "blocos vetoriais" eficazes de seus dados em todos os níveis de zoom (ele ainda possui uma opção que permite recortar ou não recortar os dados quando ultrapassar o limite do bloco). Isso cuida da separação dos vetores em blocos em vários níveis de zoom. Eu escolheria a opção "não cortar" (mas ele escolherá um bloco arbitrário onde cobre mais área). Em seguida, você pode alimentar todos os vetores através da opção de generalização do GEOS com um número grande; na verdade, você deseja que seja grande o suficiente para que polilinhas e polígonos colapsem sobre si mesmos, porque se o fizerem, você poderá removê-los do nível de zoom, pois nesse estágio eles estão. irrelevante. O Tilestache ainda permite que você escreva provedores de dados pitônicos fáceis, onde você pode colocar essa lógica. Nesse estágio, você pode optar por servi-los como arquivos json (como em algumas amostras de mapas africanos) ou como geometrias serializadas nos pngs, como em outras amostras (ou no Trulia) que forneci acima.
fonte
Direto do desenvolvedor Dino Ravnic em um post recente na lista de discussão :
Parece que o lado do cliente é a parte mais fácil. É impressionante que os dados sejam renderizados sem cache.
Ele também menciona um serviço de hospedagem que pode ser do seu interesse. Você pode ponderar o custo de tentar recriar isso com o custo de usar um serviço pronto.
fonte
Como descrevi na lista OSGeo, a chave está no fornecimento de dados como blocos JSON vetoriais que possuem pixels para geometria de subpixel e geometria generalizada para os recursos que serão realmente visíveis em um determinado nível. O desempenho é ótimo porque essa técnica elimina todas as informações desnecessárias sobre vetores e deixa apenas os vetores que realmente terão um impacto visual no mapa. Os pixels existem para preencher as lacunas e serem posicionados em vez desses vetores de subpixel. É isso em relação ao formato do bloco.
No lado de back-end está o verdadeiro trabalho pesado. Não estamos usando o TileStache ou qualquer outro mecanismo de mapa, pois criamos o nosso próprio que pode, com várias otimizações, produzir esses gráficos vetoriais em tempo real.
Primeiro, começamos a fornecer blocos de mapa como SWFs e, recentemente, ativamos a saída para JSON para que pudéssemos usar o HTML5 Canvas para renderizar os gráficos. Você pode encontrar abaixo uma referência comparando esse tipo de tecnologia vetorial com a tecnologia raster (mapnik). Para uma comparação justa, procure apenas resultados no modo CGI.
http://www.giscloud.com/blog/realtime-map-tile-rendering-benchmark-rasters-vs-vectors/
Planejamos fornecer essa tecnologia como um serviço de hospedagem de bloco de mapa. A idéia é hospedar seus dados geográficos na nuvem e, por meio do HTML5, entregá-los em qualquer cliente de mapa em alta velocidade, sem a necessidade de precache os blocos. Se você estiver interessado em participar desta versão beta, entre em contato conosco aqui: http://www.giscloud.com/contact/
fonte
Parece que uma pergunta muito semelhante foi feita recentemente no fórum OSGeo Open Layers , com os desenvolvedores do GIS Cloud descrevendo sua abordagem, que é uma mistura interessante de geometrias GeoJSON e pixels estáticos. Na verdade, eles geram todos os blocos vetoriais em tempo real, em vez de usar um cache pré-criado de arquivos GeoJSON.
A Esri implementou uma abordagem semelhante, usando o ArcGIS Server e Feature Layers , que podem generalizar as geometrias rapidamente e enviá-las por fio como JSON.
Para um método direto que você pode realmente implementar agora, você pode criar blocos vetoriais com o Tilestache (que tem suporte PostGIS ) e consumi-los no Polymaps . O Polymaps usa SVG, mas o desempenho é muito bom , e o CSS regula o estilo dos elementos do mapa, de modo que a renderização do recurso é totalmente sua. Aqui está uma postagem de blog que trabalha com algo semelhante ao que você está perguntando.
fonte
Eu brinquei com o OpenLayers usando o Canvas e obtive resultados razoáveis.
Conforme mencionado nas outras respostas: para entregar e mostrar vetores rapidamente - eles precisam ser generalizados para cada nível de zoom e cada conjunto de dados. Além disso, você pode usar a codificação de polilinha do Google para reduzir consideravelmente o tamanho.
Eu usei um mecanismo de entrega simples. Cada geometria era uma função JavaScript dentro de uma resposta HTTP JavaScript. não tão avançado quanto a entrega de vetores com base em blocos, mas simples e de código aberto!
Não experimentei o Google Maps v3 com o Canvas, mas vi algumas demos do New York Times que impressionaram.
fonte
Não sei exatamente qual solução é usada por esta empresa (talvez você possa perguntar diretamente), mas tenho uma ideia.
A principal solução para melhorar a velocidade de transferência e renderização da rede de dados vetoriais é generalizá-los de acordo com o nível de zoom: Transferir e renderizar em um nível de zoom alto Milhares de objetos projetados para um nível de zoom muito mais baixo geralmente consomem muito tempo (e também inútil porque a exibição final geralmente não é legível - veja, por exemplo, esta imagem ). Para implementar isso, o banco de dados do servidor postgis deve ser de várias escalas : Para cada nível de zoom, deve haver uma representação do objeto adequada para esse nível de zoom. Essas diferentes representações podem ser calculadas automaticamente usando técnicas de generalização. Além disso, os dados vetoriais enviados pelo servidor ao cliente não devem depender apenas da extensão espacial, mas também do nível de zoom: O servidor envia dados adequados, dependendo do nível de zoom. Esta é a abordagem defendida neste excelente artigo :-)
fonte
Há um artigo interessante, uma demonstração e o código-fonte de um software desenvolvido pelo Stanford Visualization Group que usa o datacube para cada bloco para visualizar e explorar um grande conjunto de dados geográficos. Ele pode ser usado apenas para o conjunto de dados de pontos, mas pode ser uma maneira interessante.
http://vis.stanford.edu/papers/immens
A vizzualidade com sua plataforma CartoDB e a biblioteca chamada Torque também estão experimentando, de alguma forma, como desenhar alto volume de dados.
http://cartodb.github.io/torque/
https://github.com/CartoDB/torque/tree/new_torque
fonte