Возможны следующие причины ошибки:
Вы можете:
Вы также можете:
Воспользоваться поиском
Сообщить нам о недоступой странице по e-mail или воспользовавшись формой быстрой отправки комментария.
© GIS-Lab и авторы, 2002-2021. При использовании материалов сайта, ссылка на GIS-Lab и авторов обязательна. Содержание материалов - ответственность авторов. (подробнее).
Рассмотрен вариант организации поиска и подсветки найденных объектов с помощью OpenLayers.
Обсудить в форуме Комментариев 32
Поиск объектов по атрибутике и масштабирование на них является распространенной задачей при создании как настольных ГИС, так и веб-сервисов. Эта статья рассмотривает одно из возможных решений для веб-приложения.
Оглавление
Предположим, что у нас есть векторный слой данных, который бы мы хотели опубликовать в Интернет и предоставить пользователю возможность осуществлять поиск объектов по его атрибутике. Для примера воспользуемся слоем населенных пунктов settlements из открытого набора данных Geosample, который хранится в базе данных PostGIS. Будем осуществлять поиск объектов по полю "name".
OpenLayers не позволяет визуализировать данные непосредственно из PostGIS, выходом из этой ситуации является опубликование слоя в качестве WMS-сервиса. Воспользуемся таким сервисом, созданным в ходе работы над проектом Geosample: http://gis-lab.info:8180/geoserver/wms, среди слоёв которого присутствует и необходимый нам settlements. В нашем примере мы будем использовать его в качестве подложки, также подключенной как WMS, которая изменяться никоим образом не будет. Вы можете использовать свою подложку.
Для подсветки найденных объектов создадим собственный WMS-сервис на базе MapServer, содержащий один слой, который будет формироваться на основе тех же данных (PostGIS), что и WMS-сервис из геосемпла, но динамически, в ходе выполнения запроса, и содержать контура найденных объектов, обведенные красным цветом.
Содержимое map-файла layer.map:
MAP STATUS ON IMAGETYPE PNG EXTENT 82 54 84 56 SIZE 400 300 FONTSET "fonts/fonts.list" WEB IMAGEPATH "/usr/local/www/gis-lab/data/tmp/" IMAGEURL "/tmp/" METADATA wms_title "OpenLayears search example" wms_abstract "OpenLayears search example" wms_srs "EPSG:4326" wms_feature_info_mime_type "text/html" END END PROJECTION "init=epsg:4326" END LAYER NAME "selected" CONNECTIONTYPE postgis CONNECTION "user=guest password=guest dbname=geosample host=gis-lab.info" DATA "the_geom from (%SQL%) as newtable using unique gid using srid=4326" TYPE POLYGON CLASS STYLE OUTLINECOLOR 255 0 0 ANTIALIAS TRUE WIDTH 2 END END METADATA wms_srs "EPSG:4326" END END END
Более подробное описание работы MapServer c данными PosGIS можно найти в статье Визуализация данных PostGIS в MapServer.
После того, как завершена настройка WMS сервера, переходим к настройке пользовательского интерфейса, представляющего собой HTML-страницу. Возможность выбора атрибута, в нашем случае названия населенного пункта (поле "name"), может предоставляться пользователю, например, посредством выпадающего списка, организованного следующим образом:
<form name='form'><select name='name'> <option value=''>Select one</option> <option value=2200800000200 >Акутиха</option> <option value=2200000200000 >Алейск</option> <option value=2200300000100 >Алтайский</option> <option value=2204700000300 >Алтайское</option> ...
где "value" - КЛАДР код населенного пункта (поле "code" слоя settlements). Построение подобного списка легко автоматизировать, например, с помощью PHP. После размещения на странице выпадающего списка, добавим кнопку по нажатию которой будет осуществляться поиск и непосредственно карту:
<html>
<head> <script src="http://openlayers.org/api/OpenLayers.js"></script> <script src="http://gis-lab.info/programs/js/ol-search.js"></script> ... </head>
<body onLoad="init()"> <div id="map"></div> <input type="button" value="Search" onclick="getext()"> ...
http://openlayers.org/api/OpenLayers.js - ссылка на библиотеку OpenLayers, ol-search.js - файл, содержащий 3 функции:
Содержимое файла ol-search.js:
function init() { map = new OpenLayers.Map("map"); sel = new OpenLayers.Layer.WMS( "Selected", "http://gis-lab.info/cgi-bin/mapserv?", {map:"/usr/local/www/gis-lab/data/programs/mapserver/ol-search/layer.map",layers: 'selected',sql:"select * from settlements where name='-1'",transparent:"true"},{singleTile:true}); geosample = new OpenLayers.Layer.WMS( "Selected", "http://gis-lab.info:8180/geoserver/wms", {layers:"geosample:ecoregions,geosample:road-l-osm,geosample:settlements",transparent:"false"}); map.addLayers([geosample,sel]); var bounds = new OpenLayers.Bounds.fromString('82,54,84,56'); map.zoomToExtent(bounds); } function init_AJAX() { try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {} //IE try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {} //IE try { return new XMLHttpRequest(); } catch(e) {} //Native Javascript alert("XMLHttpRequest not supported"); return null; }; function getext() { var req = init_AJAX(); req.open("GET", "http://gis-lab.info/programs/php/ol-search-getext.php?name="+encodeURIComponent(document.form.name.options[document.form.name.options.selectedIndex].value)); req.onreadystatechange = function () { if (req.readyState==4) { if (req.status==200) { var response = req.responseText.split("|"); sel.mergeNewParams({sql:response[0]}); var bounds = new OpenLayers.Bounds.fromString(response[1]); map.zoomToExtent(bounds); } } }; req.send(null); }
Рассмотрим содержимое данного файла более подробно.
init()
Создаём экземпляр карты:
map = new OpenLayers.Map("map");
Затем инициализируем слой населенных пунктов (переменная geosample) и слой обводки объектов (переменная sel) изначально пустой, поскольку в качестве подстановочного поля %SQL% серверу передается выражение "select * from settlements where name='-1'", которому, очевидно, в таблице settlements не удовлетворяет ни одна запись:
geosample = new OpenLayers.Layer.WMS(...); sel = new OpenLayers.Layer.WMS(...,{...,sql:"select * from settlements where name='-1'"},...);
Важное замечание: при пересылке параметров серверу OpenLayers переводит все параметры в верхний регистр (map,layers,sql,transparent будут переданы как MAP, LAYERS, SQL, TRANSPARENT), поэтому в качестве подстановочного поля в map-файле используется %SQL%, а не %sql%.
Добавляем слои на карту и устанавливаем нужный охват:
map.addLayers([geosample,sel]); var bounds = new OpenLayers.Bounds.fromString('82,54,84,56'); map.zoomToExtent(bounds);
init_AJAX()
Данная функция отвечает за создание экземпляра объекта XMLHttpRequest способом, определяемым типом браузера. XMLHttpRequest — набор API, используемый в языках JavaScript, JScript, VBScript и им подобных для пересылки различных данных по HTTP-протоколу между браузером и веб-сервером. Позволяет осуществлять HTTP-запросы к удаленному серверу без необходимости перезагружать страницу.
getext()
Создаём экземпляр объекта XMLHttpRequest:
var req = init_AJAX();
и передаём асинхронный запрос методом GET сереверному скрипту getext.php:
req.open("GET", "http://gis-lab.info/programs/php/ol-search-getext.php?name="+encodeURIComponent(document.form.name.options[document.form.name.options.selectedIndex].value));
Асинхронность заключается в том, что клиентское приложение не дожидаается ответа от сервера, а продолжает свою работу. Как только с сервера приходит ответ, он заносится в массив response. Серверный скрипт написан таким образом, что результатом его выполнения является строка SQL-запроса на поиск выбранного пользователем объекта и пространственный охват этого объекта, разделенные символом "|":
if (req.readyState==4) { if (req.status==200) { var response = req.responseText.split("|"); ... } } };
После чего слою sel передаётся подстановочное поле (которое затем отправляется на WMS сервер, который в свою очередь рендерит слой в соответствии с этим полем, в нашем случае - контура объектов) и устанавливается новый охват, соответствующий охвату найденных объектов:
sel.mergeNewParams({sql:response[0]}); var bounds = new OpenLayers.Bounds.fromString(response[1]); map.zoomToExtent(bounds);
Рассмотрим, что из себя представляет серверный скрипт, генерирующий подстановочное поле и вычисляющий охват запрашиваемых объектов getext.php:
<?php $dbh = pg_connect("host=gis-lab.info dbname=geosample user=guest password=guest") or die("Error in connection: " . pg_last_error()); $code = $_REQUEST['name']; $str = "SELECT * FROM settlements WHERE code='".$code."'"; echo $str."|"; $result = pg_query($dbh, "select ST_XMin(ST_Union(the_geom)) as st_xmin, ST_YMin(ST_Union(the_geom)) as st_ymin,ST_XMax(ST_Union(the_geom)) as st_xmax, ST_YMax(ST_Union(the_geom)) as st_ymax from ($str) AS foo"); $row = pg_fetch_array($result); if (!empty($row['st_xmin'])&&!empty($row['st_ymin'])&&!empty($row['st_xmax'])&&!empty($row['st_ymax'])){ echo $row['st_xmin'].",".$row['st_ymin'].",".$row['st_xmax'].",".$row['st_ymax']; } else { echo "82,54,84,56"; } ?>
Соединяемся с базой данных и запрашиваем значение переменной из URL:
$dbh = pg_connect("host=gis-lab.info dbname=geosample user=guest password=guest") or die("Error in connection: " . pg_last_error()); $code = $_REQUEST['name'];
В соответствии с названием запрашиваемого объекта генерируем SQL запрос и добавляем после него символ "|":
$str = "SELECT * FROM settlements WHERE code='".$code."'"; echo $str."|";
Используя функции PostGIS ST_XMin,ST_YMin,ST_XMax,ST_YMax, вычисляем охват запрашиваемого объекта:
$result = pg_query($dbh, "select ST_XMin(ST_Union(the_geom)) as st_xmin, ST_YMin(ST_Union(the_geom)) as st_ymin,ST_XMax(ST_Union(the_geom)) as st_xmax, ST_YMax(ST_Union(the_geom)) as st_ymax from ($str) AS foo");
Выводим рассчитанный охват, либо полный охват карты, если не найденны объекты с выбранным именем (например, выбран элемент выпадающего списка Select one):
$row = pg_fetch_array($result); if (!empty($row['st_xmin'])&&!empty($row['st_ymin'])&&!empty($row['st_xmax'])&&!empty($row['st_ymax'])){ echo $row['st_xmin'].",".$row['st_ymin'].",".$row['st_xmax'].",".$row['st_ymax']; } else { echo "82,54,84,56"; }
Примеры результата выполнения getext.php:
SELECT * FROM settlements WHERE code='2200000800000'|83.8799743652344,53.3685569763184,84.0150527954102,53.4700012207031 SELECT * FROM settlements WHERE code='5400900002500'|78.4868316650391,53.5798873901367,78.5268630981445,53.6058883666992 SELECT * FROM settlements WHERE code='2202200001200'|82.6611251831055,51.7036590576172,82.7050018310547,51.7301406860352
Итак подводя итог всему вышесказанному, представим порядок работы нашего приложения:
Обсудить в форуме Комментариев 32
Последнее обновление: September 09 2021
Дата создания: 24.04.2010
Автор(ы): Денис Рыков
© GIS-Lab и авторы, 2002-2021. При использовании материалов сайта, ссылка на GIS-Lab и авторов обязательна. Содержание материалов - ответственность авторов. (подробнее).