一步步DIY: OSM-Web服务器(五) GeoServer与矢量叠加图层

只有栅格图层是没有意义的,我们需要矢量图层才能实现自己的功能。这里实现的功能是获取公司外派的外卖员的位置,并显示他们最后一次按动汇报器按钮的时刻,以便公司掌握这些员工的交通安全、买卖效率。员工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类型摩卡托坐标字段

  1. CREATE TABLE express_status  
  2. (  
  3.   id character varying(16) NOT NULL,  
  4.   s_tel character varying(20),  
  5.   t_tel character varying(20),  
  6.   t_addr character varying(64),  
  7.   d_starttm timestamp with time zone,  
  8.   lat double precision NOT NULL DEFAULT 0,  
  9.   lon double precision NOT NULL DEFAULT 0,  
  10.   CONSTRAINT pk_id PRIMARY KEY (id )  
  11. )  
  12. WITH (  
  13.   OIDS=FALSE  
  14. );  

  1. CREATE OR REPLACE VIEW view_express_status AS  
  2.  SELECT express_status.id, express_status.s_tel, express_status.t_tel, express_status.t_addr, express_status.d_starttm, express_status.lat,   
  3. express_status.lon, st_transform(st_setsrid(st_makepoint(express_status.lon, express_status.lat), 4326), 900913) AS geobj  
  4.    FROM express_status;        

           第八个字段,摩卡托投影的字段非常重要,使用 ST_Transform(ST_SetSRID(ST_MakePoint(lon,lat),4326),900913) 把经纬度的wgs84变为摩卡托的900913投影系,否则,在 OpenLayers 上就需要做很多的设置。

<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&amp;version=1.0.0&request=GetFeature&typeName=expresstatus:view_express_status&maxFeatures=1,如果看到 下面的类似东西,就好啦:


<3> 为 OpenLays设置代理服务

     这张视图存储在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准许访问网站中。

  1. # Designed to prevent Open Proxy type stuff.  
  2. 17    
  3. 18  allowedHosts = ['www.openlayers.org''openlayers.org',   
  4. 19                  'labs.metacarta.com''world.freemap.in',   
  5. 20                  'prototype.openmnnd.org''geo.openplans.org',  
  6. 21                  'sigma.openplans.org''demo.opengeo.org',  
  7. 22                  'www.openstreetmap.org''sample.azavea.com',  
  8. 23                  'v2.suite.opengeo.org''v-swe.uni-muenster.de:8080',   
  9. 24                  'vmap0.tiles.osgeo.org''192.168.1.100:8080']  

在 OpenLayers 的 init里,写入

OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url=';

这样,在下载时,Ajax即可访问与脚本所在位置不同的东东。

<4>  实现相关网页脚本

在前面章节的基础上,我们加入一个图层,并设置好单击的事件为在侧边的DIV上显示详细的信息。看看Init

[javascript] view plaincopy
  1. function init() {  
  2.     OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url='  
  3.     map = new OpenLayers.Map("map", {  
  4.         controls: [  
  5.             new OpenLayers.Control.Navigation(),  
  6.             new OpenLayers.Control.PanZoomBar(),  
  7.             new OpenLayers.Control.Permalink(),  
  8.             new OpenLayers.Control.ScaleLine({ geodesic: true }),  
  9.             new OpenLayers.Control.Permalink('permalink'),  
  10.             //new OpenLayers.Control.KeyboardDefaults(),  
  11.             new OpenLayers.Control.LayerSwitcher(),  
  12.             new OpenLayers.Control.Attribution()],  
  13.         maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),  
  14.         maxResolution: 156543.0339,  
  15.         numZoomLevels: 19,  
  16.         units: 'm',  
  17.         projection: new OpenLayers.Projection("EPSG:900913"),  
  18.         displayProjection: new OpenLayers.Projection("EPSG:4326")  
  19.     });  
  20.   
  21.     // This is the layer that uses the locally stored tiles  
  22.     var newLayer = new OpenLayers.Layer.OSM("OSM Tiles""/osm_tiles2/${z}/${x}/${y}.png", { numZoomLevels: 19, transitionEffect: "resize" });  
  23.     map.addLayer(newLayer);  
  24.   
  25.     var vector_layer = new OpenLayers.Layer.Vector('Express Status', {  
  26.         projection: new OpenLayers.Projection('EPSG:900913'),  
  27.         protocol: new OpenLayers.Protocol.HTTP({  
  28.         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',  
  29.         format: new OpenLayers.Format.GML({  
  30.                 extractAttributes:true  
  31.             })  
  32.         }),  
  33.         strategies: [new OpenLayers.Strategy.Fixed()]  
  34.     });  
  35.   
  36.     var vector_style = new OpenLayers.Style({  
  37.         'fillOpacity': .4,  
  38.         'strokeColor''#aaee77',  
  39.         'strokeWidth': 3,  
  40.         'pointRadius': 8  
  41.     });  
  42.     var vector_style_select = new OpenLayers.Style({  
  43.         'fillOpacity': .9,  
  44.         'strokeColor''#aaee77',  
  45.         'strokeWidth': 3,  
  46.         'pointRadius': 8  
  47.     });  
  48.     var vector_style_map = new OpenLayers.StyleMap({  
  49.         'default': vector_style,  
  50.         'select': vector_style_select  
  51.     });  
  52.     vector_layer.styleMap = vector_style_map;  
  53.     map.addLayer(vector_layer);  
  54.     map.addControl(new OpenLayers.Control.EditingToolbar(vector_layer));  
  55.   
  56.     //Add a select feature control  
  57.     var select_feature_control = new OpenLayers.Control.SelectFeature(vector_layer);  
  58.     map.addControl(select_feature_control);  
  59.     select_feature_control.activate();  
  60.   
  61.     //Activate the control  
  62.     map.addControl(new OpenLayers.Control.Graticule({ visible: false }));  
  63.     var mousepos = new OpenLayers.Control.MousePosition({ div: document.getElementById('mousepos_div') });  
  64.     map.addControl(mousepos);  
  65.   
  66.     map.addControl(new OpenLayers.Control.OverviewMap());  
  67.     //map.addControl(new OpenLayers.Control.NavToolbar());  
  68.   
  69.     map.layers[1].events.register('featureselected'this, OnFeatureSelected);  
  70.     map.layers[1].events.register('featureunselected'this, on_unselect_feature);  
  71.      
  72.     var navigationT = new OpenLayers.Control.TouchNavigation({  
  73.         dragPanOptions: {  
  74.             enableKinetic: true  
  75.         }  
  76.     });  
  77.     map.addControl(navigationT);  
  78.      
  79.     if (!map.getCenter()) {  
  80.         var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  81.         map.setCenter(lonLat, zoom);  
  82.   
  83.     }  
  84. }  

还有单击的事件,枚举所有的属性并显示
[javascript] view plaincopy
  1. function OnFeatureSelected(event) {  
  2.     var info_div = document.getElementById('nodelist');  
  3.     info_div.innerHTML = '';  
  4.     //Store the clusters  
  5.     evt_selected = event.feature.attributes;  
  6.     //Loop through the cluster features  
  7.      for (var atn in evt_selected) {  
  8.          //Update the div with the info of the photos  
  9.          info_div.innerHTML += "<p>"  
  10.              + atn.toString()+":"+evt_selected[atn].toString()  
  11.              + "</p>";  
  12.      }  
  13. }  
  14. function on_unselect_feature(event) {  
  15.     //Store a reference to the element  
  16.     var info_div = document.getElementById('nodelist');  
  17.     //Clear out the div  
  18.     info_div.innerHTML = 'Please Select a Point.';  
  19. }  

网页:


完整网页代码

  1. <html>  
  2. <head>  
  3.     <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8">  
  4.     <title>OSM Local Tiles</title>  
  5.     <link rel="stylesheet" href="/openlayers/theme/default/style.css"  
  6.         type="text/css" />  
  7.     <script src="/openlayers/OpenLayers.js"></script>  
  8.     <script type="text/javascript">  
  9.         // Start position for the map (hardcoded here for simplicity)  
  10.         var lat = 31.27386;  
  11.         var lon = 121.48132;  
  12.         var zoom = 4;  
  13.         var evt_selected;  
  14.         var map; //complex object of type OpenLayers.Map  
  15.         //Initialise the 'map' object  
  16.         function init() {  
  17.             OpenLayers.ProxyHost = '/cgi-bin/proxy.cgi?url='  
  18.             map = new OpenLayers.Map("map", {  
  19.                 controls: [  
  20.                     new OpenLayers.Control.Navigation(),  
  21.                     new OpenLayers.Control.PanZoomBar(),  
  22.                     new OpenLayers.Control.Permalink(),  
  23.                     new OpenLayers.Control.ScaleLine({ geodesic: true }),  
  24.                     new OpenLayers.Control.Permalink('permalink'),  
  25.                     //new OpenLayers.Control.KeyboardDefaults(),  
  26.                     new OpenLayers.Control.LayerSwitcher(),  
  27.                     new OpenLayers.Control.Attribution()],  
  28.                 maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),  
  29.                 maxResolution: 156543.0339,  
  30.                 numZoomLevels: 19,  
  31.                 units: 'm',  
  32.                 projection: new OpenLayers.Projection("EPSG:900913"),  
  33.                 displayProjection: new OpenLayers.Projection("EPSG:4326")  
  34.             });  
  35.   
  36.             // This is the layer that uses the locally stored tiles  
  37.             var newLayer = new OpenLayers.Layer.OSM("OSM Tiles", "/osm_tiles2/${z}/${x}/${y}.png", { numZoomLevels: 19, transitionEffect: "resize" });  
  38.             map.addLayer(newLayer);  
  39.   
  40.             var vector_layer = new OpenLayers.Layer.Vector('Express Status', {  
  41.                 projection: new OpenLayers.Projection('EPSG:900913'),  
  42.                 protocol: new OpenLayers.Protocol.HTTP({  
  43.                 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',  
  44.                 format: new OpenLayers.Format.GML({  
  45.                         extractAttributes:true  
  46.                     })  
  47.                 }),  
  48.                 strategies: [new OpenLayers.Strategy.Fixed()]  
  49.             });  
  50.   
  51.             var vector_style = new OpenLayers.Style({  
  52.                 'fillOpacity': .4,  
  53.                 'strokeColor': '#aaee77',  
  54.                 'strokeWidth': 3,  
  55.                 'pointRadius': 8  
  56.             });  
  57.             var vector_style_select = new OpenLayers.Style({  
  58.                 'fillOpacity': .9,  
  59.                 'strokeColor': '#aaee77',  
  60.                 'strokeWidth': 3,  
  61.                 'pointRadius': 8  
  62.             });  
  63.             var vector_style_map = new OpenLayers.StyleMap({  
  64.                 'default': vector_style,  
  65.                 'select': vector_style_select  
  66.             });  
  67.             vector_layer.styleMap = vector_style_map;  
  68.             map.addLayer(vector_layer);  
  69.             map.addControl(new OpenLayers.Control.EditingToolbar(vector_layer));  
  70.   
  71.             //Add a select feature control  
  72.             var select_feature_control = new OpenLayers.Control.SelectFeature(vector_layer);  
  73.             map.addControl(select_feature_control);  
  74.             select_feature_control.activate();  
  75.   
  76.             //Activate the control  
  77.             map.addControl(new OpenLayers.Control.Graticule({ visible: false }));  
  78.             var mousepos = new OpenLayers.Control.MousePosition({ div: document.getElementById('mousepos_div') });  
  79.             map.addControl(mousepos);  
  80.   
  81.             map.addControl(new OpenLayers.Control.OverviewMap());  
  82.             //map.addControl(new OpenLayers.Control.NavToolbar());  
  83.   
  84.             map.layers[1].events.register('featureselected', this, OnFeatureSelected);  
  85.             map.layers[1].events.register('featureunselected', this, on_unselect_feature);  
  86.              
  87.             var navigationT = new OpenLayers.Control.TouchNavigation({  
  88.                 dragPanOptions: {  
  89.                     enableKinetic: true  
  90.                 }  
  91.             });  
  92.             map.addControl(navigationT);  
  93.              
  94.             if (!map.getCenter()) {  
  95.                 var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  96.                 map.setCenter(lonLat, zoom);  
  97.   
  98.             }  
  99.         }  
  100.   
  101.         function OnFeatureSelected(event) {  
  102.             var info_div = document.getElementById('nodelist');  
  103.             info_div.innerHTML = '';  
  104.             //Store the clusters  
  105.             evt_selected = event.feature.attributes;  
  106.             //Loop through the cluster features  
  107.              for (var atn in evt_selected) {  
  108.                  //Update the div with the info of the photos  
  109.                  info_div.innerHTML += "<p>"  
  110.                      + atn.toString()+":"+evt_selected[atn].toString()  
  111.                      + "</p>";  
  112.              }  
  113.         }  
  114.         function on_unselect_feature(event) {  
  115.             //Store a reference to the element  
  116.             var info_div = document.getElementById('nodelist');  
  117.             //Clear out the div  
  118.             info_div.innerHTML = 'Please Select a Point.';  
  119.         }  
  120.   
  121.         function Button_Mark_onclick() {  
  122.             var lat = Text_lat.value;  
  123.             var lon = Text_lon.value;  
  124.             var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  125.             var current_zoom = map.zoom;  
  126.             map.setCenter(lonLat, current_zoom);  
  127.             var point = new OpenLayers.Geometry.Point(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  128.             var feature_point = new OpenLayers.Feature.Vector(point);  
  129.             map.layers[1].addFeatures([feature_point]);  
  130.         }  
  131.   
  132.         function Button_Goto_onclick() {  
  133.             var lat = Text_lat.value;  
  134.             var lon = Text_lon.value;  
  135.             var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  136.             var current_zoom = map.zoom;  
  137.             map.setCenter(lonLat, current_zoom);  
  138.         }  
  139.   
  140.         function Button_DMSMark_onclick() {  
  141.             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;  
  142.             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;  
  143.             Text_lat.value = lat;  
  144.             Text_lon.value = lon;  
  145.             var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  146.             var current_zoom = map.zoom;  
  147.             map.setCenter(lonLat, current_zoom);  
  148.             var point = new OpenLayers.Geometry.Point(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  149.             var feature_point = new OpenLayers.Feature.Vector(point);  
  150.             map.layers[1].addFeatures([feature_point]);  
  151.         }  
  152.   
  153.         function Button_DMSGoto_onclick() {  
  154.             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;  
  155.             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;  
  156.             var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());  
  157.             var current_zoom = map.zoom;  
  158.             map.setCenter(lonLat, current_zoom);  
  159.         }  
  160.   
  161.     </script>  
  162.   
  163.     <style type="text/css">  
  164.         .style1  
  165.         {  
  166.             width: 100%;  
  167.             height: 29px;  
  168.         }  
  169.         .style2  
  170.         {  
  171.             width: 100%;  
  172.             height: 90%;  
  173.         }  
  174.   
  175.         #Text_DMS_Lat  
  176.         {  
  177.             width: 32px;  
  178.         }  
  179.         #Text_DMS_Lat_Deg  
  180.         {  
  181.             width: 32px;  
  182.         }  
  183.         #Text_DMS_Lat_min  
  184.         {  
  185.             width: 32px;  
  186.         }  
  187.         #Text_DMS_Lat_sec  
  188.         {  
  189.             width: 32px;  
  190.         }  
  191.         #Text_DMS_Lon_deg  
  192.         {  
  193.             width: 32px;  
  194.         }  
  195.         #Text_DMS_Lon_MIn  
  196.         {  
  197.             width: 32px;  
  198.         }  
  199.         #Text_DMS_Lon_Sec  
  200.         {  
  201.             width: 32px;  
  202.         }  
  203.     </style>  
  204.   
  205. </head>  
  206. <!-- body.onload is called once the page is loaded (call the 'init' function) -->  
  207. <body onload="init();">  
  208.     <table class="style2">  
  209.         <tr>  
  210.             <td width="80%">  
  211.     <div style="width: 100%; height: 100%" id="map">  
  212.     </div>  
  213.             </td>  
  214.             <td width="20%">  
  215.                 <div style="width: 100%; height: 100%" id="nodelist">  
  216.                 </div>  
  217.             </td>  
  218.         </tr>  
  219.     </table>  
  220.     <!-- define a DIV into which the map will appear. Make it take up the whole window -->  
  221.     <div style="width: 100%; height: 5%" id="mousepos_div">  
  222.     </div>  
  223.     <table class="style1">  
  224.         <tr>  
  225.             <td>  
  226.                 小数纬度:<input id="Text_lat" type="text" />经度:<input id="Text_lon"   
  227.                     type="text" /><input id="Button_Mark" type="button" value="标记"   
  228.                     onclick="return Button_Mark_onclick()" /><input   
  229.                     id="Button_Goto" type="button" value="前往"   
  230.                     onclick="return Button_Goto_onclick()" /></td>  
  231.             <td>  
  232.                  </td>  
  233.             <td>  
  234.                 纬度 :<input id="Text_DMS_Lat_Deg" type="text" /><input id="Text_DMS_Lat_Min"   
  235.                     type="text" /><input id="Text_DMS_Lat_Sec" type="text" />秒.经度:<input   
  236.                     id="Text_DMS_Lon_deg" type="text" /><input id="Text_DMS_Lon_MIn"   
  237.                     type="text" /><input id="Text_DMS_Lon_Sec" type="text" /></td>  
  238.             <td>  
  239.                 <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>  
  240.             <td>  
  241.                  </td>  
  242.             <td>  
  243.                  </td>  
  244.             <td>  
  245.                  </td>  
  246.         </tr>  
  247.     </table>  
  248. </body>  
  249. </html>  


下一篇,将开始介绍 基于native C++的 C/S 架构客户端的开发以及应用
阅读更多

没有更多推荐了,返回首页