Geoserver

Geoserver是一个功能齐全,遵循OGC开放标准的开源WFS-TWMS服务器。利用Geoserver能够把数据做为maps/images来发布(利用WMS来实现)也能够直接发布实际的数据(利用WFS来实现),同时也提供了修改,删除和新增的功能(利用WFS-T)javascript

GeoServer, 顾名思义,是一个Server. 它是开源的,容许用户查看和编辑地理数据。这是地理信息系统(GIS) 领域。GeoServer 是符合OGC 规范的一个全功能的WFS-T WMS serverhtml

GeoServer可以发布的数据类型:前端

l 地图或影象——应用WMSjava

l 实时数据——应用WFSnode

l 用户更新、删除和编辑的数据——应用WFS-Tmysql

相关概念的:

WMS: Web Map ServiceWeb地图服务

l 利用具备地理空间位置信息的数据制做地图。其中将地图定义为地理数据可视的表现。这个规范定义了三个操做:git

n GetCapabitities 返回服务级元数据,它是对服务信息内容和要求参数的一种描述;web

n GetMap 返回一个地图影像,其地理空间参考和大小参数是明肯定义了的;sql

n GetFeatureInfo(可选)返回显示在地图上的某些特殊要素的信息数据库

WFS: Web Feature ServiceWeb要素服务)

l Web 地图服务返回的是图层级的地图影像,

l Web要素服务(WFS)返回的是要素级的GML编码,并提供对要素的增长、修改、删除等事务操做,是对Web地图服务的进一步深刻。OGC Web要素服务容许客户端从多个Web要素服务中取得使用地理标记语言(GML)编码的地理空间数据,定义了五个操做:

n GetCapabilites 返回Web要素服务性能描述文档(用XML描述);

n DescribeFeatureType 返回描述能够提供服务的任何要素结构的XML文档;

n GetFeature 一个获取要素实例的请求提供服务;

n Transaction 为事务请求提供服务;

n LockFeature 处理在一个事务期间对一个或多个要素类型实例上锁的请求。

WFS-T: Web Map Service-Transactional. 容许用户以可传输的块编辑地理数据。

WCSWeb Coverage ServiceWeb覆盖服务)

Web 覆盖服务(WCS)面向空间影像数据,它将包含地理位置值的地理空间数据做为覆盖(Coverage在网上相互交换。

l 网络覆盖服务由三种操做组成:GetCapabilitiesGetCoverageDescribeCoverageType

n GetCapabilities 操做返回描述服务和数据集的XML文档。

n GetCoverage操做是在GetCapabilities肯定什么样的查询能够执行、什么样的数据可以获取以后执行的,它使用通用的覆盖格式返回地理位置的值或属性。

n DescribeCoverageType 操做容许客户端请求由具体的WCS服务器提供的任一覆盖层的彻底描述。

GML: Geography Markup Language. 一种用于描述地理数据的XML

OGC——Open Geospatial Consortium——开放地理信息联盟

总之GeoServer 是您须要显示地图在网页的那些工具的当中一个,用户能够缩放而且移动。能够与一些客户端联合使用,好比:MapBuilder (for web pages), UDig, GVSig,等等。对标准的使用容许信息从GeoServer 到其它地理信息能够很容易地被结合。

5d2a1bd81412813733fa1c2b.jpg.gif

若是你对GeoServer发出一个WMS请求,你就可能获得以下的一张图:

查看Demo

welcome界面中单击demo page连接,进入页面后单击WFS-T连接就能够启动一个名叫MapBuilder的基于Javascript的地图地图编辑器。启动MapBuilder后咱们能够看到一张样图,那就就从它开始吧!用其提供的工具对图进行修改。本身练习。

关于geoserver开发

geoserver只能用j2ee开发

geoserver是符合ogc wms/wfs/wcs标准的地图服务器,建设一套完整的webgis系统还须要客户端配合,mapbuilderopenlayers是很是好的两个选择。对于较大的项目,空间数据库也是必不可少的,geoserver支持商业的oracledb2,开源的postgismysql

扯得更远一点,geoserver支持google mapgoogle earth

Geotools

外文官网http://geotools.codehaus.org/

Geotools是开源的Java代码库,在GIS中提供对地理空间数据的标准操做。简单说,它就是一个中间件,提供的功能符合OGC规范,且与GeoAPI有密切的联系。它支持的数据格式有ShapefileGMLWFSPostGISOracle SpatialArcSDEMySQLGeoMediaMapInfo等。

利用Geotools可以实现:

l 格网覆盖Grid coverages——栅格数据,

l 坐标系统转换Coordinate Transformation

l 数据渲染Renderers

l 格式化Styling——符号化数据集等功能。

WFS地址

把下面地址中的HighwayInterchange改为本身建立的featuretype的名字,在浏览器中查看,WFSURL

http://localhost:8080/geoserver/wfs?request=getfeature&service=wfs&version=1.0.0&typename=States

下面地址的youtian改为本身的FeatureType名字,就是本身的WFS地址

http://localhost:8080/geoserver/wms/kml_reflect?layers=youtian

Openlayers dom结构

OpenLayers项目分析——(一)项目介绍

(OpenLayers JavaScript Mapping Library)

(一)项目介绍

网址:http://www.openlayers.org/

  OpenLayers 是由MetaCarta公司开发的,用于WebGIS客户端的JavaScript包,目前的最高版本是2.5 V,经过BSD License 发行。它实现访问地理空间数据的方法都符合行业标准,好比OpenGISWMSWFS规范,OpenLayers采用纯面向对象的JavaScript方式开发,同时借用了Prototype框架和Rico库的一些组件。

  采用OpenLayers做为客户端不存在浏览器依赖性。因为OpenLayers采用JavaScript语言实现,而应用于Web浏览器中的DOM(文档对象模型)由JavaScript实现,同时,Web浏览器(好比IEFF等)都支持DOM

  OpenLayers APIs采用动态类型脚本语言JavaScript编写,实现了相似与Ajax功能的无刷新更新页面,可以带给用户丰富的桌面体验(它自己就有一个Ajax类,用于实现Ajax功能)。

  目前,OpenLayers所可以支持的Format有:XMLGMLGeoJSONGeoRSSJSONKMLWFSWKT(Well-Known Text)。在OPenlayers.Format名称空间下的各个类里,实现了具体读/写这些Format的解析器。

  OpenLayers所可以利用的地图数据资源“丰富多彩”,在这方面提供给拥护较多的选择,好比WMSWFSGoogleMapKaMapMSVirtualEarthWorldWind等等。固然,也能够用简单的图片做为源。

第一次使用OpenLayers

  先到它的官方网站http://www.openlayers.org下载他的压缩包,解压后能够看到其中的一些目录和文件,拷贝目录下的OpenLayer.js、根目录下的lib目录、根目录下的img目录到你网站的Scripts目录下(固然,这个只是例子,您网站的目录结构您本身说得算,只要保证OpenLayers.js/lib/img在同一目录中便可)。而后,建立一个index.html做为查看地图的页面,导入OpenLayers.js和你将要建立的js

  咱们以加载WMSGML文件为例。 

<script src="../lib/OpenLayers.js"></script>

  <script type="text/javascript">

var lon = 5; //x-axis coodinate in map units

var lat = 40; //y-axis coordinate in map units

var zoom = 5; //number of zoom levels

var map, layer; //声明变量maplayer;等同于var map = null; var layer = null;

map = new OpenLayers.Map('map');

//实例化一个地图类OpenLayers.Map

layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",

"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );

//WMS的格式实例化图层类OpenLayers.Layer

map.addLayer(layer);

map.zoomToExtent(newOpenLayers.Bounds(-3.922119,44.335327,

4.866943,49.553833));

    //Map对象上加载Layer对象,并用map.zoomToExtent函数使地图合适地显示

    map.addLayer(new OpenLayers.Layer.GML("GML", "gml/polygon.xml"));

    //再在刚加载的WMS文件上,加载一GML文件

  剩下的工做就是,加上一些控件OpenLayers.Control之类的东西,好比LayerSwitcher等。它们会在地图浏览的“窗口”上增长一些工具栏或是“按钮”,增长互动性和功能性。

  固然,Openlayers中的东西远不止这些,至于它的框架分析、APIs实现机制,会在后续文章中说出。写这个的过程,也是一个学习的过程,其中不免有不妥之处,热烈欢迎你们批评指正,相互交流。

OpenLayers 项目完整分析——(二)源代码整体结构分析

(二)源代码整体结构分析

经过前面的项目介绍,咱们大概已经知道Openlayers是什么,可以作什么,有什么意义。接下来咱们分析它怎么样,以及怎样实现的等问题。

这个图是从它的文档上截取的,旨在从感官上认识一下OpenLayers的类。下面分别介绍(文档中的类是按字母顺序排列的,也按这个顺序说吧):

 

  咱们看到在类的顶层“高高在上”的是OpenLayers,它为整个项目实现提供名称空间JavaScript语言没有名称空间一说,可是它确实有本身的机制实现相似的功能,后面会说明),它直接拥有一常量VERSION_NUMBER,以标识版本。

 

  Ajax:顾名思义,用于实现Ajax功能,只是OpenLayers的开发者们把它单独写到一个类里了,其中用到了Prototype.js框架里的一些东西。同时,设计的时候也考虑了跨浏览器的问题。

 

  BaseTypes:这里定制了OpenLayers中用到的stringnumber function好比,OpenLayers. String. startsWith,用于测试一个字符串是否一以另外一个字符串开头;OpenLayers. Number. limitSigDigs,用于限制整数的有效数位;OpenLayers. Function.bind,用于把某一函数绑定于对象等等。

 

  ConsoleOpenLayers.Console,此名称空间用于调试和把错误等输出到“控制台”上,须要结合使用../Firebug/firebug.js

 

  Control:咱们一般所说的控件类,它提供各类各样的控件,好比上节中说的图层开关LayerSwitcher,编辑工具条EditingToolbar等等。加载控件的例子:

 

class = new OpenLayers.Map('map', { controls: [] });

    map.addControl(new OpenLayers.Control.PanZoomBar());

    map.addControl(new OpenLayers.Control.MouseToolbar());

 

  Events:用于实现OpenLayers的事件机制。具体来讲,OpenLayers中的事件分为两种,一种是浏览器事件,例如mouseup,mousedown之类的;另一种是自定义的,如addLayer之类的。OpenLayers中的事件机制是很是值得咱们学习的,后面将具体讨论。

 

  Feature:咱们知道:Featuregeography attributes的集合。在OpenLayers中,特别地OpenLayers.Feature 类由一个marker 和一个lonla组成OpenLayers. Feature.WFSOpenLayers. Feature. Vector继承于它。

 

  Format:此类用于读/写各类格式的数据,它的子类都分别建立了各个格式的解析器。这些格式有:XMLGMLGeoJSONGeoRSSJSONKMLWFSWKT(Well-Known Text)

 

  Geometry:怎么翻译呢,几何?是对地理对象的描述。它的子类有CollectionCurveLinearRingLineStringMultiLineStringMultiPointMultiPolygonPointPolygonRectangleSurface,正是这些类的实例,构成了咱们看到的地图。须要说明的是,Surface 类暂时尚未实现。

 

  Handler:这个类用于处理序列事件,可被激活和取消。同时,它也有命名相似于浏览器事件的方法。当一个handler 被激活,处理事件的方法就会被注册到浏览器监听器listener ,以响应相应的事件;当一个handler被取消,这些方法在事件监听器中也会相应的被取消注册Handler经过控件control被建立,而control经过icon表现

 

  Icon:在计算机屏幕上以图标的形式呈现,有url尺寸size位置position3个属性。通常状况,它 OpenLayers.Marker结合应用表现为一个Marker

 

  Layer:图层

 

  Map网页中动态地图。它就像容器,可向里面添加图层Layer和控件Control。实际上,单个Map是毫无心义的,正是LayerControl成就了它。

 

  Marker:它的实例是OpenLayers.LonLat OpenLayers.Icon的集合。通俗一点儿说,Icon附上必定的经纬度就是Marker

  Popup地图上一个小巧的层,实现地图“开关”功能。使用例子:

 

      Class = new OpenLayers.Popup("chicken",

new OpenLayers.LonLat(5,40),

new OpenLayers.Size(200,200),

"example popup",

true);

      map.addPopup(popup);

 

  Renderer:渲染类。在OpenLayers中,渲染功能是做为矢量图层的一个属性存在的,咱们称之为渲染器,矢量图层就是经过这个渲染器提供的方法将矢量数据显示出来。以SVGVML为例,继承关系是这样的:    

至于OpenLayers. Renderer. Elements为何要存在,以及它的渲染机制,后面会说。

 

  Tile:设计这个类用于指明单个“瓦片”Tile,或者更小的分辨率Tiles存储它们自身的信息,好比urlsize等。它的类继承关系以下:

  Util:“跑龙套”的类。

 

  写到这里,能够看到OpenLayers 的类缠绕的挺麻烦的,接下来的文章将从代码部分分析更细部的东西。

OpenLayers 项目分析——(三)BaseTypes

(三)BaseTypes :定义底层类与定制JS内置类  

先说基类型BaseTypes下,OpenLyers构建的“本身”的类。它们分别是:OpenLayers. LonLatOpenLayers. PixelOpenLayers.SizeOpenLayers. ElementOpenLayers. BoundsOpenLayers. Class。下面分别介绍:

  OpenLayers. LonLat:经纬度类,其实例为地图提供一经度、纬度对,即位置。有两个属性lonx-axis coodinate )和laty-axis coordinate 。这里说明一下,怎么经纬度又与x轴坐标、y轴坐标纠缠在一块儿?是这样:当地图是在地理坐标投影下,它就是经纬度;否则就是地图上的xy轴坐标。除构造函数外,实现了五个函数:

 

toShortString:function() 把坐标转换为字符串;

clone:function()  复制一个LonLat对象;

 

Add:function(lon,lat)  改变现有地图的位置;

  return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);

 

equals:function(ll)  判断传入的lonlat对是否与当前的相等;

wrapDateLine:function(maxExtent)  复制下(lon,lat),指定为边界的最大范围。

  OpenLayers. Pixel:像素类,在显示器上以(x,y)坐标的的形式呈现像素位置。有两个属性x坐标、y坐标,提供四个成员函数:

 

clone:function() 拷贝像素;

equals:function(px) 判断两像素是否相等;

 

add:function(x,y)  改变(x,y)使其成为新像素;

return new OpenLayers.Pixel(this.x + x, this.y + y);

 

offset:function(px)  调用add()使像素位置发生偏移。

  newPx = this.add(px.x, px.y);

  OpenLayers.Size:也有两个属性,宽度width、高度height。实现了两个成员函数:clone:function()equals:function(sz)很少说了。

  OpenLayers. Element:在这个名称空间下,开发者写了好多API,有visibletogglehideshowremovegetHeightgetDimensionsgetStyle以实现元素的显示、隐藏、删除、取得高度,取得范围等功能。以getHeight函数为例咱们看看它的代码:

  

getHeight: function(element) {

element = OpenLayers.Util.getElement(element);

return element.offsetHeight;

}

这里涉及到文档对象模型DOM的一些东西,函数自己很简单,最后返回元素的高度。

  OpenLayers. Bounds:在这个类中,数据以四个浮点型数left, bottom, right, top 的格式存储,它是一个像盒子同样的范围。它实现了三个描述一个Bound的函数:toStringtoArraytoBBOX。其中,toString的代码以下:

  

toString:function() {

return ( "left-bottom=(" + this.left + "," + this.bottom + ")"

+ " right-top=(" + this.right + "," + this.top + ")" );

}

结果相似于"left-bottom=(5,42) right-top=(10,45)"

  三个Bound数据来源函数:fromStringfromArrayfromSize

五个获取对象属性的函数:getWidthgetHeightgetSizegetCenterPixelgetCenterLonLat

余下还有:add:function(x,y)extend:function(object)containsLonLatcontainsPixelcontainsintersectsBoundscontainsBoundsdetermineQuadrantwrapDateLine。以函数extend为例,看看源码。

    extend:function(object) {

var bounds = null;

if (object) {

switch(object.CLASS_NAME) {

case "OpenLayers.LonLat":

bounds = new OpenLayers.Bounds (object.lon, object.lat, object.lon, object.lat);

break;

case "OpenLayers.Geometry.Point":

bounds = new OpenLayers.Bounds(object.x, object.y,object.x, object.y);

break;

case "OpenLayers.Bounds":

bounds = object;

break;

}

if (bounds) {

if ( (this.left == null) || (bounds.left < this.left)) {

this.left = bounds.left;}

if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {

this.bottom = bounds.bottom;}

if ( (this.right == null) || (bounds.right > this.right) ) {

this.right = bounds.right;}

if ( (this.top == null) || (bounds.top > this.top) ) {

this.top = bounds.top;}

}

}

}

能够看出,对Bounds的扩展能够有三种形式:point, lonlat, 或者bounds,计算的条件是零坐标是在屏幕的左上角。

  OpenLayers. Class:这个类是OpenLayers 中的“大红人”,只要建立其余类就得用它,同时也实现了多重继承。用法以下:

  单继承建立:class = OpenLayers.Class(prototype);

  多继承建立:class = OpenLayers.Class(Class1, Class2, prototype);

净说底层类了,对js内置类的扩展下回写。

OpenLayers 项目分析——(三)BaseTypes ()

(三)BaseTypesOpenLayers中定制JavaScript内置类

  OpenLayers不只“本身”写了一些底层的类,像上回说的那些都是。同时也定制了一些JS的一些内置类,即对JS内置类的扩展。这个扩展主要包含3类:StringNumberFunction存在于BaseTypes.js文件中。

  StringOpenLayersstring类型定制了8个方法,分别是startsWithcontainstrimcamelize;还有另外4个方法:String. startsWithString. containsString.trimString. Camelize,它们将会在3.0Version中被删除,多是之前版本遗留下来的,这里就不说它们了。

  //Test whether a string starts with another string.

  startsWith: function(str, sub) {

return (str.indexOf(sub) == 0);

}

  //Test whether a string contains another string.

contains: function(str, sub) {

return (str.indexOf(sub) != -1);

}

//Removes leading and trailing whitespace characters from a string.

trim: function(str) {

return str.replace(/^"s*(.*?)"s*$/, "$1");

}

//Camel-case a hyphenated string.

  //Ex."chicken-head"becomes"chickenHead",

//and"-chicken-head"becomes"ChickenHead".

// “骆驼”化带有连字符的字符串。

camelize: function(str) {

var oStringList = str.split('-');

var camelizedString = oStringList[0];

for (var i = 1; i < oStringList.length; i++) {

var s = oStringList[i];

camelizedString += s.charAt(0).toUpperCase() + s.substring(1);

}

return camelizedString;

}

Number

项目仅对number类型扩展了一个方法OpenLayers. Number. limitSigDigs(还有一个方法Number. limitSigDigs,一样在3.0中会删除)。

//Limit the number of significant digits on an integer.

limitSigDigs: function(num, sig) {

var fig;

if(sig > 0) {

fig = parseFloat(num.toPrecision(sig));

} else {

fig = 0;

}

return fig;

}

Function

扩展了两个方法bind bindAsEventListener(一样存在Function.bindFunction. bindAsEventListener两个被“遗弃”的函数)。

//Bind a function to an object.

//Method to easily create closures with'this' altered.

bind: function(func, object) {

// create a reference to all arguments past the second one

var args = Array.prototype.slice.apply(arguments, [2]);

return function() {

// Push on any additional arguments from the actual function call.

// These will come after those sent to the bind call.

var newArgs = args.concat(

Array.prototype.slice.apply(arguments, [0])

);

return func.apply(object, newArgs);

}

}

//Bind a function to an object, and configure it to receive the event

//object as first parameter when called.

bindAsEventListener: function(func, object) {

return function(event) {

return func.call(object, event || window.event);

};

}

这里说说这两个方法。

首先看看bind方法,这是一个可以被Function的实例获得的方法,以下所示:

Function.prototype.bind = function() {

var _method = this, args = [], object = arguments[0];

for (var i = 1; i < arguments.length; i++)

args.push(arguments[i]);

return function(moreargs) {

for (var i = 0; i < arguments.length; i++)

args.push(arguments[i]);

return _method.apply(object, args);

}

};

_method 表明Function实例自身,bind可接收多个参数,不过它绑定是是第一个参数,该参数是一个function或者是调用环境,后面的都是执行函数的参数。

Function.prototype.bindAsEventListener = function(object) {

var _method = this;

return function(event) {

return _method.call(object, event || window.event);

}

};

这里只是将object做为_method 引用的环境,就是说如今能够在object对象中这样使用,

object. _method event||window.event)。

也许你注意到了Funtion扩展的两个方法一个用到了call而另外一个用的是apply,其实这两个并无什么太大的区别,只是参数传递的形式不一样,如若没有参数要传递,那么这两个是同样的:

apply(obj[,argumentsArray]),call(obj[,arg1[,arg2]])

OpenLayers项目分析——(四)空间数据的组织与实现

提到数据,先思考几个问题:

  GIS,核心是什么?数据?平台?服务?  

  空间数据的特征、表达方式?

  地理数据的模型(结构)?

  在OpenLayers空间数据的实现主要存在OpenLayers. Geometry类及其子类中。咱们先看下面的两个图片,表现了这些类的继承关系。从图上能够清楚的看出MultiPointPolygonMultiLineString 这三个类实现了多重继承,即直接继承于Geometry类,又继承于Collection类(为何要这样实现?)。

  OpenLyers对于Geometry对象的组织是这样的,其实最基础的就是点,而后MultiPoint由点构成,继承自Openlayers.Geometry.Collection,LinearRing,LineString均由Point构成,

PolygonOpenLayers.Geometry.LinearRing构成。OpenLyers在解析数据时候,将全部的面、线包含的点所有都对象化为Openlayers.Geometry.Point有人测试这里面存在问题:解析矢量数据慢,甚至在点数多的状况下,会使浏览器“崩溃”掉。想一想是有道理的:OpenLyers在解析数据时候,将全部的面、线包含的点所有都对象化为点对象t,并首先将全部的对象读取到内存,获得一个Feature的集合,而后将这个集合提交给渲染器进行渲染。这样渲染起来固然慢了。至于为何要这样,多是OpenLayers项目自己在标准上,在框架结构上作的比较好,更细部的东西还得优化呀。可话又说回来,OpenLayers做为一个优秀的开源JS框架,学习借鉴的意义要比应用的意义大吧。 

 下面以PointCollection为例来讲明其内部实现过程,先看Point

  咱们知道一个点就是一个坐标对(x,y)嘛,固然它得有两个属性xy。在point类里,提供了六个成员函数,分别是clonedistanceToequalsmoverotateresize。看看计算两点距离的函数是怎么写的:

distanceTo: function(point) {

var distance = 0.0;

if ( (this.x != null) && (this.y != null) &&

(point != null) && (point.x != null) && (point.y != null) ) {

var dx2 = Math.pow(this.x - point.x, 2);

var dy2 = Math.pow(this.y - point.y, 2);

distance = Math.sqrt( dx2 + dy2 );

}

return distance;

}

  在collection集合对象中,能够存放同一类型的地理对象,也能够放不一样的地理对象。定义了一个属性component ,以数组对象的形式存储组成collection对象的“组件”。别的不说了,看一个获取集合大小的函数getLength

getLength: function() {

var length = 0.0;

for (var i = 0; i < this.components.length; i++) {

length += this.components[i].getLength();

}

return length;

}

  细心的朋友也许会发现,每个基类都有一个destroy函数。它是OpenLayers实现的垃圾回收机制,以防止内存泄露,优化性能:

  

destroy: function () {

this.components.length = 0;

this.components = null;

}

OpenLayers项目分析——(五)数据解析——以GML为例

(五)OpenLayers 数据解析—以GML为例

  前面也提到过,OpenLayers设计是符合标准的,有良好的框架结构和实现机制,很是值得学习。OpenLayers支持的格式比较多,有XMLGMLGeoJSONGeoRSSJSONKMLWFS等。这回主要以GML为例来看OpenLayers 数据的解析过程。

  先来了解一下GML

  GML (Geography Markup Language)即地理标识语言,它由OGC(开放式地理信息系统协会)于1999年提出,目前版本是3.0GMLXML在地理空间信息领域的应用。利用GML能够存储和发布各类特征的地理信息,并控制地理信息在Web浏览器中的显示。地理空间互联网络做为全球信息基础架构的一部分,已成为Internet上技术追踪的热点。许多公司和相关研究机构经过Web将众多的地理信息源集成在一块儿,向用户提供各类层次的应用服务,同时支持本地数据的开发和管理。GML能够在地理空间Web领域完成了一样的任务。GML技术的出现是地理空间数据管理方法的一次飞跃。

  介绍一篇文章:GML30WebGlS研究。

  咱们从整体上来把握一下OpenLayers对于GML数据的解析,首先经过调用获得GML文本数据,而后经过Formate.GML类的read方法来解析这个文本,解析获得Geometry对象,而后Geometry对象用相应的渲染器画出来。其实解析获得仍是那些基本的Point呀、LineString呀之类的Geometry对象,就是咱们在地图上看到的那些内容。

  下面看其实现过程:

  //read()函数读取数据,获取特征列表

read: function(data) {

if(typeof data == "string") {

data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);

}

var featureNodes = this.getElementsByTagNameNS (data.documentElement,this.gmlns, this.featureName);

var features = [];

for(var i=0; i<featureNodes.length; i++) {

var feature = this.parseFeature(featureNodes[i]);

if(feature) {

features.push(feature);

}

}

return features;

}

 //函数parseFeature()OpenLayersGML数据格式解析的核心,就是它建立地理对象 

//和其属性。          

  //实际上,每个Foramt 子类都实现了这个成员函数,完成相似的功能。

parseFeature: function(node) {

// only accept on geometry per feature - look for highest "order"

var order = ["MultiPolygon", "Polygon",

"MultiLineString", "LineString",

"MultiPoint", "Point"];

var type, nodeList, geometry, parser;

for(var i=0; i<order.length; ++i) {

type = order[i];

nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);

if(nodeList.length > 0) {

// only deal with first geometry of this type

var parser = this.parseGeometry[type.toLowerCase()];

if(parser) {

geometry = parser.apply(this, [nodeList[0]]);

} else {

OpenLayers.Console.error("Unsupported geometry type: " +

type);

}

// stop looking for different geometry types

break;

}

}

// construct feature (optionally with attributes)

var attributes;

if(this.extractAttributes) {

attributes = this.parseAttributes(node);

}

var feature = new OpenLayers.Feature.Vector(geometry, attributes);

// assign fid - this can come from a "fid" or "id" attribute

var childNode = node.firstChild;

var fid;

while(childNode) {

if(childNode.nodeType == 1) {

fid = childNode.getAttribute("fid") ||

childNode.getAttribute("id");

if(fid) {

break;

}

}

childNode = childNode.nextSibling;

}

feature.fid = fid;

return feature;

}

  剩下就是由具体的函数parse and bulid基本的地理对象(还有Attribute),包括pointmultipointlinestringmultilinestringpolygonmultipolygon等,而后在write出来。

  结合前面的“OpenLayers空间数据的组织”,咱们能够看到OpenLayers在解析获取GML数据的时候,好比涉及到面、线的时候,老是以点为基础构建的。有的朋友作过测试,说这时候,直接用SVG画出来,性能上会好不少(具体没测试过,不想多说什么)。

OpenLayers项目分析——(六)数据渲染分析

(六)数据渲染分析

实际上,OpenLayers的整个表现过程是这样的:经过调用获取数据,而后各类格式的解析器解析数据,在用所谓的渲染器渲染后加到图层上,最后再结合相应的控件表现出来,成为一幅咱们看到的“动态”地图。

  这里主要讨论OpenLayers. Renderer这个类及其子类。

  Renderer类提供了一些虚方法,以供其子类继承,像setExtentdrawFeaturedrawGeometryeraseFeatureseraseGeometry等。

  Elements继承Renderer,具体实现渲染的类又继承Renderer类。之因此这样设计,是由于不一样的矢量格式数据须要共享相应的函数,在Elements这个类中封装一下。这个类的核心是drawGeometrydrawGeometryNode两个函数。其中drawGeometry调用了drawGeometryNode,建立出基本的地理对象。

drawGeometry: function(geometry, style, featureId) {

var className = geometry.CLASS_NAME;

if ((className == "OpenLayers.Geometry.Collection") ||

(className == "OpenLayers.Geometry.MultiPoint") ||

(className == "OpenLayers.Geometry.MultiLineString") ||

(className == "OpenLayers.Geometry.MultiPolygon")) {

for (var i = 0; i < geometry.components.length; i++) {

this.drawGeometry(geometry.components[i], style, featureId);

}

return;

};

//first we create the basic node and add it to the root

var nodeType = this.getNodeType(geometry);

var node = this.nodeFactory(geometry.id, nodeType, geometry);

node._featureId = featureId;

node._geometryClass = geometry.CLASS_NAME;

node._style = style;

this.root.appendChild(node);

//now actually draw the node, and style it

this.drawGeometryNode(node, geometry);

}

  渲染器的继承关系这样的:

  具体实现渲染的方法在OpenLayers. Renderer.SVGOpenLayers. Renderer.VML两个类中实现的,就是实现Elements提供的虚方法,好比drawPointdrawCircledrawLineStringdrawLinearRingdrawLinedrawPolygondrawSurface等。以drawCircle为例看看具体的实现过程:

drawCircle: function(node, geometry, radius) {

if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {

var resolution = this.getResolution();

node.style.left = (geometry.x /resolution).toFixed() - radius;

node.style.top = (geometry.y /resolution).toFixed() - radius;

var diameter = radius * 2;

node.style.width = diameter;

node.style.height = diameter;

}

}

OpenLayers项目分析——(七)地图表现

(七)地图表现

一开始看到OpenLayers,就有一个问题。就是它做为WebGIS的前端,通俗地说,是“显示”地图的。那么,它显示的地图是什么,是怎么显示的,又是怎么实现的?——暂且把这个问题叫作地图表现。我以为最关键的就是Map类,把这个类分析清楚了,问题就解决了一大半了。

  前面第一回里说过怎么实例化一个地图,怎么向地图里加图层加控件。其实,地图是这样的,它就像一个容器,能够盛东西。要分析它光理解这些还不够,咱们要知道这个容器是怎么作出来的,及具体都有什么功能。

  Map类有两个常量:Z_INDEX_BASEEVENT_TYPES,不说了,可顾名而思其意。再看它定义的一些属性:divThe element that contains the map)、baseLayerThe currently selected base layer)、eventsAn events object that handles all events on the map)。是这样,web页的div经过以idname的形式得到map对象,而后layerscontrol在加载到map上,表现为地图。顺便说一句,控件control和事件event是相关联的,这之后会说。

 OpenLayers.Map类提供了两种实例化方式,举例来看:

 // create a map with default options in an element with the id "map1"

var map = new OpenLayers.Map("map1");

// create a map with non-default options in an element with id "map2"

//Optional object with properties to tag onto the map.

var options = {

maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),

maxResolution: 156543,

units: 'meters',

projection: "EPSG:41001"

};

var map = new OpenLayers.Map("map2", options);

  OpenLayers.Map类实现的函数APIMethod是分组的,好比Layer FunctionsControl FunctionsPopup FunctionsContainer Div FunctionsZoom, Center, Pan FunctionsLayer OptionsBaselayer FunctionsZooming FunctionsTranslation Functions。其中,最关键的是Layer FunctionsControl Functions,由于就是Layer对象和Control对象构成了map的主体。下面从每组函数中挑选出一两个来,看看具体实现过程。

  Layer Functions

就看addLayer函数吧,下面的addLayers就是调用的它,代码以下:

addLayer: function (layer) {

for(var i=0; i < this.layers.length; i++) {

if (this.layers[i] == layer) {

var msg = "You tried to add the layer: " + layer.name +

" to the map, but it has already been added";

OpenLayers.Console.warn(msg);

return false;

}

}

layer.div.style.overflow = "";

this.setLayerZIndex(layer, this.layers.length);

if (layer.isFixed) {

this.viewPortDiv.appendChild(layer.div);

} else {

this.layerContainerDiv.appendChild(layer.div);

}

this.layers.push(layer);

layer.setMap(this);

if (layer.isBaseLayer) {

if (this.baseLayer == null) {

// set the first baselaye we add as the baselayer

this.setBaseLayer(layer);

} else {

layer.setVisibility(false);

}

} else {

layer.redraw();

}

this.events.triggerEvent("addlayer");

}

能够看到其中涉及到layer的一些方法,下一回具体介绍OpenLayers. Layer类。

  Control Functions

addControl: function (control, px) {

this.controls.push(control);

this.addControlToMap(control, px);

}

能够看出,添加控件的过程是由controls.Push()addControlToMap()两个函数共同完成的。

addControlToMap: function (control, px) {

// If a control doesn't have a div at this point, it belongs in the

// viewport.

control.outsideViewport = (control.div != null);

control.setMap(this);

var div = control.draw(px);

if (div) {

if(!control.outsideViewport) {

div.style.zIndex = this.Z_INDEX_BASE['Control'] +

this.controls.length;

this.viewPortDiv.appendChild( div );

}

}

}

  Popup Functions:这组函数和上两组函数类似,是在地图上添加或删除Popup 对象。

  Zoom, Center, Pan Functions

    //Allows user to pan by a value of screen pixels

   pan: function(dx, dy) {

// getCenter

var centerPx = this.getViewPortPxFromLonLat(this.getCenter());

// adjust

var newCenterPx = centerPx.add(dx, dy);

// only call setCenter if there has been a change

if (!newCenterPx.equals(centerPx)) {

var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);

this.setCenter(newCenterLonLat);

}

}

 Zooming Functions:

这里就看看放大缩小函数吧。

zoomIn: function() {

this.zoomTo(this.getZoom() + 1);

}

zoomOut: function() {

this.zoomTo(this.getZoom() - 1);

}

显然,zoomInzoomOut都使用了getZoom方法,放大就是让zoom加1,缩小减1。

OpenLayers项目分析——(八)地图表现(续)

(八)地图表现(续)

  上一回说到OpenLayers.Map类,这回介绍组成Map的主体部分OpenLayers. Layer类,先从其实现细节上分析,看它是怎么设计出来的。关于它许许多多的子类,即各类图层,想单独写一篇。

  OpenLayers. Layer提供了一个EVENT_TYPES常量,用于支持关于图层的应用事件类型,这些事件有"loadstart", "loadend", "loadcancel", "Visibilitychanged"

  它“固有”的3个属性:id,name,div。其中,idnamelayer的身份,在对图层进行操做的时候,就是用它们标志的。至于div,你们都制知道,DOM元素,用于存放图层。

  定义的mapevent属性,是图层对象对mapevent对象的引用;projection属性,设置默认状况下,地图的投影,同时也设置maxExtent, maxResolution, units

  来看看构造函数:

* name - {String} The layer name

* options - {Object} Hashtable of extra options to tag onto the layer

*/

initialize: function(name, options) {

this.addOptions(options);

this.name = name;

if (this.id == null) {

this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");

this.div = OpenLayers.Util.createDiv();

this.div.style.width = "100%";

this.div.style.height = "100%";

this.div.id = this.id;

this.events = new OpenLayers.Events(this, this.div,

this.EVENT_TYPES);

}

if (this.wrapDateLine) {

this.displayOutsideMaxExtent = true;

}

}

OpenLayers中每个类的构造函数都是以initialize命名的。

  再看看其成员函数:

  destroy函数,至关于析构函数;

  onMapResizeremoveMap 虚函数,提供给子类继承;

  //移动函数

  moveTo:function(bounds, zoomChanged, dragging) {

var display = this.visibility;

if (!this.isBaseLayer) {

display = display && this.inRange;

}

this.display(display);

}

  下面一组函数是Baselayer Functions函数,就是layerBaselayer 的话,所用的函数。

好比,initResolutionsgetResolutiongetExtent等。

  经过这两次的分析,能够发现,MapLayers的关系:它们是相互引用的。其实是这样,OpenLayersMap类主要包含了对每一个图层的引用,对每一个控件的引用,对事件的引用,对装载容器的引用(其实就是那些map上层的div)以及对pop的引用,而其自身又包含有大量的方法和属性。图层主要包含了对map的引用,对自身div容器的引用以及事件的引用,而图层自身又包含了大量的属性和方法。map引用了layer,而layer又引用了map,这里就直接造成了循环引用关系。

  这样的组成和关联关系,每动一下,就会涉及到大量的对象,影响了性能

OpenLayers项目分析——(九)控件

(九)OpenLayers中的控件

  OpenLayers中的控件,是经过加载到地图上而起做用的,也算地图表现的一部分。同时,控件须要对地图发生做用,因此每一个控件也持有对地图(map对象)的引用。

  前面说过,控件是于事件相关联的。具体的说就是控件的实现是依赖于事件绑定的,每一个OpenLayers.Control及其子类的实例都会持有一个handler的引用的。

  那么,怎么来建立并添加一个控件呢?用下面的语句:

  //实例化一个控件

  var control1 = new OpenLayers.Control({div: myDiv});

  //向地图中添加控件

  var map = new OpenLayers.Map('map', { controls: [] });

  map.addControl(control1 );

对一些经常使用的OpenLayers控件,项目自己都封装好了,用下面的语句添加:

  map.addControl(new OpenLayers.Control.PanZoomBar());

  map.addControl(new OpenLayers.Control.MouseToolbar());

 map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));

 map.addControl(new OpenLayers.Control.Permalink());

  map.addControl(new OpenLayers.Control.Permalink('permalink'));

  map.addControl(new OpenLayers.Control.MousePosition());

 map.addControl(new OpenLayers.Control.OverviewMap());

map.addControl(new OpenLayers.Control.KeyboardDefaults());

  先看看OpenLayers. Control基类的实现过程,再选择几个典型的子类分析一下。

  OpenLayers. Control

  //设置控件的map属性,即控件所引用的地图

setMap: function(map) {

this.map = map;

if (this.handler) {

this.handler.setMap(map);

}

}

  //drew方法,当控件准备显示在地图上是被调用。固然,这个方法只对有图标的控件起 

  //做用。

draw: function (px) {

if (this.div == null) {

this.div = OpenLayers.Util.createDiv();

this.div.id = this.id;

this.div.className = this.displayClass;

}

if (px != null) {

this.position = px.clone();

}

this.moveTo(this.position);

return this.div;

}

  前面说过,OpenLayers.Control及其子类的实例都是会持有一个handler的引用的,由于每一个控件起做用时,鼠标事件都是不同的,这须要动态的绑定和接触绑定。在OpenLayers.Control中是经过activedeactive两个方法实现,就是动态的激活和注销。

  //激活方法

activate: function () {

if (this.active) {

return false;

}

if (this.handler) {

this.handler.activate();

}

this.active = true;

return true;

}

  //注销方法

deactivate: function () {

if (this.active) {

if (this.handler) {

this.handler.deactivate();

}

this.active = false;

return true;

}

return false;

}

  再来看OpenLayers.Control的子类,即各种“特点”控件。选鹰眼控件OpenLayers. Control. OverviewMap和矢量编辑工具条控件OpenLayers. Control. EditingToolbar来讲。

  顺便说一句,OpenLayers中的控件有些是须要图标的,像EditingToolbar,有些是不须要的,像OpenLayers. Control. DragPan

  OpenLayers. Control. OverviewMap

  “鹰眼”实际上也是地图导航的一种形式,在外部形态上跟图层开关控件有点儿像。

添加鹰眼控件的语句:

 map.addControl(new OpenLayers.Control.OverviewMap());

  在它实现的成员函数中,draw函数是核心,继承基类OpenLayers.Control,在地图中显示这个控件。

  此控件关联了一些浏览器事件,好比

rectMouseDown: function (evt) {

if(!OpenLayers.Event.isLeftClick(evt)) return;

this.rectDragStart = evt.xy.clone();

this.performedRectDrag = false;

OpenLayers.Event.stop(evt);

}

  OpenLayers. Control. EditingToolbar

  OpenLayers2.3版就对矢量编辑进行了支持,就是图上右上角几个图标。完成点、线、面的编辑功能。

  一样,它也是用drew方法激活:

draw: function() {

Var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments);

this.activateControl(this.controls[0]);

return div;

}

  下面的代码是使用此控件的具体过程:

  Var map, layer;

map = new OpenLayers.Map( 'map', { controls: [] } );

layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",

"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );

map.addLayer(layer);

vlayer = new OpenLayers.Layer.Vector( "Editable" );

map.addLayer(vlayer);

map.addControl(new OpenLayers.Control.PanZoomBar());

map.addControl(new OpenLayers.Control.EditingToolbar(vlayer));

map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);

OpenLayers项目分析——(十)事件机制分析

(十)OpenLayers事件机制分析

  OpenLayers中的事件封装是其一大亮点,很是值得学习。说到事件机制,在宏观上不得不涉及控件OpenLayers.Control类、OpenLayers. Marker类、OpenLayers.Icon类等。是这样,在外观上控件经过MarkerIcon表现出来,而事件包含在控件以后,用他们本身的话说就是:The controls that wrap handlers define the methods that correspond to these abstract events 。顺便再说一句,控件实现的核心是handler类,每一个控件中都包含对handler的引用,经过activedeactive两个方法,实现动态的激活和注销。

  OpenLayers中的事件有两种:一种是浏览器事件(好比onclickonmouseup等),另外一种是自定义的事件。自定义的事件像addLayer ,addControl等,不象浏览器事件会绑定相应的dom节点,它是与layermap等关联的。

  OpenLayers中支持的浏览器事件类型有(以常量的形式提供的): 

BROWSER_EVENTS: [

"mouseover", "mouseout",

"mousedown", "mouseup", "mousemove",

"click", "dblclick",

"resize", "focus", "blur" ] 

 看看构造函数的的实现过程:

initialize: function (object, element, eventTypes, fallThrough) {

this.object = object;

this.element = element;

this.eventTypes = eventTypes;

this.fallThrough = fallThrough;

this.listeners = {};

// keep a bound copy of handleBrowserEvent() so that we can

// pass the same function to both Event.observe() and .stopObserving()

this.eventHandler = OpenLayers.Function.bindAsEventListener(

this.handleBrowserEvent, this

);

// if eventTypes is specified, create a listeners list for each

// custom application event.

if (this.eventTypes != null) {

for (var i = 0; i < this.eventTypes.length; i++) {

this.addEventType(this.eventTypes[i]);

}

}

// if a dom element is specified, add a listeners list

// for browser events on the element and register them

if (this.element != null) {

this.attachToElement(element);

}

}

  能够这样理解:

  initializeobject, element, eventTypes, fallThrough)方法会将以数组eventTypes的每一个元素为key创建哈希表listeners,表中每一个键对应一个数组。还会给this.eventHandler赋值,它实际只是一个包装了triggerEvent事件触发函数的方法,全部的事件,包括浏览器事件和自定义事件都是经过它来中转的。而后initialize将全部的浏览器事件放入listeners中,并为其绑定相应的dom节点elementthis.eventHandler事件处理函数OpenLayers.Event.observe(element, eventType, this.eventHandler),节点上事件触发的时候会把事件传给this.eventHandler,它调用triggerEvent,从而将事件传出来。

  来看其余的成员函数:

  addEventTypeAdd a new event type to this events object

  attachToElement:把浏览器事件关联到相应的DOM元素上;

  register Register an event on the events object.

register: function (type, obj, func) {

if (func != null) {

if (obj == null) {

obj = this.object;

}

var listeners = this.listeners[type];

if (listeners != null) {

listeners.push( {obj: obj, func: func} );

}

}

}

其中,func参数是预先定义的回调函数。

  unregister:注销方法;

  removeRemove all listeners for a given event type.

  triggerEventTrigger a specified registered event

OpenLayersVectorMarkers

OpenLayers2.4版本中历史性地添加了Vector图层的支持。这个功能分别在不一样的浏览器上用SVG/VML实现,其难度能够想象。Vector的出现可能大大增长开源WebGIS客户端的功能。

不过问题也随之而来,在使用Vector的时候,咱们一般还要添加一个SelectFeature控件。这个控件的功能是使矢量的Feature可选,或是响应其余鼠标事件。问题就在于添加了SelectFeature以后,本来的Marker就不能再捕捉到事件,致使Popup之类的功能失效(包括Popup自己也不能捕捉到事件)。

鱼和熊掌不能兼得,不过OpenLayers 2.4中已经给Vector图层里增长了createMarkercreatePopup两个方法,它的注释是“HACK - we need to decide if all vector features should be able to create markers”。料想利用这两个方法构造的marker和应该是能够解决前面的问题。

VectorMarker的冲突可能仍是会继续一段时间,看起来确实是一个小小的缺陷。

下一个

OpenLayers是一个开源的js框架,用于在您的浏览器中实现地图浏览的效果和基本的zoompan等功能。OpenLayers支持的地图来源包括了WMSGoogleMapKaMapMSVirtualEarth等等,您也能够用简单的图片做为源,在这一方面OPenLayers提供了很是多的选择。

要使用OpenLayers,您能够到它的官方网站http://www.openlayers.org下载他的压缩包,解压后能够看到其中的一些目录和文件。拷贝dist目录下的OpenLayer.js、根目录下的lib目录、根目录下的img目录到你网站的scripts目录下(固然,这个只是例子,您网站的目录结构您本身说得算,只要保证OpenLayers.js/lib/img在同一目录中便可)。

接下来建立一个index.html做为查看地图的页面。导入OpenLayers.js和你将要建立的js。内容须要一个div,咱们给它的id起名叫作area。你有必要在写一些CSS限定#area的宽度和高度,若是乐意,加上一个border也是很不错的选择。

废话很少说,咱们首先要建立一个OpenLayer.Map对象的实例:

var map = new OpenLayers.Map("area");

其中的参数能够传id,也能够传ElementObject,固然id更加方便一些。

接下来就是向地图中添加图层,一般状况下使用OpenLayers.Layer的子类来完成图层的初始化。

OpenLayers提供了一下Layers的扩展:

OpenLayers.Layer.Image

OpenLayers.Layer.HTTPRequest

OpenLayers.Layer.Grid

OpenLayers.Layer.WMS

OpenLayers.Layer.KaMap

OpenLayers.Layer.EventPane

OpenLayers.Layer.Google

OpenLayers.Layer.VirtualEarth

OpenLayers.Layer.Markers

OpenLayers.Layer.Text

OpenLayers.Layer.GeoRSS

OpenLayers.Layer.Boxes

OpenLayers.Layer.TMS

Image类封装一个实际图象做为图曾内容

HTTPRequest类能够接收一个动态生成的图片,你能够经过HTTPRequest类的参数向服务器发送参数

Grid类是HTTPRequest类的子类,提供更加详细的方法

WMS类用于链接WMS服务器以得到图象

KaMap类用于链接MapServer

EventPane类做为用于接收用户操做的图层

Google类用于从Google得到图象,它仍然须要你从Google得到API KEY,而且include

VirtualEarth类用于操做VirtualEarth的图层

Markers类用于生成接收和显示用户本地标记的图层

Text类用于接收CSV文件

GeoRSS类是Marker类的子类,用于封装接收GeoRSS并在图层中做出marker

Boxes一样也是Marker类的子类,能够用div来作marker,而非image

TMS用于接收TMS服务器的地图

建立完图层后,能够用MapaddLayer(layer)方法插入,并执行MapzoomToMaxExtent()方法让地图合适地显示。

OpenLayers还提供了丰富的Control类为地图浏览添加一些工具,继承自OpenLayers.Control

OpenLayers.Control.LayerSwitcher

OpenLayers.Control.MouseDefaults

OpenLayers.Control.MousePosition

OpenLayers.Control.MouseToolbar

OpenLayers.Control.OverviewMap

OpenLayers.Control.PanZoom

OpenLayers.Control.PanZoomBar

OpenLayers.Control.Permalink

OpenLayers.Control.Scale

这些类的实例会在地图浏览的“窗口”上增长一些工具栏或是“按钮”,增长互动性和功能性。

OpenLayers对经常使用的数据结构进行了封装

OpenLayers.LonLat

OpenLayers.Size

OpenLayers.Pixel

OpenLayers.Bounds

以便于操做。

此外OpenLayers.Util类能够对图片载入错误时图片框的颜色和图片框中默认的图片进行自定义,这一点是很是方便的。OpenLayersAjax类对建立XHR对象的过程进行了封装,可使用它进行简单的Ajax操做。

相关文章
相关标签/搜索