指定范围进行地图打印

7
分享 2018-04-08
       在应用程序中,地图打印是一个经常被用到的操作。自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工具需要四个输入参数,分别是:
图片4.png

       在这四个参数中,最重要的是Web_Map_as_JSON参数。我们在编辑或者构造打印服务所需的参数时,主要就是针对Web_Map_as_JSON参数。其结构形式如下图所示。其中,mapOptions对象定义了地图显示属性(例如范围);operationalLayers列表包含了要在输出图片中要显示的所有操作图层;baseMap对象定义了要在输出图片中显示的底图;exportOptions对象指定了输出图片的dpi和布局尺寸;layeyoutOptions对象定义了页面布局元素。
{
"mapOptions": {},
"operationalLayers": ,
"baseMap": {},
"exportOptions": {},
"layoutOptions": {}
}

       下面我们具体看一下这两种方法的实现过程:
 
方法一:拦截打印请求并修改打印参数
 
       这个方法可以基于现有的PrintTask和Print控件进行。当执行打印时,客户端会发送一个打印请求,开发人员可以拦截此请求并进行修改:
 
  1. 拦截打印请求:系列ArcGIS API for JavaScript中,esri/request类的esriRequest.setRequestPreCallback(callbackFunction)方法可以拦截打印请求;4系列的ArcGIS API for JavaScript,目前还没有提供pre-callback方法。
  2. 获取请求中的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控件,开发人员自行构造参数,并提交打印请求:
 
  1. 按照rest打印服务的参数要求,构造一个空的Web_Map_as_JSON对象;
  2. 根据地图或者视图中使用的图层以及显示的范围等,修改Web_Map_as_JSON对象的内容;
  3. 利用esri/request类的esriRequest(request, options)方法提交打印请求。

 
       完整示例请见:http://jsbin.com/ducasoqake/edit?html,output
 
       两种方法相比较,第一种方法基于现有的printTask任务或者print控件进行,比较简单,推荐大家使用这种方法。
 
 

4 个评论

Merry GISmas!
抓住了
每个ID只需找到一个彩蛋即可中奖,请勿重复操作!
您好!请问一下使用printTask来打印已发布的点图层,但是在地图上展示是用图片渲染的。应该怎么做呀?

要回复文章请先登录注册