一步步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类型摩卡托坐标字段
- 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;
第八个字段,摩卡托投影的字段非常重要,使用 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&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准许访问网站中。
- # 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 的 init里,写入
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 架构客户端的开发以及应用
转载自:https://blog.csdn.net/tian_110/article/details/42041075