封装简介
项目中如果使用了Openlayers3以上版本,难免需要对图层操作;完成一些交互等工作。于是提炼出一些常用的封装逻辑,一下封装都是基于Map对象以及初始化之后。
1. 一些全局定义
为了方便查找图层,定义图层的时候,我们给图层增加_name 属性作为图层的主键。后续查找图层,过滤等操作都是基于这一定义进行。
//默认样式
var defaultStyle = {
'PointHidden': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#00ff00'
}),
radius: 0,
stroke: new ol.style.Stroke({
color: '#000',
width: 0
})
})
}),
'PointCurrent': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#00ff00'
}),
radius: 5,
stroke: new ol.style.Stroke({
color: '#000',
width: 1
})
}),
zIndex: 10
}),
'LineString': new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 3
})
}),
'DeviceStyle': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 5,
color: "#000099"
})
}),
'TransStyleDefault': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#ff0'
}),
radius: 10,
stroke: new ol.style.Stroke({
color: '#fff',
width: 1
})
}),
zIndex: 15
}),
'TransStyleActive': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#f00'
}),
radius: 10,
stroke: new ol.style.Stroke({
color: '#fff',
width: 1
})
}),
zIndex: 15
}),
'AfterTransStyleDefault': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#0ff'
}),
radius: 10,
stroke: new ol.style.Stroke({
color: '#fff',
width: 1
})
}),
zIndex: 15
}),
'AfterTransStyleActive': new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: '#f00'
}),
radius: 10,
stroke: new ol.style.Stroke({
color: '#fff',
width: 1
})
}),
zIndex: 15
}),
'DefaultRoute': new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#999',
lineCap: 'round',
width: 10
}),
fill: new ol.style.Fill({
color: '#fff'
})
}),
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 1,
color: '#A1601E'
})
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({
radius: 1,
snapToPixel: false,
fill: new ol.style.Fill({
color: '#A1601E'
}),
stroke: new ol.style.Stroke({
color: '#A1601E',
width: 2
})
})
})
};
/**
* 单击事件容器
*/
var ec = {}
/**
*
* hover 事件对应图层容器
*/
var slc = [],
selectStyleFun = [];
/**
* 获取点击坐标的回调函数
*/
var coord_collback = void(0);
//标识是不是在取坐标
var isCoord = false;
var _selectStyleFun = function (fea) {
return selectStyleFun[select.getLayer(fea).get("_name")](fea)
}
2. 地图初始化
底图图层顺序的控制时一个比较棘手的问题,一般情况下图层顺序为:底图,其他切片图层,矢量面图层,矢量线图层,矢量点图层,高亮图层,临时图层。另外也可以使用占位图层(空图层)方式保证图层顺序的正确性。
/**
* 高亮图层
* @type {ol.layer.Vector}
*/
highLightLayer = new ol.layer.Vector({
source: new ol.source.Vector({
wrapX: false
})
})
/**
* 临时图层
* @type {ol.layer.Vector}
*/
tempLayer = new ol.layer.Vector({
source: new ol.source.Vector({
wrapX: false
})
})
map = new ol.Map({
target: 'map',
layers: [底图, ... , highLightLayer, tempLayer],
view: view
});
3. 单击私有方法定义
所有的单机逻辑都走这里,这里统一管理
/**
* 私有的地图点击方法
* 要素图层的点击优先,要素图层点击没有的时候触发切片图层的点击
* @param e
* @private
*/
var _mapClick = function (e) {
//如果时取坐标
if (isCoord) {
coord_collback(e);
return true;
} else {
var param = this;
//获取点击位置对应的要素和图层
var hasFea = map.hasFeatureAtPixel(e.pixel, {
layerFilter: function (layer) {
return !("RegionLayer" === layer.get("_name")); //要素图层中排除 矢量切片图层
}
});
//矢量数据优先
if (hasFea) { //先检测一下有没有
map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
// 停止的时候,返回true
var _name = layer.get("_name");
var _res = Object.keys(ec).find(function (item) {
return item === _name;
})
if (_res) {
if (ec[_res].callback && typeof ec[_res].callback === 'function') {
//如果是有回调函数,必须是回调函数返回true,才能停止;
return ec[_res].callback(feature)
}
}
return true;
});
} else {
//更新当前区划
}
}
}
4. 地图事件处理
/**
* 给Map绑定事件
* @param layer 事件对应图层
* @param callback 事件回调函数
* @param thisObj 事件参数(该参数可以传递到事件函数里面,充当this)
*/
map.bindClickEvent = function (layer, callback, thisObj) {
if (thisObj) map.un("click", _mapClick, thisObj)
ec[layer.get("_name")] = {
callback: callback || void(0),
thisObj: thisObj || {}
}
}
/**
* 解除某事件
* @param type
* @param callback
* @param thisObj
*/
map.unBindEvent = function (type, callback, thisObj) {
map.un(type, _mapClick, thisObj);
}
5. 坐标拾取事件
/**
* 针对获取坐标点击事件绑定
* @param _callback
*/
map.position = function (_callback) {
if (_callback) {
coord_collback = _callback || void(0)
isCoord = true;
map.on("click", _mapClick)
} else {
coord_collback = void(0)
isCoord = false;
map.un("click", _mapClick)
}
}
6. 矢量数据hover事件
/**
* 绑定hover事件
*/
map.bindHoverEvent = function (lys, selStyles) {
if (lys instanceof Array) {
lys.forEach(function (item, index, array) {
selectStyleFun[item.get("_name")] = selStyles[index]
var isCnt = slc.some(function (a) {
return a.get("_name") === item.get("_name")
})
if (!isCnt) slc.push(item)
})
} else {
selectStyleFun[lys.get("_name")] = selStyles
var isCnt = slc.some(function (a) {
return a.get("_name") === lys.get("_name")
})
if (!isCnt) slc.push(lys)
}
if (select) map.removeInteraction(select);
select = new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
layers: slc,
style: _selectStyleFun,
multi: false
})
map.addInteraction(select)
}
7. 绘图交互封装
/**
* 绘制封装
* @param geoType 绘制对象类型 ol.interaction.Draw.type
* @param targetLayer 联动图层,当鼠标靠近此图层的要素时,会吸附上去
* @param cb 绘制完成后的回调函数
* @param pointUp 点对象特殊回调
* @param geometryFunction ol.interaction.Draw.geometryFunction
*/
map.startDraw = function (geoType, targetLayer, cb, pointUp, geometryFunction) {
if (draw) map.removeInteraction(draw);
if (snap) map.removeInteraction(snap);
if (targetLayer && (targetLayer.getType() === "VECTOR")) {
snap = new ol.interaction.Snap({
source: targetLayer.getSource()
});
}
var darwParam = {
source: tempLayer.getSource(),
type: geoType,
};
if (geometryFunction) {
darwParam.geometryFunction = geometryFunction;
}
draw = new ol.interaction.Draw(darwParam);
//4.5.6可用,这里可以更加细化绘制的时候鼠标按下,弹起等回调,不能使用压缩包
// draw.handleEvent = function (event) {
// this.freehand_ = this.mode_ !== ol.interaction.Draw.Mode_.POINT && this.freehandCondition_(event);
// var pass = true;
// if (this.freehand_ && event.type === ol.MapBrowserEventType.POINTERDRAG && this.sketchFeature_ !== null) {
// this.addToDrawing_(event);
// pass = false;
// } else if (this.freehand_ && event.type === ol.MapBrowserEventType.POINTERDOWN) {
// pass = false;
// } else if (event.type === ol.MapBrowserEventType.POINTERMOVE) {
// pass = this.handlePointerMove_(event);
// } else if (event.type === ol.MapBrowserEventType.DBLCLICK) {
// pass = false;
// } else if (event.type === ol.MapBrowserEventType.SINGLECLICK) {
// if ($.isFunction(pointUp)) pointUp(event);
// }
// return ol.interaction.Pointer.handleEvent.call(this, event) && pass;
// };
draw.on("drawend", function (evt) {
if (geoType === "Point")
if ($.isFunction(pointUp)) pointUp(evt)
if ($.isFunction(cb)) cb(evt.feature)
})
if (draw) map.addInteraction(draw);
if (snap) map.addInteraction(snap);
}
/**
* 结束绘制
* @param notClear 若为true,则在结束绘制后,保留临时图层上的要素
*/
map.endDraw = function (notClear) {
if (draw) map.removeInteraction(draw);
if (snap) map.removeInteraction(snap);
if (tempLayer && !notClear) {
tempLayer.getSource().clear();
}
;
}
8. 查找图层
/**
* 查找图层
* @param _name
* @returns {VRLayer | undefined}
*/
map.findLayer = function (_name) {
return map.getLayers().getArray().find(function (lyr) {
return _name === lyr.get("_name");
})
};
9. 清除临时图层
/**
* 清除临时图层上的要素
*/
map.cleanTempLayer = function () {
tempLayer.getSource().clear();
}
10. 高亮要素集合
/**
* 高亮要素集合
* @param features
*/
map.flashFeatures = function (features) {
highLightLayer.getSource().clear();
features.forEach(function (fea) {
if (fea.getGeometry()) {
fea.setStyle((fea.getGeometry().getType() === "Point") ? defaultStyle.PointCurrent : defaultStyle.LineString);
highLightLayer.getSource().addFeature(fea);
}
})
var tmout = setTimeout(function () {
highLightLayer.getSource().clear();
tmout = null;
}, 2000);
}
11. 缩放至要素集合
/**
* 缩放至
* @param features 要素
* @param zoom 缩放等级
* @param isFlash 是否缩放
*/
map.panToFeatures = function (features, zoom, isFlash) {
if (!features) return;
var geoms = [];
features.forEach(function (fea) {
if (fea && fea.getGeometry()) geoms.push(fea.getGeometry());
})
if (geoms.length == 1) {
var center, extent, geom = geoms[0];
if (geom.getType() === "Point")
center = geom.getCoordinates().slice(0, 2);
else if (geom.getType() === "LineString" || geom.getType() === "MultiLineString" ||
geom.getType() === "Polygon" || geom.getType() === "MultiPolygon")
extent = geom.getExtent();
if (center) view.animate({
zoom: zoom || view.getZoom()
}, {
center: center
})
if (extent) view.fit(extent, {
padding: [20, 20, 20, 20]
})
} else if (geoms.length > 1) {
view.fit(new ol.geom.GeometryCollection(geoms).getExtent(), {
padding: [20, 20, 20, 20]
})
}
if (isFlash) map.flashFeatures(features);
}
12. 地图中弹框(popup)
map.popup = function (loc, html) {
map.clearPopup();
var popup = $('<div style="z-index:999999;" class="ol-popup"><a href="#" class="ol-popup-closer"></a><div class="popup-content">' + html + '</div></div>');
overla = new ol.Overlay({
position: loc,
element: popup[0],
offset: [0, -39],
autoPan: false,
autoPanAnimation: {
duration: 250
}
})
popup.find('.ol-popup-closer').on("click", function () {
tempLayer.getSource().clear();
popup.blur();
overla.setPosition(null);
})
map.addOverlay(overla);
return overla;
}
map.andPOIMarker = function (geom) {
if (tempLayer) tempLayer.getSource().clear();
var fea = new ol.Feature({
geometry: geom
});
fea.setStyle(new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'marker.png'
})
}));
tempLayer.getSource().addFeature(fea);
}
13. 缩放至范围
/**
* 缩放到范围
*
* @param extent
*/
map.zoomToExtent = function (extent) {
map.getView().setResolution(map.getView().getResolutionForExtent(extent));
map.getView().fit(extent, {
padding: [30, 20, 30, 20]
});
};
14. 统一管理地图点击事件
/**
* 最后触发一下点击事件
*/
map.on("click", _mapClick);