在应用程序中,地图打印是一个经常被用到的操作。自10.1版本起,Esri就在ArcGIS for Server中提供了一个预先配置好的打印服务来实现打印操作。相应地,在ArcGIS API for JavaScript中也提供了PrintTask任务和Print控件,开发人员在使用时只需要将map或者view对象指定为打印对象,map或者view显示的信息就会被以JSON的形式传递给GIS服务器完成打印,极大地方便了前端开发人员调用GIS服务器中的的打印服务。但是PrintTask任务和Print控件存在的问题是:打印服务会按照当前map或者view显示的范围进行打印,用户不能细粒度地控制打印范围。针对这个问题,有两种解决方法:一种是拦截打印请求,修改打印请求中的参数;另一种方法是自行构造打印服务所需要的参数,直接调用REST打印服务。
两种方法都涉及对打印服务中参数的编辑,所以我们有必要先了解一下打印服务。打印服务本质上是一个地理处理服务,借助于Export Web Map Task工具输出一张用于打印的图片。Export Web Map Task工具需要四个输入参数,分别是:
在这四个参数中,最重要的是Web_Map_as_JSON参数。我们在编辑或者构造打印服务所需的参数时,主要就是针对Web_Map_as_JSON参数。其结构形式如下图所示。其中,mapOptions对象定义了地图显示属性(例如范围);operationalLayers列表包含了要在输出图片中要显示的所有操作图层;baseMap对象定义了要在输出图片中显示的底图;exportOptions对象指定了输出图片的dpi和布局尺寸;layeyoutOptions对象定义了页面布局元素。
{
"mapOptions": {},
"operationalLayers": ,
"baseMap": {},
"exportOptions": {},
"layoutOptions": {}
}
下面我们具体看一下这两种方法的实现过程:
方法一:拦截打印请求并修改打印参数
这个方法可以基于现有的PrintTask和Print控件进行。当执行打印时,客户端会发送一个打印请求,开发人员可以拦截此请求并进行修改:
- 拦截打印请求:系列ArcGIS API for JavaScript中,esri/request类的esriRequest.setRequestPreCallback(callbackFunction)方法可以拦截打印请求;4系列的ArcGIS API for JavaScript,目前还没有提供pre-callback方法。
- 获取请求中的Web_Map_as_JSON参数并进行修改:
- 根据指定的打印范围,修改Web_Map_as_JSON.mapOptions对象中的extent参数;
- 判断Web_Map_as_JSON.mapOptions对象中是否有scale,如果有,移除掉;
- 根据打印范围的长度和宽度比例,修改输出的图片尺寸。如果使用MAP_ONLY打印模板,图片尺寸使用的是Web_Map_as_JSON.exportOptions对象中的outputSize,需要修改outputSize的长度和宽度;如果使用的是MAP_ONLY以外的打印模板,图片尺寸使用的是打印模板中固有尺寸,没有办法修改,因此输出的范围会与指定的打印范围稍有不同,在长度或者宽度上会适当进行延伸。
关键代码如下:
// 拦截请求
esriRequest.setRequestPreCallback(function (ioArgs) {
//如果指定了打印范围,那么就修改打印请求中的参数值
if (ioArgs.content.Web_Map_as_JSON && extentLayer.graphics.length > 0) {
//获取Web_Map_as_JSON参数
var preJSON = ioArgs.content.Web_Map_as_JSON;
//把JSON字符串转换为JavaScript对象
var obj = JSON.parse(preJSON);
//修改打印范围
var newExtent = extentLayer.graphics[0].geometry;
obj.mapOptions.extent.xmax = newExtent.xmax;
obj.mapOptions.extent.xmin = newExtent.xmin;
obj.mapOptions.extent.ymax = newExtent.ymax;
obj.mapOptions.extent.ymin = newExtent.ymin;
//移除mapOptons中的scale参数(如果指定打印模板,mapOptions中会有这个参数)
if (obj.mapOptions.scale) {
delete obj.mapOptions.scale;
}
//修改输出的图片尺寸
obj.exportOptions.outputSize[1] = obj.exportOptions.outputSize[0] * (newExtent.ymax - newExtent.ymin) / (newExtent.xmax - newExtent.xmin);
//移除存储extent要素的graphicslayer
var n = obj.operationalLayers.length;
obj.operationalLayers.pop();
//将JavaScript对象序列化为一个JSON字符串
ioArgs.content.Web_Map_as_JSON = JSON.stringify(obj);
}
return ioArgs;
});
完整示例请见:
http://jsbin.com/geruzidife/edit?output //使用默认打印模板MAP_ONLY
http://jsbin.com/nonunokiqe/edit?output //可选打印模板(如果打印后单击打印输出没有出图,请右键在新标签页打开结果,或者将代码部署在本地进行测试)
方法二:自行构造打印参数并调用REST打印服务
放弃使用ArcGIS API for JavaScript中的tasks任务和widget控件,开发人员自行构造参数,并提交打印请求:
- 按照rest打印服务的参数要求,构造一个空的Web_Map_as_JSON对象;
- 根据地图或者视图中使用的图层以及显示的范围等,修改Web_Map_as_JSON对象的内容;
- 利用esri/request类的esriRequest(request, options)方法提交打印请求。
完整示例请见:
http://jsbin.com/ducasoqake/edit?html,output
两种方法相比较,第一种方法基于现有的printTask任务或者print控件进行,比较简单,推荐大家使用这种方法。