这节对Popups这一章的最后两个例子进行介绍和解析。
第一个【Popup Actions】介绍了弹窗中如何自定义工具按钮(名为actions),以PopupTemplate+FeatureLayer的形式测量要素的长度为例子进行介绍。
第二个【Custom popup actions per feature】则是上一个的升级,如果说上一个例子的功能是写死的,那么这个例子就把这个功能写活了。什么意思呢?上个例子的测距仅仅能测距,没有什么别的特别的。而这个例子以啤酒店的分布(点要素图层)为例,在自定义的按钮中弹出在谷歌搜索的结果甚至弹出这个啤酒店的网站。
actions是什么?
actions是Popup类的一个属性,类型是Collection,即同类型AJS对象或原生JS对象的数组容器。
它能装什么?
能装一些“动作”,这些动作在点击弹窗左下角按钮时,会触发这个容器中的“动作”。每个弹窗都有一个默认的“动作”,就是“Zoom-To”缩放功能,就是一个小放大镜。
看第一个例子的结果:
按下弹窗中的小测距尺子按钮后,灰色文字条中就出现了这个红色线要素的长度:11.82miles。
看第二个例子的结果:
按下按钮后就会弹出谷歌搜索的结果。
来看代码解析吧!
【Part I 简单action:测距】
给出引用
require(
[
"esri/Map",
"esri/layers/FeatureLayer",
"esri/views/MapView",
"esri/geometry/geometryEngine",
"dojo/domReady!"
],
function(...){...}
);
多了个geometryEngine,暂时不管它是干啥用的,继续往下看。
事先说明一下,CDN的引用又多了一行:
<link rel="stylesheet" href="https://js.arcgis.com/4.2/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/4.2/esri/css/main.css">
<script src="https://js.arcgis.com/4.2/"></script>
函数参数骨架
function(Map, FeatureLayer, MapView, geometryEngine){
var map = new Map({...});
var view = new MapView({...});
var measureThisAction = {...};
var template = {...};
featureLayer =new FeatureLayer({...});
map.add(featureLayer);
function measureThis(){...};
view.popup.on("trigger-action", function(event){...});
}
套路依旧,map和view实例化。var的template是PopupTemplate对象赋给了featureLayer的popupTemplate属性,再把featureLayer丢进map中。
好了,其余陌生的是什么?measureThisAction这个对象、measureThis这个方法、和view.popup.on方法?
别急,一个一个来。
measureThisAction出现的地方一一揪出来:
var measureThisAction = {
title: "Measure Length",
id: "measure-this",
image: "Measure_Distance16.png"
};
var template = {
title: "Trail run",
content: "{name}",
actions: [measureThisAction]
};
OK了,很明显,measureThisAction是一个Object,有title、id和image,分别对应标题、ID和按钮上的图案。这个png文件在html的同级别目录下。
下面这个template是featureLayer的PopupTemplate属性所需的对象,有title、content,第三个actions属性就将上方的measureThisAction赋给了它(数组形式,因为是Collection类型)。
可以理解如下:
measureThisAction是一个“动作”的声明,本身无功能,可以说是一个UI层上的描述。
————
那么measureThis()这个方法呢?
function measureThis() {
var geom = view.popup.selectedFeature.geometry;
var distance = geometryEngine.geodesicLength(geom, "miles");
distance = parseFloat(Math.round(distance * 100) / 100).toFixed(2);
view.popup.content = view.popup.selectedFeature.attributes.name +
"<div style='background-color:DarkGray;color:white'>" + distance +
" miles.</div>";
}
这里出现了新玩意儿:popup类的selectedFeature属性以及其子属性geometry/attributes,geometryEngine类的geodesicLength方法。
查询API,解读一下:
selectedFeature属性类别:Graphic类,当前选择的要素。
所以Graphic的geometry和attributes属性就容易查到:
geometry:几何体,没什么好说的。类型:Geometry类。
attributes:要素的字段名和字段值的成对集合。
————
geodesicLength():计算传入几何体(Geometry)的长度。
于是这个方法就是:获取几何体,然后把长度用geodesicLength()计算出来,单位是miles。然后设定popup的content动态设置为获取的要素长度值。
————
那么view.popup.on()这个方法呢?
看看完整的方法体:
view.popup.on("trigger-action", function(event) {
if (event.action.id === "measure-this") {
measureThis();
}
});
已经灰常、灰常灰常明显了,在popup这个类的“trigger-action”事件上,绑定一个事件方法体:如果“触发”的“动作(action)”的id是“measure-this”,那么执行measureThis()方法执行测距并输出到popup的content上。
于是,这个trigger-action是什么?
trigger-action是popup的事件的一种,和普通的click事件是一样的,意义就是popup的“当动作(action)被触发时”。click即“当鼠标点击时”。
而Popup的triggerAction()方法则接受一个索引,去触发trigger-action这个事件,然后执行索引对应的action。
现在明白了吧!
总结一下。
想要自己弄个按钮在弹窗上,就要:告诉AJS我要创建一个按钮,这个按钮能做什么事情。
第一步,创建一个按钮,使用Object对象measureThisAction来创建,并添加到PopupTemplate的actions属性中(数组形式)。
第二步,写出这个按钮的事件方法measureThis,然后把它绑定到trigger-action事件上。
【Part II 为按钮定制更高级的独特的功能】
节约篇幅,引用和函参骨架一起给出
require(
[
"esri/Map","esri/views/MapView","esri/layers/FeatureLayer","dojo/domReady!"
],
function(Map,MapView,FeatureLayer){
var map = new Map({});
var view = new MapView({});
var featureLayer = new FeatureLayer({
...
definitionExpression: "country = 'United States'",
popupTemplate: {
...
actions: [{ id: "find-brewery", image: "beer.png",title: "Brewery Info"}]
}
});
map.add(featureLayer);
view.then(function(){
var popup = view.popup;
popup.viewModel.on("trigger-action", function(event){...})
});
}
)
鉴于JavaScript的语法特性及面向对象的特性,Part I的很多对象、方法参数都直接用{}赋值了。
可以看到仍然是map和view的实例化,用的也是featureLayer和actions,actions不是[对象名]而是[{}]这种写法给定,不过并没有什么实质性的区别。
然后把featureLayer添加到map中去。
最后和Part I就有所不同了,Part I是view.popup.on("trigger-action", function(event){...})
而这里Part II,则是在view的回调函数中先获取popup,然后使用popup.viewModel.on("trigger-action", function(event){...})
我们暂时不看这有什么区别,先看看这个function(event){...}做了什么:
popup.viewModel.on("trigger-action", function(event) {
if (event.action.id === "find-brewery") {
var attributes = popup.viewModel.selectedFeature.attributes;
var info = attributes.website;
if (info !== null) {
window.open(info.trim());
} else {
window.open("https://www.google.com/search?q=" +
attributes.name);
}
}
});
仍和Part I没有什么区别,同样是获取一些信息,若info存在则直接打开,若不存在则到Google上搜索这个关键词,即如果选择的啤酒店有网站链接,那么就跳转到这个网站;如果啤酒店没有网站,就给出谷歌的搜索页面。
所以我觉得,popup.viewModel.on()的写法和view.popup.on()的写法没什么不同,多一层引用而已。
我们最后到官方的例子中看看有什么遗漏的信息:
没有。说明这两个写法应该是通用的?留个标记,以后测试。
至此,第五章也结束了学习,这一章是我比较忙的时候写的,可能读起来比较费劲,各位看官还请见谅。
在下一章"Searching"即空间查询中,我将转换一下心情,写出更好的笔记来学习AJS 4.2。
空间查询的代码量会激增,而AJS 4.3发布也快了,所以学习AJS 4.2的时间也不多了,新版本出来必定有新特性,我也会保持跟进继续更新4.3的新特性,并予以解读、测试。
下一章再见!