ARCGIS 气泡 提示

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Arcgis server架构
Arcgis server的Tools使用
Arcgis定义了常用的几个工具类,提供如放大(zoom in)、缩小(zoom out)、平移(Pan)等功能。

具体如下:
EsriMapCircle,EsriMapContinuousPan,EsriMapLine,EsriMapOval,EsriMapPan,EsriMapPoint,EsriMapPolygon,EsriMapPolyline,EsriMapRectangle
如果我们要自己写一个工具,我们可以新建一个普通的类,这个类MapToolAction接口(如果使用command,则可以不实现该接口)。

如:
public class MyTool implements MapToolAction {
public void execute(MapEvent event) {
WebContext ctx = event.getWebContext();
WebGeometry screenGeom = event.getWebGeometry();
WebGeometry mapGeom = screen.toMapGeometry(ctx.getWebMap());
………..
}
}
工具必须经过注册才能使用。

注册在faces-config.xml中添加对应的<managed-bean>属性。

如:
<managed-bean>
<managed-bean-name> MyTool </managed-bean-name>
<managed-bean-class>
com.tool.MyTool
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>context</property-name>
<value>#{mapContext}</value>
</managed-property>
</managed-bean>
经过注册后,就可在前台页面使用该工具了。

如下的蓝色字体显示:
<a:toolbar id="Toolbar" mapId="map1" >
<a:tool id="mytool" defaultImage="…" hoverImage="…"
selectedImage="…" clientAction="EsriMapPoint"
serverAction="com.tool.MyTool"
clientPostBack="true"
toolTip="提示信息"/>
</a:toolbar>
这里客户端采用了EsriMapPoint,实现在地图上点击的功能,并把这个点的坐标封装到WebGeometry里送到到后台。

这里对上面的几个类进行一下解释:(英文为帮助上的原文解释说明)
ClientActionArgs can be created for known client actions (on the map controls) such as EsriMapPoint, EsriMapLine, EsriMapOval etc. Concrete sub-classes of this class represent the actual client action arguments. They construct themselves by extracting the required parameters from the request.
The WebContext maintains references to the GISResources as well as to attributes (GIS business objects) such as WebMap, WebGraphics, WebQuery, etc.
Additionally, the WebContext is responsible for making the callback methods implemented by the resources and attributes at appropriate junctures of the ADF application. The callback methods are declared in the WebContextInitialize, WebContextObserver and WebLifecycle interfaces.
A MapEvent object is created by the MapControl when a map tool is invoked. This object is passed to the execute(MapEvent) method of the MapToolAction or to the tool method designated by the user.
In addition to the information provided by the ADFEvent base class, this class gives the tools access to the ClientActionArgs as well as a shortcut to the WebGeometry representing the shape that the client had drawn on the map to invoke the tool.
More often than not, the tools will only invoke this shortcut method getWebGeometry() to get to the geometry. This geometry is in screen coordinates. You can use the toMapGeometry(WebMap) method on the WebGeometry to convert it to map coordinates:
The getWebGeometry() method in this class is actually a shortcut to ClientActionArgs.getWebGeometry(). The actual type of geometry (WebPoint, WebExtent, etc.) depends on the ClientActionArgs that it comes from. The ClientActionArgs in turn depends on the client action (Javascript method) called on the map control on the client. The out of the box client actions are defined in the ClientActions interface. The mappings for out of the box client actions are as follows:
Client Action - ClientActionArgs - WebGeometry mappings
Client JavaScript Action ClientActionArgs WebGeometry ClientActions.MAP_POINT(EsriMapPoint) PointArgs WebPoint ClientActions.MAP_LINE(EsriMapLine) LineArgs WebPolyline ClientActions.MAP_RECTANGLE(EsriMapRectangle) DragRectangleArgs WebExtent ClientActions.MAP_CIRCLE(EsriMapCircle) CircleArgs WebCircle ClientActions.MAP_OVAL(EsriMapOval) OvalArgs WebOval
ClientActions.MAP_POLYLINE(EsriMapPolyline) PolylineArgs WebPolyline ClientActions.MAP_POLYGON(EsriMapPolygon) PolygonArgs WebPolygon ClientActions.MAP_PAN(EsriMapPan) DragImageArgs WebPoint
So if the client action associated with the myToolMethod() tool from above was EsriMapPoint, the corresponding geometry would be WebPoint, in which case you would cast the mapGeom to WebPoint: WebPoint mapPt = (WebPoint)mapGeom;
Arcgis server 页面与后台交互
Tools的交互在前面已经说明,通过把前台得到的几何信息提交到后台进行处理。

采用Tools或command方式与后台交互,Tools方式可以把页面的数据传递到后台,而command 则没有这个功能。

同时,在后台返回时,都不能单独的传递信息给前台。

既后台已经封装好了xml返回前台。

如果想通过与后台交互,并把想要的数据返回到前台进行进一步的处理,这里可采用PhaseListener的方式,也就是进行监听的方式。

PhaseListener定义:(英文为帮助上的原文解释说明)
An interface implemented by objects that wish to be notified at the beginning and ending of processing for each standard phase of the request processing lifecycle.
也就是在每次标准的request请求处理周期中,在处理开始和结束时监听都能做出反应。

这里我们就可以加入自己的代码实现我们想要的功能了。

最后把结果数据封装成xml 再传回到前台的ajax回调函数进行处理。

这样的方式,我们可以实现把地理位置的基本信息和x、y值传回前台,前台再在对应的地方显示一个div做的气泡提示框,实现类似google 的地图提示。

PhaseListener也必须在进行faces-config.xml注册才能有效。

如下面的蓝色字体显示:
<lifecycle>
<phase-listener>
com.esri.adf.web.templates.MapViewerPhaseListener
</phase-listener>
<phase-listener>
com.tool.MyPhaseListener
</phase-listener>
</lifecycle>
Google气泡提示框实例
系统采用的Arcgis Server For Java实现。

通过使用MapToolAction、Arcgis javascript库和PhaseListener来实现气泡提示功能。

考虑到通过点击地图时,如地理位置为x=124,y=85,很难保证鼠标能精确点击到该点上。

地理位置与实际点击点的位置有一定的偏差。

所以我们这里实现对离点击点最近的地理位置弹出气泡提示。

基本步骤:
1.做个MapToolAction实现点击功能,得到点击的屏幕坐标。

2.修改js文件,实现发送请求。

并加入自己处理Ajax传回的responseXml的函数。

3.做个PhaseListener实现监听功能,处理请求。

MapToolAction实现点击功能
为了得到点击的位置,前台页面我们必须要实现一个点击的功能。

这里采用EsriMapPoint实现。

定义Tool时,必须要提供serverAction(我试了半天,不提供则会报错)。

所以我们建立一个继承MapToolAction的类来提供这个功能。

代码如下:
package com.esri.adf.web.myproject;
import com.esri.adf.web.data.WebContext;
import com.esri.adf.web.faces.event.MapEvent;
import com.esri.adf.web.faces.event.MapToolAction;
public class MapShowinfo implements MapToolAction {
public static final long serialVersionUID = 200800001L;
private WebContext context;
public void setContext(WebContext context) {
this.context = context;
}
public WebContext getContext() {
return this.context;
}
public void execute(MapEvent arg0) throws Exception {
//这里不用实现任何代码
}
}
在faces-config.xml进行注册:
<managed-bean>
<managed-bean-name>MapShowInfo</managed-bean-name>
<managed-bean-class>
com.esri.adf.web.myproject.MapShowInfo
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>context</property-name>
<value>#{mapContext}</value>
</managed-property>
</managed-bean>
再在前台页面中加上这个tool:
……
<a:tool id="ShowInfo" defaultImage="images/tasks/maptools/identify.png"
hoverImage="images/tasks/maptools/identifyU.png"
selectedImage="images/tasks/maptools/identifyD.png"
clientAction="EsriMapPoint"
serverAction="com.esri.adf.web.myproject.MapShowInfo"
clientPostBack="true" toolTip="点击显示信息"/>
……
这样点击功能我们已经实现了,serverAction的类我们没有实现具体的代码。

主要是为了提供了这个类,防治系统报错。

具体的发送和处理代码我们将通过javascript采用Ajax 的方式来实现。

接着我们在页面中加上气泡div。

div可以按自己需求设计。

Div的中间嵌套了个div,用于显示提示内容。

角上的按钮用于关闭整个提示框。

控制提示框的教本
//关闭信息提示框
function closeinfotable(){
var info = document.getElementById("datainfo");
info.innerHTML = "";
var obj = document.getElementById("datainfodiv");
obj.style.visibility = "hidden";
}
<!-- 以下是提示框 -->
<div id="datainfodiv" style=" visibility:hidden ;position:absolute; z-index: 1">
<table width="235" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="21" height="18"><img src="images/info/info_01.gif" width="21" height="18" alt=""></td>
<td width="64" height="18"><img src="images/info/info_02.gif" width="64" height="18" alt=""></td>
<td height="18" align="right" background="images/info/info_03.gif" width="100%">
<img src="images/info/info_close.gif" width="12" height="12" style="cursor:hand" onClick="closeinfotable()">&nbsp;</td>
<td width="20" height="18"><img src="images/info/info_04.gif" width="20" height="18" alt=""></td>
</tr>
<tr>
<td height="82" background="images/info/info_05.gif">&nbsp;</td> <td height="82" colspan="2" bgcolor="#FFFFFF"><div id="datainfo" style="width:100%; height:100%"></div></td>
<td height="82" background="images/info/info_07.gif">&nbsp;</td> </tr>
<tr>
<td height="50"><img src="images/info/info_08.gif" width="21" height="50" alt=""></td>
<td width="64" height="50"><img src="images/info/info_09.gif" width="64" height="50" alt=""></td>
<td height="50" background="images/info/info_10.gif" width="100%">&nbsp;</td>
<td height="50"><img src="images/info/info_11.gif" width="20" height="50" alt=""></td>
</tr>
</table>
</div>
<!-- 以上是提示框 -->
发送数据和接受数据的处理
在js文件夹中找到esri_map.js并打开,找到EsriMapPoint类。

function EsriMapPoint(id, toolName, isMarkerTool, isPin){
……
}
我们的按钮ShowInfo采用了EsriMapPoint来实现。

<a:tool id="ShowInfo" ……/> 将调用js/esri_map.js中EsriMapPoint类来实例化。

EsriMapPoint继承了EsriMapToolItem。

这是所有tool类的父类。

EsriMapPoint有两个属性和两个函数。

我们关注的是第二个函数“this.postAction”。

这个函数就是对整个页面进行提交的功能。

为此,我们将修改这个函数,来实现发送自己的请求到监听的PhaseListener中去。

函数EsriMapPoint的参数id就是页面中tool定义时的id值。

所以我们通过判断id 值是否等于“ShowInfo”来确定是否是触发了我们的气泡提示功能。

同时,函数postAction 自带的参数point为我们点击地图时产生的WebPoint值。

这个值为屏幕坐标,到后台需要转换为地理坐标。

当我们得到了点击值后,就封装参数字符串,最后通过Ajax方式发送到后台。

参数串中我们添加了“mapaction=showinfo”。

这里mapaction是我们在PhaseListener 中监听的变量名称。

当mapaction的值等于showinfo时,我们就认为是请求的气泡提示功能,并对此做出反应。

函数dealWithInfo()是处理PhaseListener返回的responseXML的函数。

这个函数的功能是解析xml,取得地理位置的气泡内容,以及气泡div要呈现的屏幕坐标。

蓝色代码为我们自己添加的。

代码如下:
function EsriMapPoint(id, toolName, isMarkerTool, isPin) {
this.inheritsFrom(new EsriMapToolItem(id, toolName, new EsriDrawPointAction(), isMarkerTool));
this.isPin = isPin;
var self = this;
this.update = function() { self = this; }
this.postAction = function(point) {
self.update();
var map = self.control;
//点击,返回内容并显示提示框。

if(id=="ShowInfo"){
var url = EsriUtils.getServerUrl("mapForm");
var params = "mapaction=showinfo&doPostBack=doPostBack&__ADFPostBack__=false&formId=mapForm& mapId=map1&map1=map1&x=" + point.x + "&y=" + point.y ;
var xh = EsriUtils.sendAjaxRequest(url, params, true, function() { dealWithInfo(xh)});
}
else {
if (self.isMarker) {
if (self.isPin) map.graphics.drawPin(point);
else map.graphics.drawPoint(point);
}
else {
if (self.showLoading) map.showLoading();
point = point.offset(-map.viewBounds.left, -map.viewBounds.top);
EsriUtils.addFormElement(map.formId, map.id, map.id);
EsriUtils.addFormElement(map.formId, map.id + "_mode", self.id);
EsriUtils.addFormElement(map.formId, map.id + "_minx", point.x);
EsriUtils.addFormElement(map.formId, map.id + "_miny", point.y);
if (self.clientPostBack) EsriUtils.addFormElement(map.formId, "doPostBack", "doPostBack");
EsriUtils.submitForm(map.formId, self.clientPostBack, EsriControls.processPostBack);
}
}
}
}
同时添加函数dealWithInfo:
function dealWithInfo(xh){
if (xh !== null && xh.readyState == 4 && xh.status == 200) {
try{
var xml = xh.responseXML;
var id = xml.getElementsByTagName("id").item(0).firstChild.nodeValue;
var name = xml.getElementsByTagName("name").item(0).firstChild.nodeValue;
var info = xml.getElementsByTagName("info").item(0).firstChild.nodeValue;
var sx = xml.getElementsByTagName("sx").item(0).firstChild.nodeValue;
var sy = xml.getElementsByTagName("sy").item(0).firstChild.nodeValue;
var mx = xml.getElementsByTagName("x").item(0).firstChild.nodeValue;
var my = xml.getElementsByTagName("y").item(0).firstChild.nodeValue;
var content = "<table width=\"100%\" border=\"0\" cellpadding=\"1\" cellspacing=\"1\">"+
"<tr><td width=\"20%\" align=\"right\" bgcolor=\"#FFFFFF\">名称:</td>"+
"<td width=\"80%\" bgcolor=\"#FFFFFF\"><a href='#'>"+name+"</a></td></tr>"+ "<tr><td width=\"20%\" align=\"right\" bgcolor=\"#FFFFFF\">&nbsp;</td>"+
"<td width=\"80%\" bgcolor=\"#FFFFFF\">"+info+"</td></tr></table>";
//填写气泡能容。

var datadiv = document.getElementById("datainfo");
datadiv.innerHTML = content;
//计算气泡框位置,使气泡下面的尖角刚好指向地理位置,并呈现。

var infodiv = document.getElementById("datainfodiv");
infodiv.style.left= (sx - 35)+ "px";
infodiv.style.top= (sy - 155) + "px";
infodiv.style.visibility = "visible";
} catch(e){
}
}
}
PhaseListener监听
Phaselistener的处理主要是得到前台传来的x和y值,把这个x、y值与地图上的地理坐标进行匹配,找到距离最近的点。

我们就认为要对这个点进行气泡提示。

得到这个点的基本信息,同时计算该点的屏幕坐标,最后封装成xml一起返回前台。

代码如下:
public class MapPhaseListener implements PhaseListener {
private WebContext context = null;
public void afterPhase(PhaseEvent phaseEvent) {
try {
FacesContext facesContext = phaseEvent.getFacesContext();
ExternalContext externalContext = facesContext.getExternalContext();
Map paramMap = externalContext.getRequestParameterMap();
String mapaction = "";
//取得mapaction参数
mapaction = (String) paramMap.get("mapaction");
if (mapaction == null)
return;
//showinfo标识请求气泡提示
if (mapaction.equals("showinfo")) {
// 取得context
UIComponent form = facesContext.getViewRoot().findComponent((String) paramMap.get(MapConfig.FORM_ID));
MapControl mapControl = (MapControl) form.findComponent((String) paramMap.get(MapConfig.MAP_ID));
context = mapControl.getWebMap().getWebContext();
//spoint标识前台传来的屏幕坐标
WebPoint spoint = new WebPoint(Double.parseDouble((String) paramMap.get("x")), Double.parseDouble((String) paramMap.get("y")));
// 转换为地图坐标
WebPoint mpoint = (WebPoint) spoint.toMapGeometry(context.getWebMap());
/*
我采用的是图片标注,同时在标注点上又保存了这个点的基本信息。

这方便取到标注后能马上得到基本信息。

所以就新写了类WebCSSTPictureMarkerSymbol。

WebCSSTPictureMarkerSymbol继承了WebPictureMarkerSymbol。

同时添加了bean字段来保存信息。

*/
WebCSSTPictureMarkerSymbol matchws = null;
WebPoint matchpoint = null;
double len = -1, tlen = 0;
// 匹配和地图坐标最符合的点
WebGraphics graphics = context.getWebGraphics();
//取得点的集合
List glist = graphics.getPointGraphics();
GraphicElement element = null;
for (int i = 0; i < glist.size(); i++) {
element = (GraphicElement) glist.get(i);
WebPoint wp = (WebPoint) element.getGeometry();
//计算距离,最后得到最小的那个点
tlen = getDistance(mpoint, wp);
if (tlen <= len || len == -1) {
len = tlen;
matchws = (WebCSSTPictureMarkerSymbol) element.getSymbol();
matchpoint = wp;
}
}
// 存在该坐标,返回至前台处理。

if (matchpoint != null) {
//得到保存基本信息的bean
MapLabelBean mlb = matchws.getMapLabelBean();
// 根据匹配的点,转换成屏幕坐标
spoint = (WebPoint) matchpoint.fromMapGeometry(context.getWebMap());
Document doc = XMLUtil.newDocument();
Element responseElement = XMLUtil.createElement(doc,"response", null, null);
XMLUtil.createElement("id", mlb.getId(), responseElement);
XMLUtil.createElement("name", mlb.getName(),responseElement);
XMLUtil.createElement("info", mlb.getInfo(),responseElement);
XMLUtil.createElement("sx",
Double.toString(spoint.getX()),responseElement);
XMLUtil.createElement("sy",
Double.toString(spoint.getY()),responseElement);
XMLUtil.createElement("x", Double.toString(matchpoint.getX()), responseElement);
XMLUtil.createElement("y", Double.toString(matchpoint.getY()), responseElement);
try {
AJAXUtil.writeResponse(facesContext, doc);
} catch (Exception e) {
e.printStackTrace();
} finally {
facesContext.responseComplete();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
……
在faces-config.xml进行注册:
<!-- MapViewer Phase Listener -->
<lifecycle>
<phase-listener>
com.esri.adf.web.templates.MapViewerPhaseListener
</phase-listener>
<phase-listener>
com.esri.adf.web.project.MapPhaseListener
</phase-listener>
</lifecycle>
<!-- Application Beans -->
经过以上三步,实现了从前台传输数据到后台。

后台经过处理后在传至前台的回调函数进行处理。

最终完成气泡框的功能。

相关文档
最新文档