5.7. 演练:使用TileMill使用Mapnik创建瓦片

在本演练中,您将使用Mapnik(由TileMill包装)创建费城的通用基本地图。在接下来的课程中,你将能够在地图上覆盖主题层。本演练的数据是您在第3课中预处理的费城的基础数据。如果按照所有说明操作,则应将此数据保存在名为c:dataPhiladelphia或类似文件夹中。它应该使用墨卡托投影EPSG:3857。

Mapnik 是一个FOSS地图绘制引擎,通常用于制作地图图像块集。Mapnik结合了抗锯齿等技术,使线条和标签的边缘看起来平滑,而不是像素化。它不依赖于任何其他GIS软件框架的开销,这一事实提高了它的性能。支持各种类型的基于文件的数据和空间数据库作为地图的数据源。

要使用Mapnik,需要定义一组数据源,然后将它们连接到一组样式规则。您可以设置样式规则using an XML file ,或者你可以write them programmatically 使用像Python这样的语言。配置完数据源和样式规则后,可以指示Mapnik导出地图的图片。

这在理论上很简单,但对初学者来说不是最简单的过程,特别是当你的编程技能很弱的时候。在本课程中,要使用Mapnik,您将使用一个名为TileMill的程序,该程序使过程简单得多。TileMill在Mapnik周围放置了一个GUI,允许您浏览要使用的数据集,并在为每个层应用样式规则时查看工作结果。与使用XML文件或代码定义规则不同,您将使用一种相当直观的语言CartoCSS,它借鉴了web样式表的结构。

TileMill 是自由/开源软件,但它是由Mapbox开发的,目的是与该公司的营利性瓦片托管服务集成。当您使用TileMill 导出tiles并且结果文件的扩展名为.mbtiles时,这一点很明显。如果您不想在Mapbox的服务器上托管这些磁贴,可以从.mbtiles文件中“解包”这些瓦片,并将它们作为单独的图像托管在您自己的web服务器上。在本演练中,您将解压缩图像并将其托管在Penn State PASS web空间中。然后,您将通过向web地图提供tiles的URL结构来测试tiles。

完成本演练时,您可能会偶尔看到软件消息,说明Tile Mill未处于活动开发中,并且Mapbox已将其焦点转移到Mapbox Studio。Tile Mill继续作为一个FOSS工具,用于构建栅格化地图图像的瓦片集。相比之下,Mapbox Studio致力于创建矢量图块,然后Mapbox将托管矢量图块以换取费用。请注意,您专业地遇到的Mapbox Studio生成的.mbtiles文件可能包含矢量瓦片,而不是包含栅格化图像,如我们将在本演练中使用的瓦片磨坊生成的.mbtiles文件。

5.7.1. 安装TileMill并设计地图

  1. 从以下链接下载并安装TileMill:TileMill 。 接受所有的默认值。安装TileMill时,Mapnik也会为您安装。

  2. 通过单击TileMill>Start TileMill从Windows的“开始”菜单启动TileMill。

  3. 单击“新建项目”并按下图所示填写信息。然后单击“添加”。

../../_images/tilemill_new_project.png

图5.8 TileMill新项目图形用户界面

如果要缓存栅格图像,可能需要使用有损jpeg图像格式来减小缓存大小。因为我们正在制作矢量地图,所以png格式很好。

请注意,使用矢量数据的地图并不意味着您需要使用矢量瓦片。我们地图中的矢量将被瓦片创建过程栅格化,这意味着用户将只看到一堆“数据图片”。

  1. 在项目列表中,单击PhillyBasemap并查看画布。在tilemil中,地图预览显示在左侧,CartoCSS代码显示在右侧。每当您保存CartoCSS代码时,地图都会更新。

让我们通过将背景颜色从蓝色更改为白色来了解这个过程是如何工作的。

  1. 将background color属性设置为#FFFFFF(白色的HTML十六进制代码),如下所示,然后单击Save。

Map {
   background-color: #FFFFFF;
}

保存代码后,背景应该立即更新为白色。现在,让我们添加一些层,并遵循此过程来设置它们的样式。

  1. 单击“图层”按钮,然后单击“添加图层”。

../../_images/tilemill_add_layer.png

图5.9 TileMill添加层GUI

  1. 使用如下所示的确切属性将city_limits.shp shapefile添加为层(确保它位于EPSG:3857投影中)。

../../_images/tilemill_add_city_limits.png

图5.10 TileMill添加层GUI

这里有几件事值得一提。首先,TileMill允许您使用类和ID的概念设置样式规则的不同粒度级别。例如,如果要为所有街道设置一些常规规则,则可以为所有街道设置一个类,如果要为街道的某个子组设置一些更具体的规则,则可以为该子组使用ID。您只需要在city limits图层上设置一个样式,因此这些说明告诉您将类和ID设置为相同的名称。实际上,为了简单起见,本教程中的每个层都将使用相同的ID和类名。

此外,在使用最初使用OGR投影到EPSG:3857中的文件时,投影代码900913必须定义为空间引用。这两个投影是等效的,但是如果让TileMill 自动检测空间引用,您将看到由于投影参数的解释方式而与Google的tiles有偏移。

  1. 2级的起始视图放大过远,无法在费城使用,因此请使用“缩放到范围”按钮将地图放大到“城市限制”图层。

../../_images/tilemill_zoom_to_layer.png

图5.11“瓦磨机层缩放到范围”对话框

  1. 默认的CityLimit样式使城市看起来像一个大公园,因此使用以下代码将样式更改为简单的边界:

#CityLimit {
  line-color:#88789e;
  line-width:3;
}

保存时,应看到以下内容:

../../_images/tilemill_city_limit_styled.png

图5.12 TIleMill样本输出

现在您已经完成了添加图层和设置图层样式的过程,说明将开始更快地移动。我将提供有关要添加哪些层的信息,以及一些基本代码来设置它们的样式。请确保为您的层添加的ID与我在代码中使用的ID匹配(请记住,该ID是#符号后面的名称,例如#CityLimit或#Waterways)。

如果你不喜欢我的样式,你可以试着根据自己的喜好调整它,但要注意保持合法的语法。Carto按钮提供有关如何使用不同属性的参考文档。

不要花太多时间对地图样式进行重大更改,因为在本周的作业中,您将有机会制作自己的地图。完成演练后,可以使用此费城地图进行进一步的练习和实验。

../../_images/tilemill_carto_button.png

图5.13卡托图形用户界面

  1. 将waterways.shp添加为图层,并添加以下代码以设置其样式。将这段代码粘贴到CSS中的位置无关紧要。

#Waterways {
  line-width:1;
  line-color:#89aceb;
}
  1. 添加natural.shp作为图层,并添加以下代码以设置其样式。

#NaturalFeatures{
  [type='park']{
  polygon-opacity:1;
  polygon-fill:#ae8;
  }
  [type='riverbank']{
  polygon-opacity:1;
  polygon-fill:#89aceb;
  }
  [type='water']{
  polygon-opacity:1;
  polygon-fill:#89aceb;
  }
}

请注意,如果只想在数据集中显示要素的子集,则可以添加查询项。我们只展示公园、河岸和水景,尽管在这个形状文件中有很多类型的特色。

  1. 添加Neighborhoods.shp作为图层,并添加以下代码来设置其样式。

#Neighborhoods[zoom>12] {
  text-name:[NAME];
  text-face-name:"Arial Black";
  text-fill:#88789e;
  text-size: 12;
  text-character-spacing: 2;
  text-transform: uppercase;
}

在这种情况下,我们只指定文本属性。这样做的效果是隐藏邻域边界,以便仅显示邻域名称的标签。不管怎么说,这更适合社区,因为他们没有严格的边界。

在TileMill中标记图层时,需要指定包含标签文本的数据集中字段的名称。在这种情况下,您希望基于“名称”字段进行标记,因此您可以放置文本名称: [NAME] 。

另外,请注意,可以在图层上设置一个条件,使其仅在放大到某个级别以上时才显示。放大过去的12级,以确保这是正确的工作,你看到的邻里标签。

../../_images/tilemill_neighborhoods.png

图5.14样品输出

  1. 添加roads.shp作为图层,并为其指定主要道路的ID和类名。然后添加以下代码来设置样式。

#MajorRoads{
  [type='motorway']{
   line-width:3;
   line-color:#606060;
  }
  [type='trunk']{
   line-width:3;
   line-color:#606060;
  }
  [type='primary'] {
   line-width:2;
   line-color:#838383;
  }
}

这将象征着主要的道路。OpenStreetMap有很多不同的道路类型,您可以通过不同的方式在这里应用样式。在我们的情况下,我们将通过重新添加所有道路并将它们放置在主要道路下面来显示次要街道。这引入了一些冗余,但使代码更简单。

  1. 再次将roads.shp添加为图层,但这次,请为其指定道路的ID和类名。然后,添加以下代码来设置样式。

#Roads[zoom>12]{
  line-width:1;
  line-color:#b6b6b6;
}

#Roads[zoom>14]{
  line-width:1;
  line-color:#b6b6b6;
  text-name:[name];
  text-face-name:"Arial Regular";
  text-fill:#838383;
  text-size: 11;
  text-placement: line;
  text-min-path-length:100;
  text-avoid-edges:true;
  text-min-distance:50;
  text-dy: 6;
  text-max-char-angle-delta: 15;
}

放大后会在道路上贴上一些标签。

  1. 将railways.shp添加为图层,并添加以下代码以设置其样式。

#Railroads{
  line-width:1;
  line-color:#d2bcb0;
}

#Railroads[zoom>15] {
  ::line, ::hatch { line-color: #d2bcb0; }
  ::line { line-width:1; }
  ::hatch {
    line-width: 4;
    line-dasharray: 1, 24;
  }
}
  1. 按以下顺序放置图层(单击并拖动到图层名称的左侧),然后保存地图。

../../_images/tilemill_layer_order.png

图5.15层列表图形用户界面

缩小后,您的地图应该如下所示:

../../_images/tilemill_map_zoom_11.png

图5.16放大输出示例

放大后,您的地图应如下所示:

../../_images/tilemill_map_zoom_15.png

图5.17放大输出的示例

最后的代码应该是这样的,尽管层可能以不同的顺序列出。

Map {
  background-color: #FFFFFF;
}

#CityLimit {
  line-color:#88789e;
  line-width:3;
}

#Waterways {
  line-width:1;
  line-color:#89aceb;
}

#NaturalFeatures{
  [type='park']{
  polygon-opacity:1;
  polygon-fill:#ae8;
  }
  [type='riverbank']{
  polygon-opacity:1;
  polygon-fill:#89aceb;
  }
  [type='water']{
  polygon-opacity:1;
  polygon-fill:#89aceb;
  }
}

#Neighborhoods[zoom>12] {
  text-name:[NAME];
  text-face-name:"Arial Black";
  text-fill:#88789e;
  text-size: 12;
  text-character-spacing: 2;
  text-transform: uppercase;
}

#MajorRoads{
  [type='motorway']{
  line-width:3;
  line-color:#606060;
 }
  [type='trunk']{
  line-width:3;
  line-color:#606060;
 }
  [type='primary'] {
  line-width:2;
  line-color:#838383;
 }
}

#Roads[zoom>12]{
  line-width:1;
  line-color:#b6b6b6;
}

#Roads[zoom>14]{
  line-width:1;
  line-color:#b6b6b6;
  text-name:[name];
  text-face-name:"Arial Regular";
  text-fill:#838383;
  text-size: 11;
  text-placement: line;
  text-min-path-length:100;
  text-avoid-edges:true;
  text-min-distance:50;
  text-dy: 6
  text-max-char-angle-delta: 15;
}

#Railroads{
  line-width:1;
  line-color:#d2bcb0;
}

#Railroads[zoom>15] {
  ::line, ::hatch { line-color: #d2bcb0; }
  ::line { line-width:1; }
  ::hatch {
   line-width: 4;
   line-dasharray: 1, 24;
 }
}

5.7.2. 导出和提取瓦片

一旦你完成了地图设计阶段,你的地图在每一个比例尺上看起来都很好,你就可以开始考虑生成图块了。对于大型地图,考虑到本课前面讨论的一些因素(如地图的形状和选择生成的比例级别),计划此操作需要一些时间。

本演练的这一部分介绍如何生成费城基础地图的分幅,将其解压缩,并将其托管在web空间中。然后在网页上测试它们。

  1. 在代码中进行一个小的更改以增加默认值buffer size around the metatile 。这有助于避免在绘制瓦片时切断非常宽的标签。您可以在代码顶部的地图部分添加此项,如下所示:

Map {
  background-color: #FFFFFF;
  buffer-size: 512;
}
  1. 在TileMill中,单击导出按钮并选择MBTiles。这是MapBox的格式,用于将所有分幅存储在SQLite数据库中。我们最终将把它们作为单独的PNG图像解包。

  2. 定义缓存的区域和原点。要执行此操作,请使用左侧的地图视图放大到费城。然后按住Shift键并拖动鼠标左键,在费城市边界周围绘制一个框。确保以相当大的比例(放大)执行此操作,以便不会为大量外围空白创建瓦片。

将地图缩放到所需区域后,在地图中间单击鼠标右键以放置瓦片的中心点。如果看起来你的地图已经消失了——它还没有消失——一定要反复缩放和调整大小(TileMill可能会将你重置为缩放0,使你的地图看起来很小),直到你回到一个更合理的缩放级别。

你的地图应该是这样的:

../../_images/tilemill_area_of_interest.png

图5.18示例地图输出

  1. 在右侧菜单中,将缩放滑块设置为覆盖级别0到17,如下所示。请注意,移动滑块(尤其是在较大的缩放级别)会如何影响潜在瓦片的数量。

../../_images/tile_mill_zoom_slider.png

图5.19缩放滑块图形用户界面

不要更改此面板上的任何其他默认设置。

  1. 单击Export,并注意进度条(在Export-View Exports下),让您知道还有多少时间可以完成瓦片。在创建磁瓦片,您可以继续并执行接下来的一些步骤,不过,如果打开Windows任务管理器,您将看到名为node.exe(或Evented I/O)的进程在绘制磁贴时耗尽了大部分CPU电源。

要打开这些瓦片,我们将使用一个名为MBUtil的实用程序。您需要从GitHub上的主页(一个在线存储库,开发人员经常喜欢在这里与世界共享他们的代码)下载这个。

  1. 前往MBUtil page on GitHub 然后单击Clone或下载>下载ZIP。将zip文件保存到计算机。

  2. 将zip文件的内容提取到一个非常容易记住的路径中,例如c:mbutil。

  3. MBUtil需要Python,因此请确定Python.exe在计算机上的安装位置。查找一个文件夹,如c:Python27或c:Python27ArcGIS10.4(它可能已与ArcGIS一起安装)。如果在计算机上找不到python.exe,请访问python.org并下载python 2.7并在默认路径中安装。

在本教程中,我将假定c:Python27python.exe是您的python路径。如果您的Python安装在不同的位置,只需调整示例中的路径以匹配您自己Python.exe的路径。

  1. 在Windows资源管理器中,转到My DocumentsMapboxexport并找到PhillyBasemap.mbtiles。这些都是你的瓦片。将此文件复制到一个容易记住的位置,例如c:dataPhiladelphia。由于某些原因,我无法提取过去的瓦片,当它们位于“我的文档”文件夹中时。

  2. 打开命令提示符。(在Windows上,单击“开始”,然后在搜索框中键入cmd。)

  3. 通过运行以下命令提取所有瓦片:

    c:\python27\python.exe c:\mbutil\mb-util c:\data\Philadelphia\PhillyBasemap.mbtiles c:\data\Philadelphia\PhillyBasemap

请注意,这些参数依次是Python的路径、mb util实用程序的路径、压缩瓦片的路径以及希望瓦片解压缩的新文件夹。如果任何路径不同,则在键入此命令时需要调整它们。运行此命令后,您应该会在文件夹c:\ data\ Philadelphia\ PhillyBasemap中看到一组未压缩的瓦片。

../../_images/extracted_tiles.png

图5.20显示每个缩放级别的瓦片文件夹的文件对话框

5.7.3. 托管和测试瓦片

如果在已解包的瓦片文件夹中导航,您会注意到图像被提取到一个高度组织的levelcolumnrow 结构中。这种结构被各种地图程序和 API所理解,因此此时您所要做的就是将tiles放到面向web的服务器上。一个方便你实验的地方是你的通行证空间中的www文件夹,一个面向公众的目录,所有宾夕法尼亚州立大学的学生都在他们的个人网络空间中。我们将把瓦片放在那里,然后在网络地图上测试它们。

  1. 在Windows资源管理器中,右键单击未压缩磁贴的文件夹,然后单击“发送到>压缩(zipped)文件夹”。这将生成一个名为PhillyBasemap.zip的文件夹。

    像这样压缩文件夹可以让你一次发送所有文件,而不是单独上传(这太繁琐了,不实用)。

  2. 打开web浏览器PASS Explorer site

  3. 使用Penn State访问帐户登录并导航到 [www] 文件夹。

    如果您没有此文件夹,请转到Work.psu并单击左侧的链接以请求个人web空间。完成所需的简短测验,然后等待一两分钟以创建您的个人页面。

    手动创建名为 [www] 将不适用于此练习;您必须从宾夕法尼亚州立大学将此文件夹作为个人web空间申请。

    不管你的 [www] 文件夹是否已创建,请求更多存储将很有帮助。默认情况下,Penn State给您100 MB,但您可以将此限制增加到10 GB。您可以在同一站点work.psu上执行此操作,方法是将“更改配额”下拉列表调整为10 GB。

  4. 内 [www] 创建名为的新文件夹 [瓦片] 并导航到它。

  5. 单击上载按钮。

  6. 浏览到PhillyBasemap.zip文件夹并选中“自动提取”框。

../../_images/pass_upload.png

图5.21 Tile上传GUI

  1. 单击“上载”,然后等待您的瓦片上载和提取。完成后,您应该能够导航到如下结构:

../../_images/pass_extracted_files.png

图5.22显示tiles文件夹的PASS Explorer GUI

  1. 通过点击结构的URL来测试tilehttp://personal.psu.edu/<your_psu_ID>/tiles/PhillyBasemap/15/9555/12400.png。URL中的<your_PSU_ID>部分需要替换为您自己的ID,即@PSU.edu之前的PSU电子邮件地址部分。你应该得到一个像下面这样的图像。

../../_images/pass_extracted_files.png

图5.23

现在,让我们看看是否可以将此添加到在线地图以测试磁贴外观和导航体验。我们将使用ArcGIS.com地图查看器,这是一个基于浏览器的软件,用于制作网络地图。它可以免费用于实验或与公众共享地图。

我们在这里使用ArcGIS.com地图查看器仅仅是因为它是测试瓦片地图层的一种快速便捷的方法。本演练中不依赖于ArcGIS软件。

  1. 打开ArcGIS的浏览器并单击屏幕顶部的地图链接。你会看到一张Esri提供的地图,我们会把它换成费城的底图。

  2. 单击“添加>从Web添加层”。(如果没有看到“添加”按钮,请首先单击“修改贴图”链接。)

  3. 选择从瓦片层添加数据,然后按如下所示填充对话框,再次替换URL中您自己的Penn State ID(替换sdq107),但保留其他内容不变。请注意,若要设置范围,必须单击“设置瓦片覆盖率”并在费城周围绘制一个框。你不需要得到完全相同的坐标如下所示。

../../_images/add_tile_layer_arcgiscom.png

图5.24从GeoServer中的Web GUI添加层

  1. 单击“添加图层”。如果长时间没有发生任何事情,请重复并确保URL字段中没有错误。在你的费城地图上导航来测试它。表演要快,要脆。如果您打开浏览器开发工具的网络实用程序,您应该能够看到正被带到地图中的分幅。

../../_images/tiles_in_arcgiscom.png

图5.25示例地图输出

  1. 或者,您可以在上面添加其他web层,但是,为了节省时间,这里将不介绍这一点。在以后的课程中,您将学习如何在不使用ArcGIS.com的情况下以编程方式构建此类web地图。