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: