OpenLayers图形与列表互动
项目上遇到这样一种需求:查询数据库后得到结果(带地理位置的)列表,每个结果在地图上都是一个四边形,四边形之间有交叉,有重叠,需要实现地图上的四边形和结果列表的互动。抛开其他逻辑功能,互动需求可以表示为如下两点意思:
1、点击地图上的四边形,被点击的(或者说被选中的)四边形会由蓝色变成绿色,结果列表中对应项会被打钩选中;
2、反过来,点击结果列表中的复选框,被打钩选中的结果对应的地图上的四边形会随之由蓝色变成绿色,取消打钩选中,则绿色还原成蓝色。
(约定:查询结果四边形用蓝色表示,被选中的四边形用绿色表示)
如图所示:
实现思路:
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.
效果如下图所示:
(补充:仅仅是个实现思路,具体细节还需要慢慢完善,比如如何才能让SelectFeature组件的操作不影响自定义样式,需不需要重构SelectFeature类,SelectFeature是不是已经留有相应的功能等)