OpenLayers图形与列表互动

项目上遇到这样一种需求:查询数据库后得到结果(带地理位置的)列表,每个结果在地图上都是一个四边形,四边形之间有交叉,有重叠,需要实现地图上的四边形和结果列表的互动。抛开其他逻辑功能,互动需求可以表示为如下两点意思:

1、点击地图上的四边形,被点击的(或者说被选中的)四边形会由蓝色变成绿色,结果列表中对应项会被打钩选中;

2、反过来,点击结果列表中的复选框,被打钩选中的结果对应的地图上的四边形会随之由蓝色变成绿色,取消打钩选中,则绿色还原成蓝色。

(约定:查询结果四边形用蓝色表示,被选中的四边形用绿色表示)

如图所示:

OpenLayers图形与列表互动

实现思路:

1、每个四边形都是一个OpenLayers.Feature.Vector对象,包含一个fid属性,该属性唯一,且可以由用户设定。我们可以通过fid和结果列表中的checkbox的id的某种关系(直接将fid设置成id的值即可)实现两者的一一对应,绘制四边形的代码如下:

// lefttop, righttop, rightdown, letdown是四个二维向量,表示四边形四个顶点的经纬度坐标
// featureID用于设定OpenLayers.Feature.Vector的fid,可以用于保存checkbox的id值
function drawPolygon(lefttop, righttop, rightdown, letdown, featureID) {
var lr = new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(lefttop[0], lefttop[1]),
new OpenLayers.Geometry.Point(righttop[0], righttop[1]),
new OpenLayers.Geometry.Point(rightdown[0], rightdown[1]),
new OpenLayers.Geometry.Point(letdown[0], letdown[1]),
new OpenLayers.Geometry.Point(lefttop[0], lefttop[1])]);
lr = lr.transform("EPSG:4326", "EPSG:900913");
var polygonFeature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Polygon(lr),
{
'location': 'Fanghorn Forest',
'description': 'Land of the Ents'
}
);
polygonFeature.renderIntent = "default";
polygonFeature.fid = featureID;
vectorLayer.addFeatures([polygonFeature]); // vectorLayer是四边形几何对象的容器图层,在第2点中说明...
}

2、将所有的四边形Vector对象都绘制在一个OpenLayers.Layer.Vector父容器图层对象(设为vectorLayer)中,给vectorLayer指定一组样式,用于统一设定其内四边形选中和未选中时的颜色,样式代码如下:

var polygonLayerStyle = new OpenLayers.StyleMap({
'default': {
fillColor: "#0000ff", //蓝色表示默认状态
fillOpacity: 0.1,
strokeColor: "#0000ff",
strokeOpacity: 1,
strokeWidth: 1
},
'select': {
fillColor: "#00ff00", //绿色表示选中的状态
fillOpacity: 0.1,
strokeColor: "#00ff00",
strokeOpacity: 1,
strokeWidth: 1
}
});
 

3、使用OpenLayers.Control.SelectFeature组件,绑定vectorLayer图层,使vectorLayer层里边的各个四边形Vector可以被选中,同时给vectorLayer图层添加其内Feature被选中时要触发的动作事件,代码如下:

var selcetCtl = new OpenLayers.Control.SelectFeature(vectorLayer, { //将vectorLayer绑定到SelectFeature组件上
clickout: false, toggle: false,
multiple: true, hover: false,
clickout: true,
renderIntent: "select"
});
vectorLayer.events.on({ // 注册动作事件
'featureselected': function (feature) {
selcetCtl.unselect(feature.feature); // 为何要调用该函数呢,是为了vector在选中和解除选中时样式不可控(SelectFeature空间定义的默认样式跟我们要的不一样)
var a = document.getElementById(feature.feature.fid);
a.checked = true;
checkboxchange(a); // 手动触发checkbox状态改变事件,貌似用代码改变其checked属性后,并没有失去焦点的动作,没办法自动触发
}
});
map.addControl(selcetCtl);
selcetCtl.activate(); // 添加空间后需要显式地激活

4、修改四边形样式,以及改变checkbox的状态等功能的实现,主要是如下函数:

        function checkboxchange(e) {
var theFeature = vectorLayer.getFeatureByFid(e.id);
if (e.checked) {
theFeature.renderIntent = "select"; } else {
theFeature.renderIntent = "default";
}
vectorLayer.drawFeature(theFeature);
}

这里略提一点细节问题,通过修改Feature对象的renderIntent,能够指定其套用Style对象里的哪套样式,但是修改之后,Feature的样式不会立马改变(静态页面嘛...),需要调用一下vectorLayer.drawFeature(theFeature)来重绘一下(缩放一下也能起到刷新重绘效果),drawFeature函数的含义可以参考一下api中的注释,这里截取一部分如下:

 * This function is not designed to be used when adding features to
* the layer (use addFeatures instead). It is meant to be used when
* the style of a feature has changed, or in some other way needs to
* visually updated *after* it has already been added to a layer. You
* must add the feature to the layer for most layer-related events to
* happen.

效果如下图所示:

OpenLayers图形与列表互动

(补充:仅仅是个实现思路,具体细节还需要慢慢完善,比如如何才能让SelectFeature组件的操作不影响自定义样式,需不需要重构SelectFeature类,SelectFeature是不是已经留有相应的功能等)

上一篇:leetcode — first-missing-positive


下一篇:测试C++代码与WebBrowser HTML的互动