内蒙古java团队

j2se,j2ee开发组
posts - 139, comments - 212, trackbacks - 0, articles - 65
  语源科技BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

基于OpenLayers的地图小工具

Posted on 2010-11-12 00:02 帅子 阅读(2157) 评论(0)  编辑  收藏 所属分类: 申请加入java团队 、j2ee技术专区

提到小工具,就不得不提到 OpenLayers 。 OpenLayers (主页是 http://www.openlayers.org )是由 MetaCarta 最初发起的,用于在网页界面上展示地图的一套 Javascript 脚本框架。

MapGuide 的 Fusion 框架最为核心的地图 Widget ,就是采用了 OpenLayers 框架。 Fusion 框架对 OpenLayers 进行包装,为其添加了更多的功能,从而使之能够更符合 Fusion 框架并与其余 Fusion 组件进行交互。

非常有趣的是,由于 OpenLayers 所采用的术语跟 Fusion 采用的并不是十分一致,甚至 Fusion 不同部分采用的术语也不是十分一致,所以同一个名字在不同地方表达的意思却很可能并不相同。所以,在详细介绍 Fusion 如何对 OpenLayers 进行包装之前,有必要对两者之间的术语进行一下区分,以免当您阅读到相关材料时感到疑惑。

OpenLayers 认为,用户看到的由多个图层 (layer) 组成的一张地图 (map) 。地图本身与加载的数据源格式无关,与数据源格式相关的是图层。因此,地图类只有一个( OpenLayers.Map ),而图层类却有很多,这些类都以 OpenLayers.Layer 作为命名空间,如 OpenLayers.Layer.Google/Yahoo/MapGuide/WMS/Vector 等等。

这样的结构有一个问题,那就是所有的图层之间是平行的关系,这是很不利于图层管理的。我们假设有这样一张地图:该地图包含有十二个图层,有九个来自于不同数据源的图层和三个位于顶层的 Vector 层。那么,我如果想用代码去处理所有 Vector 的层,就必须遍历所有的层,依次比较是不是 Vector 层,再对 Vector 层进行处理。解决这个问题的方案很简单,那就是引入层级结构,允许用户把图层分组。比如上面的例子中,把三个 Vector 分成一组,比如命名为“标记”组,届时只需要对标记组中的每一个层进行处理即可。

这也正是 Fusion 对于 OpenLayers 众多改进中的一个。而问题也正是这里引入的:地图 Widget 在给这种层级结构命名的时候,出人意料地采用了另外的命名方式:地图 Widget 把图层组命名为“地图组” (map group) ,把组里面的图层命名为 (map) 。下面代码是示例数据中 Library://Samples/Sheboygan/FlexibleLayouts/Slate.ApplicationDefinition 布局文件对于地图定义的那一部分,用户可以在 MapGuide Studio 中通过点击位于 Map 面板上的 “Edit Map Group” 按钮来查看这部分内容。

<?xml version="1.0" encoding="utf-8"?>

<MapSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <MapGroupType id="Sheboygan">

    <Map>

      <Type>MapGuide</Type>

      <SingleTile>true</SingleTile>

      <Extension>

        <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId>

        <SelectionAsOverlay>true</SelectionAsOverlay>

        <SelectionColor>0x0000FFA0</SelectionColor>

      </Extension>

    </Map>

    <Extension />

  </MapGroupType>

</MapSet>

布局文件中地图定义的部分代码

其实, MapGuide 这样做是有原因的。这个问题源于不同产品之间定位的不同: OpenLayers 框架的目的是在同一张地图上面显示多个数据源。所以在 OpenLayers 看来,一个来自 MapGuide 的地图仅仅是一个层而已。然而,在 MapGuide 内部,一张 MapGuide 地图内是包含多个 Layer ,具体表现就是一个 MapDefinition 里可以包含多个 LayerDefinition 。所以,如果 Fusion 把 MapGuide 叫做一个 Layer 的话,又该如何称呼里面的 Layer 呢?

鉴于这样的考虑, Fusion 才做了这种概念上的映射: Fusion 中的地图 Widget 对应 OpenLayers 里面的地图; Fusion 里面的地图组是一个逻辑概念,从而形成一种逻辑上的层级结构以便管理; Fusion 中的地图实际对应于 OpenLayers 里面的图层。

但事情到这里还没有结束,接下来的事情可能会让您有些意外:在编写地图 Widget 实现代码时,为了能够便于与 OpenLayers 中的类对应起来, Fusion 将地图(也就是 OpenLayers 中的图层)称为 Layers (注意,不是 Layer ),并要求每一个地图的代码都继承自 Fusion.Layers 。比如, MapGuide 的 Layers 的名称就叫做 Fusion.Layers.MapGuide 。

下表总结了 Fusion 与 OpenLayers 之间这种概念映射关系

Fusion 概念

Fusion 代码命名

OpenLayers 概念

OpenLayers 代码命名

地图

Fusion.Layers

图层

OpenLayers.Layer

地图组

无对应概念

地图 Widget

Fusion.Widget.Map

地图

OpenLayers.Map

 Fusion 与 OpenLayers 之间的概念映射关系

在阅读 Fusion 和 OpenLayers 的源代码或学习他们的 API 时,一定要注意两者术语上的区别。

本节中,我们提到了 Fusion 引入了地图组这一个概念。这只是 Fusion 对于 OpenLayers 众多改动中的一个。下面我们来看看到底 Fusion 对 OpenLayers 还做了哪些改动。
Fusion 对于 OpenLayers 的改进
为了便于 Fusion 的其他组件能够与地图进行交互, Fusion 对于 OpenLayers 进行了较为全面的包装。一般来说,如果您不是开发 Fusion.Layers 的开发人员,除了使用一些 OpenLayers 的一些工具性的函数之外,您甚至都不需要知道 OpenLayers 的存在。但是,仅仅进行包装是不够的,由于 OpenLayers 与 Fusion 定位的不同, Fusion 必须对 OpenLayers 进行扩展才能适应更为复杂的模型。

1.       Fusion 中添加了选择集的概念。 OpenLayers 在同一张地图里面显示多种不同数据源的方面确实做的很好,遗憾的是,它缺少选择集这一至关重要的概念。对于 OpenLayers 来说,选择集完全是可有可无的,因为它的目的在于将地图展示出来,而且,很多地图根本就没有选择集这样的 API ,比如 Google 地图等等。但对于 Fusion 则不同,我们很难想象没有选择集,用户该如何利用 MapGuide 进行管理。所以, Fusion 加入了选择集这个概念,并且要求实现 Layers 的地图(比如 MapGuide )实现选择集功能。我们可以看到, Fusion.Widget.Map 中不但有诸如 get/set/clear/hasSelection 这样控制和读取选择集的函数,而且有 MAP_SELECTION_ON 和 MAP_SELECTION_OFF 这两个事件来通知监听者地图选择集的当前状况。

2.       Fusion 开放了更多的事件。借助于 Fusion 自己独立实现的事件机制, Fusion 允许用户接收到更多种类的事件,比如 Session 是否已创建、地图当前忙碌与否、选择集状态变更、当前图层(这个是 Fusion 中的图层,不是 OpenLayers 的)变化等等。

3.       Fusion 允许地图的实现类返回自身支持哪些比例尺,这就使得用户可以直观的知道自己当前缩放地图到什么程度。

4.       允许用户随时设置当前地图的背景图片和地图上的光标形状。这对于直观地反应地图当前状态是是否有用的。

5.       支持右键菜单。虽然在浏览器上实现右键菜单相对简单一些,但是通过使用地图 Widget 的 setContextMenu ,代码编写者就可以直接把已经准备好的 div 作为右键菜单,再也不需要直接与底层鼠标事件打交道了。

地图的定义
前面在介绍 Fusion 与 OpenLayers 术语不同的时候,摘录了应用程序定义中对于地图部分的定义。通过解析这个定义, Fusion 了解了应该如何加载该地图。下面,我们就来看看这个定义中到底都定义了哪些东西。

在 Fusion 中,一个地图组用一个 MapGroup 进行标签定义, MapGroup 里面的 Map 标签就是对于一个地图的定义了。

1.       Type: 该标签标示了地图的类型。所有 MapGuide 地图该标签的值均为 MapGuide 。当 Fusion 读取到该地图的 Type 时,就会用对应的 “Fusion.Layers. 标签值 ” 来初始化该地图。比如 MapGuide 地图就会用 Fusion.Layer.MapGuide 来初始化。

2.       SingleTile: 如果该项为真,则表示该项不采用分块服务。

3.       Extension: 该于扩展 Map 标签,来为地图初始化提供更多的信息。各个 Fusion.Layers 的实现类可以自行决定其需要的内容,以及如何解释这些内容。对于 MapGuide 而言,有以下常见的扩展:

a)         ResourceId: MapDefinition 的资源 Id ,通过该 Id , Fusion 可以知道加载哪一个地图定义。

b)        SelectionAsOverLay: 如果该项是 true ,那么将会使用 GETDYNAMICOVERLAY 来获取地图,否则采用 GETMAPIMAGE 来获取地图。前者是新版本才支持的,可以把选择集和地图本身绘制成两张地图。如果您使用的 MapGuide 版本比较旧,您可以把该项设置成为 false

c)         SelectionColor: 该项表示用什么颜色来显示选中的要素。