教程:使用 arcpy.mapping 进行的基本 Web 地图打印/导出
在本教程中,您将构建 Web 应用程序,使最终用户能够导航至感兴趣区域并按下打印按钮。输出为方便打印的 PDF 文档,其中包含了服务图层矢量输出。
使用 ArcGIS Web API 中开箱即用的打印工具服务及其客户端打印微件从 Web 应用程序中进行导出,可输出高质量的服务图层图像。但是,有时需要矢量输出。例如,矢量 PDF 输出在 PDF 查看应用程序中支持以下功能:切换图层可见性、查看要素属性以及查看地图坐标。在将要构建的 Web 应用程序中,您会输出世界地形图底图服务的矢量化表示。世界地形图底图服务的小区域的矢量子集在 ArcGIS Resource 上公开提供给所有用户。
要生成含有本地矢量数据而非服务图层图像的输出文档,您必须具有访问相应矢量数据的权限。
下图显示了将要构建的 Web 应用程序。
Web 应用程序中打印按钮后的代码使用了 ArcGIS Web API 打印任务,该任务从 ArcGIS 10.1 for Server 开始提供。您将创建 Python 脚本,该脚本将作为打印任务所用的地理处理服务发布。Python 脚本使用 arcpy.mapping 模块中的 ConvertWebMapToMapDocument 函数,该函数会将 web 地图的完整状态插入过渡的模板地图文档。模板包含了地图服务中所有可能图层的矢量化表示。arcpy.mapping 模块还可用于移除服务图层,同时将已过渡的本地矢量数据保留在模板地图文档中,并导出至 PDF。
单击打印按钮后,输出将会是方便打印的 PDF 文档,该文档包含了本地矢量数据而非服务图层的图像。
要完成本教程,应熟悉 arcpy.mapping 模块、ArcGIS Web API、ArcGIS for Desktop 和 ArcGIS for Server。本教程包含了所有 ArcGIS Web API 的示例代码。还应逐渐熟悉 web 应用程序帮助主题中的打印:
从 ArcGIS Resource Center 获取矢量数据
您可从 ArcGIS Resources 上的社区地图模板库中下载 zip 文件,其中包含了在已过渡地图文档模板中使用的矢量数据。
在此之前,需确保存在一个文件夹结构,并且在该结构中 ArcGIS for Server 可以查看将用于 web 应用程序的模板地图文档和数据。本教程假定存在注册到 ArcGIS for Server 的文件夹。有关将数据注册到 ArcGIS for Server 的详细信息,请参阅
在 ConvertWebMapToMapDocument 函数中使用模板地图文档时,最佳做法是使用注册到 ArcGIS for Server 的数据。如果选择不使用注册的数据,那么模板地图文档和数据将打包复制到服务器。在打包过程中, 数据可能移动并带着相对路径重新指向 ConvertWebMapToMapDocument 无法解析的文件夹结构。有关详细信息,请参阅 ConvertWebMapToMapDocument。
LGIM_World_Topo_Map_v1.5 地图文档现已准备就绪,可以在 Web 应用程序中使用。
创建 Python 脚本
您将创建用作自定义地理处理打印服务的 Python 脚本。
自定义地理处理打印服务中的 Python 脚本会执行 ConvertWebMapToMapDocument 功能,可转换想要打印或导出至地图文档的 Web 地图(以 JSON 格式)。该脚本随后会移除输出地图文档中的服务图层,保留与 Web 地图 JSON 中服务图层相对应的矢量图层。Web 地图 JSON 还包含了 Web 应用程序中的地图范围。最后,该脚本将地图文档导出至 PDF 文档。
- 打开任意的 Python IDE,如 IDLE(ArcGIS for Desktop 附带)。
- 将以下代码复制并粘贴到新的 Python 脚本中。
- 将 templateMxd 变量更改为包含模板地图文档的已注册文件夹中的文件夹 UNC 路径。
- 保存 Python 脚本。命名脚本 BasicTutorial.py。将其保存至已注册文件夹中名为 WebApp 的文件夹内。
import arcpy
import os
import uuid
# Input WebMap json
Web_Map_as_JSON = arcpy.GetParameterAsText(0)
# The template location in the server data store
templateMxd = '//MyComputer/MyDataStore/BasicTutorial/LG_062912_10.1/LG_062912_10.1/LGIM_World_Topo_Map_v1.5.mxd'
# Convert the WebMap to a map document
result = arcpy.mapping.ConvertWebMapToMapDocument(Web_Map_as_JSON, templateMxd)
mxd = result.mapDocument
# Reference the data frame that contains the webmap
# Note: ConvertWebMapToMapDocument renames the active dataframe in the template_mxd to "Webmap"
df = arcpy.mapping.ListDataFrames(mxd, 'Webmap')[0]
# Remove the service layer
# This will just leave the vector layers from the template
for lyr in arcpy.mapping.ListLayers(mxd, data_frame=df):
if lyr.isServiceLayer:
arcpy.mapping.RemoveLayer(df, lyr)
# Use the uuid module to generate a GUID as part of the output name
# This will ensure a unique output name
output = 'WebMap_{}.pdf'.format(str(uuid.uuid1()))
Output_File = os.path.join(arcpy.env.scratchFolder, output)
# Export the WebMap
arcpy.mapping.ExportToPDF(mxd, Output_File)
# Set the output parameter to be the output file of the server job
arcpy.SetParameterAsText(1, Output_File)
# Clean up - delete the map document reference
filePath = mxd.filePath
del mxd, result
os.remove(filePath)
如果 ArcGIS for Server、ArcGIS for Desktop 和已注册文件夹都在同一台计算机上,则无需已注册文件夹的 UNC 路径。但可以使用绝对路径。
创建 Python 脚本工具
您将创建运行 BasicTutorial.py 脚本的自定义地理处理工具。
- 在 ArcMap 的目录 窗口中,浏览至已注册文件夹目录中的 WebApp 文件夹。
- 右键单击 WebApp 文件夹并单击新建 > 工具箱。将该工具箱命名为 BasicTutorial。
- 右键单击 BasicTutorial 工具箱并单击项目描述。
- 在项目描述 对话框中,使用所选文本填充标签 和摘要 项目。或者,填写其他项目描述。
- 单击保存 并退出项目描述 对话框。
- 在目录 窗口中,右键单击 BasicTutorial 工具箱并单击添加 > 脚本。
- 在添加脚本 对话框中,为名称和标注输入 BasicTutorial。
- 单击下一步。
- 对于脚本文件,浏览至已注册文件夹中的 WebApp 文件夹并选择 BasicTutorial.py。
- 单击下一步。
- 两个参数需要添加至脚本工具。
- 第一个参数为 Web_Map_as_JSON。该参数采用要在地图在 Web 应用程序中显示时导出的地图状态的 JSON 表示。属性应与以下内容相匹配:
- 另一参数为 Output_File,即将创建的输出文件。属性应与以下内容相匹配:警告:
Web_Map_as_JSON 和 Output_File 参数名称必须完全按照以下所示拼写,以便与 ArcGIS Web API 中打印任务的工具签名相匹配。
- 单击添加脚本 对话框上的完成。
- 右键单击 BasicTutorial 脚本工具并单击项目描述。
- 在项目描述 对话框中,使用所选文本填充标签和摘要项目。同样,使用所选文本填充项目描述 对话框语法部分内所有四个参数的对话框说明。或者,填写其他项目描述。
执行工具
需要成功执行工具以在结果 窗口中创建可发布到 ArcGIS for Server 中的结果。
- 在目录 窗口中,右键单击 BasicTutorial 脚本工具并单击打开。
- 将 Web_Map_as_JSON 输入参数留空。提示:
出于发布目的,由于 ArcGIS Web API 将在 Web 应用程序中提供 Web 地图 JSON,因此您可将 Web_Map_as_JSON 输入参数留空。如果 Python 脚本的写入方式使其在空白输入时仍能正常执行,则可将 Web_Map_as_JSON 输入参数留空。例如,脚本不会按名称查找 Web 地图图层。
- 单击确定。等待工具完成执行。
结果现已准备就绪,可作为地理处理服务发布。
- 打开结果 窗口。
- 展开当前会话。
- 右键单击 BasicTutorial 结果并单击共享为 > 地理处理服务。
- 检查发布服务。
- 单击下一步。
- 选择指向 ArcGIS for Server 计算机的发布或管理连接。
- 单击下一步。
- 单击下一步。
- 单击继续。
- 在服务编辑器 对话框的右上角,单击发布。
地理处理服务现已准备就绪,可以在 ArcGIS Web API 中使用。
选择想要用来创建 web 应用程序的 ArcGIS web API。
ArcGIS Web API 提供类似的 GIS 功能;您可以根据自己的偏好选择相应的开发平台。本教程不包含关于利用每种 API 开始构建 web 应用程序的详细介绍。有关该介绍的详细信息,请参阅 API 文档。有关详细信息,请参阅
每个 ArcGIS Web API 都拥有打印任务。打印任务具有一个 URL 属性,该属性将引用您之前所创建的自定义地理处理服务。有关打印任务的详细信息,请参阅 ArcGIS Web API 文档。
在以下部分中,使用用来构建 Web 应用程序的 ArcGIS Web API 的代码示例。
ArcGIS API for JavaScript 示例代码
如果您正在使用 ArcGIS API for JavaScript,那么请使用以下示例代码来构建 web 应用程序。
在以下 ArcGIS API for JavaScript 代码示例中,将 URL 更改为在上一步骤中创建的地理处理服务,以匹配服务器名称。在本行中进行引用:
var printUrl = "http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial";
BasicTutorial.html 的代码
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Webmap Printing</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.0/js/dojo/dijit/themes/claro/claro.css">
<script src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.0"></script>
<script type="text/javascript" language="Javascript">
dojo.require("esri.map");
dojo.require("esri.tasks.PrintTask");
var printTask, params;
function init() {
// set the extent to the Naperville area - which matches the extent of the template map document
var startExtent = new esri.geometry.Extent({"xmin":-9815098,"ymin":5124020, "xmax":-9811168,"ymax":5127339, "spatialReference":{"wkid":102100}});
var map = new esri.Map("map", {extent:startExtent});
// add tiled map service to webmap
var tiledUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";
var tiledLayer = new esri.layers.ArcGISTiledMapServiceLayer(tiledUrl);
map.addLayer(tiledLayer);
var printUrl = "http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial";
printTask = new esri.tasks.PrintTask(printUrl, {async: true});
params = new esri.tasks.PrintParameters();
params.map = map;
}
function print(){
var ptemplate = new esri.tasks.PrintTemplate();
// use the extent of the webmap in the output PDF
ptemplate.preserveScale = false;
params.template = ptemplate;
printTask.execute(params, printComplete);
}
function printComplete(result){
window.open(result.url);
}
dojo.addOnLoad(init);
</script>
</head>
<body class="claro">
<input type="button" id="print" value="Print" onclick="print();"/>
<div id="map" style="width:1000px; height:600px; border:1px solid #000;"></div>
</body>
</html>
ArcGIS API for Flex 示例代码
如果您正在使用 ArcGIS API for Flex,请使用以下示例代码构建 Web 应用程序。
在以下 ArcGIS API for Flex 代码示例中,将 URL 更改为在上一步骤中创建的地理处理服务,以匹配服务器名称。在这些行中进行引用:
url="http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial"/>
BasicTutorial.mxml 的代码
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:esri="http://www.esri.com/2008/ags"
initialize="printTask.getServiceInfo()"
pageTitle="High-quality printing">
<fx:Script>
<![CDATA[
import com.esri.ags.events.PrintEvent;
import com.esri.ags.tasks.supportClasses.DataFile;
import com.esri.ags.tasks.supportClasses.JobInfo;
import com.esri.ags.tasks.supportClasses.ParameterValue;
import mx.controls.Alert;
public var preserveScale:Boolean = true;
private function printBtn_clickHandler(event:MouseEvent):void
{
if (printTask.getServiceInfoLastResult.isServiceAsynchronous)
{
printTask.submitJob(printParameters);
}
else
{
printTask.execute(printParameters);
}
}
private function printTask_jobCompleteHandler(event:PrintEvent):void
{
var jobInfo:JobInfo = event.jobInfo;
if (jobInfo.jobStatus == JobInfo.STATUS_SUCCEEDED)
{
printTask.getResultData(jobInfo.jobId);
}
else
{
Alert.show(jobInfo.jobStatus);
}
}
private function printTask_getResultDataCompleteHandler(event:PrintEvent):void
{
var dataFile:DataFile = event.parameterValue.value as DataFile;
navigateToURL(new URLRequest(dataFile.url));
}
private function printTask_executeCompleteHandler(event:PrintEvent):void
{
var paramValue:ParameterValue = event.executeResult.results[0];
var dataFile:DataFile = paramValue.value as DataFile;
navigateToURL(new URLRequest(dataFile.url));
}
]]>
</fx:Script>
<fx:Declarations>
<esri:PrintTask id="printTask"
executeComplete="printTask_executeCompleteHandler(event)"
fault="Alert.show(event.fault.faultString)"
getResultDataComplete="printTask_getResultDataCompleteHandler(event)"
jobComplete="printTask_jobCompleteHandler(event)"
showBusyCursor="false"
url="http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial"/>
<esri:PrintParameters id="printParameters"
preserveScale="false"
map="{map}">
</esri:PrintParameters>
<esri:Extent id="initialExtent"
xmin="-9815098" ymin="5124020" xmax="-9811168" ymax="5127339">
<esri:SpatialReference wkid="102100"/>
</esri:Extent>
</fx:Declarations>
<s:controlBarLayout>
<s:HorizontalLayout gap="10"
paddingBottom="7"
paddingLeft="10"
paddingRight="10"
paddingTop="7"
verticalAlign="baseline"/>
</s:controlBarLayout>
<s:controlBarContent>
<s:Button id="printBtn"
click="printBtn_clickHandler(event)"
enabled="{printTask.getServiceInfoLastResult != null}"
label="Print"/>
</s:controlBarContent>
<esri:Map id="map" extent="{initialExtent}">
<esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
</esri:Map>
</s:Application>
ArcGIS API for Silverlight 示例代码
如果您正在使用 ArcGIS API for Silverlight,请使用以下示例代码构建 Web 应用程序。
XAML 代码
<UserControl x:Class="Basic_Tutorial.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:esri="http://schemas.esri.com/arcgis/client/2009">
<Grid x:Name="LayoutRoot" Background="White">
<esri:Map x:Name="MyMap" Extent="-9815098,5124020,-9811168,5127339">
<esri:Map.Layers>
<esri:ArcGISTiledMapServiceLayer ID="MyTiledService"
Url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>
</esri:Map.Layers>
</esri:Map>
<StackPanel Orientation="Vertical" Margin="15" HorizontalAlignment="Left" VerticalAlignment="Top" >
<Border x:Name="PrintPanel" CornerRadius="10" BorderBrush="Gray" BorderThickness="1" Background="White" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="15" Padding="10">
<Border.Effect>
<DropShadowEffect/>
</Border.Effect>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Button x:Name="Print" Content="Print" Click="ExportMap_Click"
Grid.Row="1" Grid.Column="0" Margin="2"/>
</Grid>
</Border>
</StackPanel>
</Grid>
</UserControl>
在以下 ArcGIS API for Silverlight 代码示例中,将 URL 更改为在上一步骤中创建的地理处理服务,以匹配服务器名称。在本行中进行引用:
printTask = new PrintTask("http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial");
C# 中的代码
using System;
using System.Windows;
using System.Windows.Controls;
using ESRI.ArcGIS.Client.Printing;
using ESRI.ArcGIS.Client.Tasks;
namespace Basic_Tutorial
{
public partial class MainPage : UserControl
{
PrintTask printTask;
public MainPage()
{
InitializeComponent();
printTask = new PrintTask("http://MyServer:6080/arcgis/rest/services/BasicTutorial/GPServer/BasicTutorial");
printTask.DisableClientCaching = true;
printTask.JobCompleted += new EventHandler<PrintJobEventArgs>(printTask_JobCompleted);
printTask.GetServiceInfoCompleted += new EventHandler<ServiceInfoEventArgs>(printTask_GetServiceInfoCompleted);
printTask.GetServiceInfoAsync();
}
void printTask_GetServiceInfoCompleted(object sender, ServiceInfoEventArgs e)
{
PrintPanel.DataContext = e.ServiceInfo;
}
void printTask_JobCompleted(object sender, PrintJobEventArgs e)
{
if (e.Error == null)
{
if (e.PrintResult != null)
System.Windows.Browser.HtmlPage.Window.Navigate(e.PrintResult.Url, "_blank");
}
}
private void ExportMap_Click(object sender, RoutedEventArgs e)
{
if (printTask == null || printTask.IsBusy) return;
PrintParameters printParameters = new PrintParameters(MyMap)
{
};
printTask.SubmitJobAsync(printParameters);
}
}
}
运行 Web 应用程序
运行在上一步骤中创建的 Web 应用程序。如有必要,请参阅 ArcGIS Web API 文档获取运行 Web 应用程序的说明。ArcGIS for JavaScript Web API 应用程序的屏幕截图如下。
放大至感兴趣区域并单击打印按钮。稍后,输出 PDF 文档将自动弹出。输入为方便打印的 PDF 文档,其中包含了在布局模板中过渡的本地矢量数据,而非服务图层的图像。请参阅如下示例输出:
使用 arcpy.mapping 进行的基本 Web 地图打印和导出教程到此结束。有关高级方案的详细信息,请参阅使用 arcpy.mapping 进行的高级 Web 地图打印和导出教程。