domingo, agosto 17, 2014

WMS GetFeatureInfo Utilizando MapServer e Leaflet

No Leaflet existem duas formas bem usuais de se obter os dados tabulares de uma feição através do clique do usuário em uma determinada camada. Uma delas é através do uso de marcadores (Markers), que é mais utilizada para a representação de pontos. A outra  é  o formato GeoJSON, que é uma excelente opção para exibir camadas de polígonos e de linhas neste aplicativo.

Porém, quando uma camada GeoJSON possui muitas feições ou uma grande quantidade de vértices, seu carregamento pode comprometer o desempenho do aplicativo. Uma saída para este problema é utilizar o formato WMS habilitando a requisição GetFeatureInfo como é mostrado no exemplo a seguir.

1 - Configuração do Mapfile como Servidor WMS:


A configuração do servidor WMS é feita através da definição dos itens obrigatórios para o seu funcionamento, a nível de MAP e de LAYER, definidos na documentação do MapServer no item "Setting Up a WMS Server Using MapServer". 

MAP
EXTENT -38.7852 -8.31435 -34.7738 -6.01455
NAME "mapserver_wms"
SIZE 800 600
UNITS DD
OUTPUTFORMAT
NAME "png"
MIMETYPE "image/png"
DRIVER "AGG/PNG"
EXTENSION "png"
IMAGEMODE RGB
TRANSPARENT TRUE
END # OUTPUTFORMAT
PROJECTION
"init=epsg:4326"
END # PROJECTION
WEB
METADATA
"ows_enable_request" "*"
"wms_title" "mapserver_wms"
"wms_onlineresource" "http://localhost/cgi-bin/mapserv?map=/var/www/html/mapserver_wms/municipios.map&"
"ows_srs" "EPSG:3857 EPSG:4326 EPSG:4291 EPSG:900913"
"wms_feature_info_mime_type" "text/html"
END # METADATA
END # WEB
LAYER
NAME "municipios"
EXTENT -38.7852 -8.31435 -34.7738 -6.01455
TYPE POLYGON
CONNECTIONTYPE POSTGIS
CONNECTION "dbname='mapserver_wms' host=localhost port=5432 user='marcello' password='<mypass>' sslmode=disable"
DATA 'geom FROM "municipios" USING UNIQUE gid USING srid=4326'
TEMPLATE "template.html"
STATUS ON
METADATA
"ows_title" "municipios"
END # METADATA
PROJECTION
'init=epsg:4326'
END # PROJECTION
CLASS
NAME "Municípios"
STYLE
COLOR 85 255 127
OUTLINECOLOR 0 85 0
WIDTH 1.4
OPACITY 60
END # STYLE
END # CLASS
END # LAYER
END # MAP
view raw gistfile1.rb hosted with ❤ by GitHub


2 - Configuração do Template HTML para a requisição GetFeatureInfo:


Neste arquivo são definidos os dados que serão exibidos na janela de atributos através do GetFeatureInfo WMS Request. 

<!-- Mapserver Template -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mapserver Template</title>
</head>
<body>
<ul>
<li><strong>Município: </strong>[item name=nome]</li>
<li><strong>Código IBGE: </strong>[item name=geocodigo]</li>
<li><strong>Mesoregião: </strong>[item name=meso]</li>
<li><strong>Microregião: </strong>[item name=micro]</li>
</ul>
</body>
</html>
view raw template.html hosted with ❤ by GitHub

3 - Configuração do Leaflet:


Para habilitar esta funcionalidade  é necessário configurar a camada WMS no Leaflet, como é exibido a seguir:

var host = "http://localhost/cgi-bin/mapserv?";
var mapfile = "map=/var/www/html/mapserver_wms/municipios.map&";
var wms_server = host + mapfile;
var municipios = new L.tileLayer.wms(wms_server, {
layers: 'municipios',
format: 'image/png',
srs:"EPSG:4326",
transparent: true,
pointerCursor: true
}).addTo(map);
view raw gistfile1.js hosted with ❤ by GitHub
Já com a função IDENTIFY abaixo, é possível associar ao clique do mouse uma requisição GetFeatureInfo, através da obtenção das variáveis BBOX, WIDTH, HEIGHT, X e Y. Com elas é definida a variável URL que fará esta requisição ao servidor WMS e trará o resultado de forma assíncrona com método $.ajax do jQuery.

function Identify (e) {
var BBOX = map.getBounds().toBBoxString();
var WIDTH = map.getSize().x;
var HEIGHT = map.getSize().y;
var X = map.layerPointToContainerPoint(e.layerPoint).x;
var Y = map.layerPointToContainerPoint(e.layerPoint).y;
var URL = wms_server + 'SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=municipios&QUERY_LAYERS=municipios&BBOX='+BBOX+'&FEATURE_COUNT=1&HEIGHT='+HEIGHT+'&WIDTH='+WIDTH+'&INFO_FORMAT=text%2Fhtml&SRS=EPSG%3A4326&X='+X+'&Y='+Y;
$.ajax({
url:URL,
datatype: "html",
type: "GET",
success: function(data) {
var popup = new L.popup({
maxWith: 300
});
popup.setContent(data);
popup.setLatLng(e.latlng);
map.openPopup(popup);
}
});
}
view raw gistfile1.js hosted with ❤ by GitHub
A página HTML contendo o Leaflet fica então desta forma:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Quick Start Guide Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/leaflet.css" />
<style>
#map { width: 800px; height: 600px; border: 1px solid #000; cursor: pointer; }
ul>li { font-size: 12px; }
</style>
</head>
<body>
<div id="map"></div>
<script src="js/leaflet.js"></script>
<script src="js/jquery-2.1.1.min.js"></script>
<script>
var map = L.map('map').setView([-7.1826, -36.7382], 8);
L.tileLayer('https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png', {
maxZoom: 18,
id: 'examples.map-i86knfo3'
}).addTo(map);
var host = "http://localhost/cgi-bin/mapserv?";
var mapfile = "map=/var/www/html/mapserver_wms/municipios.map&";
var wms_server = host + mapfile;
var municipios = new L.tileLayer.wms(wms_server, {
layers: 'municipios',
format: 'image/png',
srs:"EPSG:4326",
transparent: true,
pointerCursor: true
}).addTo(map);
map.addEventListener('click', Identify);
function Identify (e) {
var BBOX = map.getBounds().toBBoxString();
var WIDTH = map.getSize().x;
var HEIGHT = map.getSize().y;
var X = map.layerPointToContainerPoint(e.layerPoint).x;
var Y = map.layerPointToContainerPoint(e.layerPoint).y;
var URL = wms_server + 'SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&LAYERS=municipios&QUERY_LAYERS=municipios&BBOX='+BBOX+'&FEATURE_COUNT=1&HEIGHT='+HEIGHT+'&WIDTH='+WIDTH+'&INFO_FORMAT=text%2Fhtml&SRS=EPSG%3A4326&X='+X+'&Y='+Y;
$.ajax({
url:URL,
datatype: "html",
type: "GET",
success: function(data) {
var popup = new L.popup({
maxWith: 300
});
popup.setContent(data);
popup.setLatLng(e.latlng);
map.openPopup(popup);
}
});
}
</script>
</body>
</html>
view raw index.html hosted with ❤ by GitHub

4 - Resultado:


Ao clicar em um município, é exibido uma janela contendo os atributos, como mostra a figura abaixo:


Você pode baixar os códigos deste exemplo neste link.

Sugestões de Leitura:


3 comentários:

raffaeldantas disse...

olá professor,

baixei os arquivos mas não consegui fazer a camada wms aparecer. tentei fazer com shp e não com postgres.
o console do firefox diz o seguinte erro:

GET http://localhost/cgi-bin/mapserv [HTTP/1.1 404 Not Found 0 ms]

URL do pedido: http://localhost/cgi-bin/mapserv?map=/var/www/html/mapserver_wms/municipios.map&&SERVICE=WMS&REQUEST=GetMap&VERSION=1.1.1&LAYERS=municipios&STYLES=&FORMAT=image%2Fpng&TRANSPARENT=true&HEIGHT=256&WIDTH=256&SRS=EPSG%3A3857&POINTERCURSOR=true&BBOX=-10018754.171394622,-5009377.085697309,-7514065.628545966,-2504688.542848655
Método do pedido: GET
Código do status: HTTP/1.1 404 Not Found

Marcello Benigno disse...

Olá Rafael,

Observe que eu estou utilizando o Linux. Se você estiver utilizando Windows, altere o nome do CGI do mapserver para "mapserv.exe", tanto no mapfile quanto no arquivo HTML, no código javascript. Também verifique os caminhos dos diretórios, feito isso, deve funcionar normalmente.

Valengo's disse...

Obrigada! Me ajudou aqui :)