6.3. 使用Web 制图API的编程模式

如果您在组织中作为一个能够开发web地图的人而与众不同,那么您很可能最终会被要求使用上一节中描述的不止一个API。如前所述,项目环境和需求可以强制为不同的努力选择不同的API。作为一个程序员,理解你所使用的API和语言背后的一般结构、模式和架构是很重要的,这样你就可以随时学习新的API和语言。技术总是在变化,如果你把自己绑在一个单一的开发模式上,你将限制你的效用。

下一节描述了一些模式和特性,这些模式和特性在前面描述的许多(但不是所有)web地图 API中是共同的。我在深入到Leaflet之前包含了这一部分,这样当我们开始查看代码时,您就可以了解到Leaflet的一些特性。不过,我也包括了一些示例片段来说明这个概念是如何在 Leaflet 中实现的。

几乎所有使用Web 制图API的页面都包含以下内容:

6.3.1. 对JavaScript文件和样式表的引用

在开始之前,HTML页面需要包含指向Web 制图API的JavaScript文件的<script>标记。请注意,您引用的JavaScript越多,加载页面所需的时间就越长。有些API比其他API更纤细(因此有一个类似于ModestMaps的名字),但提供的功能可能更少。当采用一个更大的API(如OpenLayers)时,一些开发人员构建并引用自己的API的较小版本,该版本只包含他们想要提供的函数。

有几种方法可以引用API。一种方法是在自己的服务器上下载并托管API,从而最小化加载时间并允许您自定义API。第二种方法是引用其他服务器上的API。称为内容交付网络(CDN)的网站专门托管常用的API。这是 Leaflet 的CDN URL,在页眉内的脚本标记中引用:

<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js"></script>

在本课程中,为了简单起见,我们将以这种方式通过CloudFlare CDN参考 Leaflet 。这要求您在测试代码时维护Internet连接。请注意,如果您正在开发一个内部应用程序,需要对API硬件进行完全控制,或者需要以任何方式自定义API,则需要自己下载并托管API。

许多Web 制图API提供了一些样式表,可帮助您开始制作美观的应用程序。您可以通过将CSS托管在自己的服务器上或使用CDN来以CSS文件的形式引用这些样式表。您可以使用以下语法从头部的CloudFlare CDN将Leaflet样式表导入页面:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" type="text/css" crossorigin="">

6.3.2. 地图 div 和对象

当您想在页面中放置地图时,通常会使用HTML<div>标记划出一些空间。然后使用API创建一个map对象并将其与div关联。

例如,使用说明书,您可以在页面主体中创建这样的地图div。

<div id="mapid"></div>

在页面的其他地方,在JavaScript代码中,您可以创建一个Leaftlet 地图对象,并将其与div关联起来。L.Map构造函数以div名称作为参数(L代表此处的shelf库)。

var myMap;
myMap = new L.map('mapid');

地图包含用于获取当前图层集,将地图居中,缩放至给定坐标等的方法。在许多Web映射API中,地图是功能最强大的对象之一。每当您采用新的地图 API时,请查看该地图对象的参考文档,以了解其功能以及调用最常用方法的语法。

6.3.3. 图层对象

大多数Web 制图API提供了定义层对象的方法,您可以将层对象逐个添加到地图对象中以创建mashup。需要注意的是,从这个意义上说,层可以表示web服务,比如WMS或瓦片服务,它本身包含许多底层数据层。但是,您只需要一个layer对象就可以将这种类型的web服务引入到地图中。引用单个数据文件的其他层对象(如KML或GeoJSON)更易于概念化。

在许多Web 制图api中,层是提供一组公共属性的抽象(或“基类”)类,并且仅通过更具体的类向开发人员公开。查看中提供的方法和事件Leaftlet's Layer 基类。这些方法包括从地图中添加和删除图层以及管理弹出窗口和工具提示等元素。现在看看一些更具体的派生类的属性,比如TileLayer , WMS ,和GeoJSON 查看与这些层类型相关联的一些更具体的方法。通常,您将在这个较低的级别上使用API帮助文档;但是,重要的是记住,无论何时使用这些特定的层类型,您仍然拥有Layer类的所有属性和方法。

在 Leaflet 中创建新图层时,通常需要提供包含该图层源数据的URL或文件路径。在调用addTo(…)方法之前,该层不会显示在地图上。根据 Leaflet 文档改编,有一种方法可以创建引用WMS的图层并将其添加到基础地图中:

var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
    layers: 'nexrad-n0r-900913',
    format: 'image/png',
    transparent: true,
    attribution: "Weather data © 2012 IEM Nexrad"
});

nexrad.addTo(myMap);

如果上述所有参数的含义不是很明显,请不要担心。重要的是要认识到这个层需要你在它能够识别WMS之前提供一个URL。您还可以切换透明度选项并为图层提供属性文本。

如果在其他层上调用addTo(…)方法,它将被放置在第一层的顶部。

许多类型的瓦片层包括每个URL中的瓦片缩放级别、行和列编号。在 Leaflet 中创建这些层时,提供特定的URL是没有意义的,因为这样只会指向一个瓦片。相反,可以使用{x}、{y}和{z}分别为列、行和缩放级别提供通用格式。这有点像您在上一课中将瓦片添加到ArcGIS在线地图查看器时所做的。

// create and add OpenStreetMap tile layer
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
});

osm.addTo(map);

6.3.4. 图层样式设置机制

已经由服务器绘制的图层(如瓦片地图和WMS图像)已经应用了样式设置,但是对于由浏览器绘制的图层(如GeoJSON或geoss),必须定义图层的样式设置方式。Web 制图api通常提供一组属性,您可以在这样的层上设置这些属性来定义浏览器应该如何绘制它。这些属性包括填充宽度、填充颜色、轮廓宽度、轮廓颜色等。在手册中,通常将样式定义为可以在层构造函数中引用的函数,如下所示:

function parkStyle(feature) {
    return {
        fillColor: '#FF00FF',
        fillOpacity: 1,
        color: '#B04173',
    };
}

var gardenLayer = new L.GeoJSON.AJAX('gardens.geojson', {
    style: parkStyle
});

gardenLayer.addTo(map);

style函数返回一组样式属性(在本例中为fillColor、fillOpacity和color),这些属性将在从图层绘制要素时应用。在这个简单的例子中,所有的功能看起来都是一样的。但是,由于样式函数具有要作为参数绘制的特征(函数参数特征),因此我们可以使用特征的属性来计算其样式属性值,例如根据其属性之一对所有特征进行不同的着色。你稍后将在本课程中学习如何做到这一点。

许多api允许您使用自定义图像作为标记,而不是放置一个简单的点。下面的小册子示例演示如何将杂货店的GeoJSON层添加到地图中,并使用保存在SVG(scalable vector graphics,可缩放矢量图形)文件scrible.SVG中的购物车图标对其进行样式设置。这可以很容易地成为PNG文件或其他栅格化图像类型。

// create icons for supermarkets
var groceryIcon = L.icon({
    iconUrl: 'grocery.svg',
    iconSize: [20,20]
});

// create a vector layer of grocery stores from GeoJSON data
var groceryLayer = new L.GeoJSON.AJAX('supermarkets.geojson',{
    pointToLayer: function (feature, latlng) {
        return L.marker(latlng, {icon: groceryIcon});
    }
});

groceryLayer.addTo(map);

当放在基本地图层的顶部时,结果可能如下所示:

../../_images/grocery_icon.png

图6.1

如果你还不完全清楚上面的代码,不要担心。只需确保您可以看到通过JavaScript对象定义样式的位置。在第7课中,您将进一步了解GeoJSON和设置浏览器绘制图形的样式。

6.3.5. 事件和交互元素

Web 制图API提供了交互式元素,这些元素可以帮助您的地图不仅仅是HTML页面上的静态图片。通常,上述地图和图层对象使您可以响应某些用户操作(例如单击鼠标)来运行代码。用户操作称为事件(或触发事件)。您作为响应运行的代码称为事件处理程序,通常会进入其自己的代码功能块。有时,事件可以通过包含事件属性的“事件对象”向处理程序函数提供参数,例如触发事件的鼠标单击的屏幕坐标。

例如,您可以指示地图“侦听”鼠标单击事件。然后,您可以编写一个处理函数,获取事件参数的屏幕坐标(换句话说,单击像素的坐标)并将其转换为地图坐标,然后将坐标写入HTML页面中的标签,以便用户可以看到它们。通过将此处理程序函数连接到悬停事件(而不是单击)可以实现更大程度的交互性。然后,当你在屏幕上移动鼠标时,你会看到鼠标的坐标。

Web地图用户通常希望获得有关地图中特定功能的更详细信息。通过显示包含有关单击功能的更多信息的弹出窗口来处理单击事件是非常常见的;事实上,许多web API都有用于弹出窗口的特殊类和方法,不需要编写典型的事件侦听逻辑。在本课程的后续课程中,您将在 Leaflet 中了解更多有关弹出窗口的信息。

有时弹出窗口在空间或复杂度上对于想要显示的内容来说太有限。即使您的地图 API 允许您将大型图像或选项卡式接口塞进弹出窗口中,在页面的其他位置的 HTML div 中显示此类内容通常更有意义。Web 制图API允许您对单击的点执行查询,并从单击的功能中检索属性信息(通常作为处理程序函数的一部分,如上文所述)。然后,可以使用此处理程序函数执行任何操作,以便以HTML格式显示信息。您甚至可以将信息传递给另一个专门的API,该API绘制图表、查询Wikipedia、查找附近的待售房屋等等。

所需交互的另一个常见部分是关闭和打开图层的功能。记住,在这个意义上,“层”是一个完整的web服务。显然不可能在瓦片地图中切换单个子图层的可见性,因为所有图层都“烧录”到瓦片图像中。但是,您可以切换到不同的基础瓦片地图,或者关闭放置在其上的WMS或GeoJSON层。

Leaflet offers a Layers Control that acts like a table of contents for toggling visibility. You create your layers as usual, but instead of adding them to the map individually, you organize them in JavaScript objects for your base layers and overlays (thematic or business layers). Suppose you have two layer variables, grayscale and streets, representing tiled maps, and one layer variable cities representing a layer of city points. Again, from the Leaflet doc, here is how you can add the layer switching control with these defined as base layers and overlays:

var baseLayers = {
  "Grayscale": grayscale,
  "Streets": streets
};

var overlays = {
  "Cities": cities
};

L.control.layers(baseLayers, overlays).addTo(map);

既然您已经熟悉了Web 制图API的不同元素,并且已经看到了这些元素是如何在 Leaflet 中表达的,那么我们将继续讨论并查看一些功能齐全的示例。