内蒙古java团队

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

基于OpenLayers的地图小工具

Posted on 2010-11-12 00:02 帅子 阅读(2092) 评论(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: 该项表示用什么颜色来显示选中的要素。


只有注册用户登录后才能发表评论。


网站导航: