只有栅格图层是没有意义的,我们需要矢量图层才能实现自己的功能。这里实现的功能是获取公司外派的外卖员的位置,并显示他们最后一次按动汇报器按钮的时刻,以便公司掌握这些员工的交通安全、买卖效率。员工ID 是唯一的工号,姓名、正在执行的送外卖对象的电话、地址。下面,我们来实现这个Web应用。
<0>、数据环境
数据使用PostgreSQL 视图发布,该视图主要字段:
1、id , 员工ID
2、s_tel, 员工电话
3、t_tel , 外卖对象电话
4、t_addr, 外卖对象位置
5、d_starttm 任务开始时刻
6、lat, 当前经度
7、lon ,当前纬度
8、GEO类型摩卡托坐标字段
CREATE TABLE express_status ( id character varying(16) NOT NULL, s_tel character varying(20), t_tel character varying(20), t_addr character varying(64), d_starttm timestamp with time zone, lat double precision NOT NULL DEFAULT 0, lon double precision NOT NULL DEFAULT 0, CONSTRAINT pk_id PRIMARY KEY (id ) ) WITH ( OIDS=FALSE );
CREATE OR REPLACE VIEW view_express_status AS SELECT express_status.id, express_status.s_tel, express_status.t_tel, express_status.t_addr, express_status.d_starttm, express_status.lat, express_status.lon, st_transform(st_setsrid(st_makepoint(express_status.lon, express_status.lat), 4326), 900913) AS geobj FROM express_status;
<1>、安装配置GeoSevrer
下载GeoServer到本地,这里是2.1.4版本。下载后,解压到喜欢的地方待用。这里设置在 ~/bin/geoserver-2.1.4下。
sudo nano /etc/environment
设置 JAVA_HOME 环境变量到安装的JAVA虚拟机(JVM)路径,/usr/lib/jvm/default-java
JAVA_HOME="/usr/lib/jvm/default-java"
设置GEOSERVER_HOME 到安装路径
GEOSERVER_HOME="/home/goldenhawking/bin/geoserver-2.1.4"
直接运行 $(GEOSERVER_HOME)/bin/startup.sh 即可启动。stop终止,很方便的。
测试,访问 127.0.0.1:8080/geoserver/web/出现起始页面即可。初始用户密码 admin : geoserver
<2> 创建新的数据服务
1、 在 Web页面上首先创建一个workspace 叫 expresstatus ,uri也是 expresstatus
2、创建 Stores,名字叫 storexpresstatus,工作空间是 expresstatus, 数据库连接写好后,会列出数据库里的表,选择我们的视图view_express_status,并publish
3、系统调到创建图层的界面,主要注意的是,全球摩卡托的 bbox 为 正负20037508.342789,换算过去纬度为正负85
测试地址http://192.168.1.100:8080/geoserver/expresstatus/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=expresstatus:view_express_status&maxFeatures=1,如果看到 下面的类似东西,就好啦:
这张视图存储在PostgreSQL服务器上,但是位于另外一台机器。我们的GeoServer也位于另外一台机器,所以,首先要做的是突破 Ajax 默认拒绝异地XMLRequest的安全限制。根据OpenLayers 2.10 Beginner's Guide - E. Hazzard 书中所说,到http://trac.osgeo.org/openlayers/browser/trunk/openlayers/examples/proxy.cgi下载proxy.cgi,拷到自己的/usr/lib/cgi-bin下,别忘了把geoserver 所在的ip 追加到proxy.cgi准许访问网站中。
# Designed to prevent Open Proxy type stuff. 17 18 allowedHosts = ['www.openlayers.org', 'openlayers.org', 19 'labs.metacarta.com', 'world.freemap.in', 20 'prototype.openmnnd.org', 'geo.openplans.org', 21 'sigma.openplans.org', 'demo.opengeo.org', 22 'www.openstreetmap.org', 'sample.azavea.com', 23 'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080', 24 'vmap0.tiles.osgeo.org', '192.168.1.100:8080']
OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url=';
这样,在下载时,Ajax即可访问与脚本所在位置不同的东东。
<4> 实现相关网页脚本
在前面章节的基础上,我们加入一个图层,并设置好单击的事件为在侧边的DIV上显示详细的信息。看看Init
function init() { OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url=' map = new OpenLayers.Map("map", { controls: [ new OpenLayers.Control.Navigation(), new OpenLayers.Control.PanZoomBar(), new OpenLayers.Control.Permalink(), new OpenLayers.Control.ScaleLine({ geodesic: true }), new OpenLayers.Control.Permalink('permalink'), //new OpenLayers.Control.KeyboardDefaults(), new OpenLayers.Control.LayerSwitcher(), new OpenLayers.Control.Attribution()], maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34), maxResolution: 156543.0339, numZoomLevels: 19, units: 'm', projection: new OpenLayers.Projection("EPSG:900913"), displayProjection: new OpenLayers.Projection("EPSG:4326") }); // This is the layer that uses the locally stored tiles var newLayer = new OpenLayers.Layer.OSM("OSM Tiles", "/osm_tiles2/${z}/${x}/${y}.png", { numZoomLevels: 19, transitionEffect: "resize" }); map.addLayer(newLayer); var vector_layer = new OpenLayers.Layer.Vector('Express Status', { projection: new OpenLayers.Projection('EPSG:900913'), protocol: new OpenLayers.Protocol.HTTP({ url: 'http://192.168.1.100:8080/geoserver/expresstatus/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=expresstatus:view_express_status&maxFeatures=50', format: new OpenLayers.Format.GML({ extractAttributes:true }) }), strategies: [new OpenLayers.Strategy.Fixed()] }); var vector_style = new OpenLayers.Style({ 'fillOpacity': .4, 'strokeColor': '#aaee77', 'strokeWidth': 3, 'pointRadius': 8 }); var vector_style_select = new OpenLayers.Style({ 'fillOpacity': .9, 'strokeColor': '#aaee77', 'strokeWidth': 3, 'pointRadius': 8 }); var vector_style_map = new OpenLayers.StyleMap({ 'default': vector_style, 'select': vector_style_select }); vector_layer.styleMap = vector_style_map; map.addLayer(vector_layer); map.addControl(new OpenLayers.Control.EditingToolbar(vector_layer)); //Add a select feature control var select_feature_control = new OpenLayers.Control.SelectFeature(vector_layer); map.addControl(select_feature_control); select_feature_control.activate(); //Activate the control map.addControl(new OpenLayers.Control.Graticule({ visible: false })); var mousepos = new OpenLayers.Control.MousePosition({ div: document.getElementById('mousepos_div') }); map.addControl(mousepos); map.addControl(new OpenLayers.Control.OverviewMap()); //map.addControl(new OpenLayers.Control.NavToolbar()); map.layers[1].events.register('featureselected', this, OnFeatureSelected); map.layers[1].events.register('featureunselected', this, on_unselect_feature); var navigationT = new OpenLayers.Control.TouchNavigation({ dragPanOptions: { enableKinetic: true } }); map.addControl(navigationT); if (!map.getCenter()) { var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); map.setCenter(lonLat, zoom); } }
function OnFeatureSelected(event) { var info_div = document.getElementById('nodelist'); info_div.innerHTML = ''; //Store the clusters evt_selected = event.feature.attributes; //Loop through the cluster features for (var atn in evt_selected) { //Update the div with the info of the photos info_div.innerHTML += "<p>" + atn.toString()+":"+evt_selected[atn].toString() + "</p>"; } } function on_unselect_feature(event) { //Store a reference to the element var info_div = document.getElementById('nodelist'); //Clear out the div info_div.innerHTML = 'Please Select a Point.'; }
完整网页代码
<html> <head> <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8"> <title>OSM Local Tiles</title> <link rel="stylesheet" href="/openlayers/theme/default/style.css" type="text/css" /> <script src="/openlayers/OpenLayers.js"></script> <script type="text/javascript"> // Start position for the map (hardcoded here for simplicity) var lat = 31.27386; var lon = 121.48132; var zoom = 4; var evt_selected; var map; //complex object of type OpenLayers.Map //Initialise the 'map' object function init() { OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url=' map = new OpenLayers.Map("map", { controls: [ new OpenLayers.Control.Navigation(), new OpenLayers.Control.PanZoomBar(), new OpenLayers.Control.Permalink(), new OpenLayers.Control.ScaleLine({ geodesic: true }), new OpenLayers.Control.Permalink('permalink'), //new OpenLayers.Control.KeyboardDefaults(), new OpenLayers.Control.LayerSwitcher(), new OpenLayers.Control.Attribution()], maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34), maxResolution: 156543.0339, numZoomLevels: 19, units: 'm', projection: new OpenLayers.Projection("EPSG:900913"), displayProjection: new OpenLayers.Projection("EPSG:4326") }); // This is the layer that uses the locally stored tiles var newLayer = new OpenLayers.Layer.OSM("OSM Tiles", "/osm_tiles2/${z}/${x}/${y}.png", { numZoomLevels: 19, transitionEffect: "resize" }); map.addLayer(newLayer); var vector_layer = new OpenLayers.Layer.Vector('Express Status', { projection: new OpenLayers.Projection('EPSG:900913'), protocol: new OpenLayers.Protocol.HTTP({ url: 'http://192.168.1.100:8080/geoserver/expresstatus/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=expresstatus:view_express_status&maxFeatures=50', format: new OpenLayers.Format.GML({ extractAttributes:true }) }), strategies: [new OpenLayers.Strategy.Fixed()] }); var vector_style = new OpenLayers.Style({ 'fillOpacity': .4, 'strokeColor': '#aaee77', 'strokeWidth': 3, 'pointRadius': 8 }); var vector_style_select = new OpenLayers.Style({ 'fillOpacity': .9, 'strokeColor': '#aaee77', 'strokeWidth': 3, 'pointRadius': 8 }); var vector_style_map = new OpenLayers.StyleMap({ 'default': vector_style, 'select': vector_style_select }); vector_layer.styleMap = vector_style_map; map.addLayer(vector_layer); map.addControl(new OpenLayers.Control.EditingToolbar(vector_layer)); //Add a select feature control var select_feature_control = new OpenLayers.Control.SelectFeature(vector_layer); map.addControl(select_feature_control); select_feature_control.activate(); //Activate the control map.addControl(new OpenLayers.Control.Graticule({ visible: false })); var mousepos = new OpenLayers.Control.MousePosition({ div: document.getElementById('mousepos_div') }); map.addControl(mousepos); map.addControl(new OpenLayers.Control.OverviewMap()); //map.addControl(new OpenLayers.Control.NavToolbar()); map.layers[1].events.register('featureselected', this, OnFeatureSelected); map.layers[1].events.register('featureunselected', this, on_unselect_feature); var navigationT = new OpenLayers.Control.TouchNavigation({ dragPanOptions: { enableKinetic: true } }); map.addControl(navigationT); if (!map.getCenter()) { var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); map.setCenter(lonLat, zoom); } } function OnFeatureSelected(event) { var info_div = document.getElementById('nodelist'); info_div.innerHTML = ''; //Store the clusters evt_selected = event.feature.attributes; //Loop through the cluster features for (var atn in evt_selected) { //Update the div with the info of the photos info_div.innerHTML += "<p>" + atn.toString()+":"+evt_selected[atn].toString() + "</p>"; } } function on_unselect_feature(event) { //Store a reference to the element var info_div = document.getElementById('nodelist'); //Clear out the div info_div.innerHTML = 'Please Select a Point.'; } function Button_Mark_onclick() { var lat = Text_lat.value; var lon = Text_lon.value; var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var current_zoom = map.zoom; map.setCenter(lonLat, current_zoom); var point = new OpenLayers.Geometry.Point(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var feature_point = new OpenLayers.Feature.Vector(point); map.layers[1].addFeatures([feature_point]); } function Button_Goto_onclick() { var lat = Text_lat.value; var lon = Text_lon.value; var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var current_zoom = map.zoom; map.setCenter(lonLat, current_zoom); } function Button_DMSMark_onclick() { var lat = parseFloat(Text_DMS_Lat_Deg.value.toString()) + parseFloat(Text_DMS_Lat_Min.value.toString()) / 60.0 + parseFloat(Text_DMS_Lat_Sec.value.toString()) / 3600.0; var lon = parseFloat(Text_DMS_Lon_deg.value.toString()) + parseFloat(Text_DMS_Lon_MIn.value.toString()) / 60.0 + parseFloat(Text_DMS_Lon_Sec.value.toString()) / 3600.0; Text_lat.value = lat; Text_lon.value = lon; var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var current_zoom = map.zoom; map.setCenter(lonLat, current_zoom); var point = new OpenLayers.Geometry.Point(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var feature_point = new OpenLayers.Feature.Vector(point); map.layers[1].addFeatures([feature_point]); } function Button_DMSGoto_onclick() { var lat = parseFloat(Text_DMS_Lat_Deg.value.toString()) + parseFloat(Text_DMS_Lat_Min.value.toString()) / 60.0 + parseFloat(Text_DMS_Lat_Sec.value.toString()) / 3600.0; var lon = parseFloat(Text_DMS_Lon_deg.value.toString()) + parseFloat(Text_DMS_Lon_MIn.value.toString()) / 60.0 + parseFloat(Text_DMS_Lon_Sec.value.toString()) / 3600.0; var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()); var current_zoom = map.zoom; map.setCenter(lonLat, current_zoom); } </script> <style type="text/css"> .style1 { width: 100%; height: 29px; } .style2 { width: 100%; height: 90%; } #Text_DMS_Lat { width: 32px; } #Text_DMS_Lat_Deg { width: 32px; } #Text_DMS_Lat_min { width: 32px; } #Text_DMS_Lat_sec { width: 32px; } #Text_DMS_Lon_deg { width: 32px; } #Text_DMS_Lon_MIn { width: 32px; } #Text_DMS_Lon_Sec { width: 32px; } </style> </head> <!-- body.onload is called once the page is loaded (call the 'init' function) --> <body onload="init();"> <table class="style2"> <tr> <td width="80%"> <div style="width: 100%; height: 100%" id="map"> </div> </td> <td width="20%"> <div style="width: 100%; height: 100%" id="nodelist"> </div> </td> </tr> </table> <!-- define a DIV into which the map will appear. Make it take up the whole window --> <div style="width: 100%; height: 5%" id="mousepos_div"> </div> <table class="style1"> <tr> <td> 小数纬度:<input id="Text_lat" type="text" />经度:<input id="Text_lon" type="text" /><input id="Button_Mark" type="button" value="标记" onclick="return Button_Mark_onclick()" /><input id="Button_Goto" type="button" value="前往" onclick="return Button_Goto_onclick()" /></td> <td> </td> <td> 纬度 :<input id="Text_DMS_Lat_Deg" type="text" />度<input id="Text_DMS_Lat_Min" type="text" />分<input id="Text_DMS_Lat_Sec" type="text" />秒.经度:<input id="Text_DMS_Lon_deg" type="text" />度<input id="Text_DMS_Lon_MIn" type="text" />分<input id="Text_DMS_Lon_Sec" type="text" />秒</td> <td> <input id="Button_DMSMark" type="button" value="标记" onclick="return Button_DMSMark_onclick()" /><input id="Button_DMSGoto" type="button" value="前往" onclick="return Button_DMSGoto_onclick()" /></td> <td> </td> <td> </td> <td> </td> </tr> </table> </body> </html>
下一篇,将开始介绍 基于native C++的 C/S 架构客户端的开发以及应用