openlayers中一些问题的解决方案
一、使用地图时可能会出现的需求
1、定位:需要将地图的中心视野,定位到研究区域的中心点;
2、地图蒙版:只研究特定区域,将其他部分区域用蒙层遮罩,突显重点;
3、变色:设置整体的地图颜色风格,更换不同的主题颜色;
4、打点:在地图上加入一些点位图标的矢量元素;
5、画线:在地图上加入矢量线元素;
6、画面:在地图上加入矢量面元素;
7、事件:设置地图矢量的点击事件等;
8、弹出层:配置地图内部弹出层,显示特定信息。
二、解决方案
以下使用的部分变量基本上均为地图相关变量,需传入对应参数。
1、定位
①直接设置地图中心点(无位移动画)
map.getView().setCenter(coord)
②动画位移至中心点
map.getView().animate( {center: center},{zoom: zoom})
2、地图蒙版
需借助插件"ol-ext"完成。
import Mask from 'ol-ext/filter/Mask'
// region 需要被遮罩的图层
let maskLayer = this.getLayer('img')
// 创建遮罩过滤, 此处注意坐标系问题
const maskFilter = new Mask({
feature: new GeoJSON({
featureProjection: 'EPSG:4326'
}).readFeature(gis.features[0]),
wrapX: true,
inner: false,
fill: new Fill({
color: color || 'rgba(0,0,0,0.5)'
}),
})
// 设置图层遮罩过滤
maskLayer.addFilter(maskFilter)
3、变色
核心操作:回调函数,通过每次获取瓦片时,对瓦片进行重绘,然后再将瓦片数据上图。
new TileLayer({
id: "cia_n",
source: new WMTS({
url: wmtsUrl_1 + webKey,
layer: "cia",
matrixSet: "c",
format: "tiles",
style: "default",
projection: projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
wrapX: true,
tileLoadFunction: function (imageTile, src) {
// 使用滤镜 将白色修改为深色
let img = new Image()
// img.crossOrigin = ''
// 设置图片不从缓存取,从缓存取可能会出现跨域,导致加载失败
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function () {
let canvas = document.createElement('canvas')
let w = img.width
let h = img.height
canvas.width = w
canvas.height = h
let context = canvas.getContext('2d')
context.filter = 'grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%)'
context.drawImage(img, 0, 0, w, h, 0, 0, w, h)
imageTile.getImage().src = canvas.toDataURL('image/png')
}
img.src = src
}
}),
});
4、打点
常见需求,对部分地标或者建筑需要将其加入地图中,有助于使用者查看内容分布情况和内容具体位置。
添加地图元素需要分四步走,第一步是生成图层(点位元素的容器),第二步生成点位,第三步声明style(即点位的样式信息,例如点位图片、位置等),第四步将点位加入图层。
import {
Point,
} from 'ol/geom'
// 声明图层名称变量
const addToLayer = toLayer || 'pointerLayer'
// 生成点位,param为函数传入参数,代表点位信息数据
let newFeature = new Feature({
id: param.id,
layerId: param.layerId,
data: param.data,
geometry: new Point(param.position)
})
// 生成样式
let style = new Style()
newFeature.setStyle(style)
// 此处将第一步和第三步合并,在生成的时候加入点位,当然也可以在生成之后再通过调用source加入
const vectorLayerObj = new VectorLayer({
id: addToLayer,
zIndex: param.zIndex || 95,
minZoom: param.minZoom,
maxZoom: param.maxZoom,
source: new VectorSource({
features: [newFeature]
})
})
5、画线
步骤与生成点基本一致,只是在声明矢量元素时有所不同。
import {
LineString
} from 'ol/geom'
let routerLine = new Feature({
geometry: new LineString(param.coordinates),
data: param.data,
layerId: param.layerId,
id: param.id,
});
6、画面
import {
MultiPolygon,
Polygon
} from 'ol/geom'
let newPolygon = new Feature({
geometry: new Polygon(data.coordinates),
data: data.data,
layerId: data.layerId,
id: data.id,
});
7、事件
若需要与地图交互时触发相关事件,需要添加对应的监听方法,常用的有点击监听、鼠标移动监听等事件。
①监听鼠标移动事件:常用的方式为,鼠标划过矢量元素时变成小手。
mouseoverEvent() {
map.on("pointermove", (e) => {
this.$emit("handleMoveCoordinate", e.coordinate);
let pixel = this.map.mapObj.getEventPixel(e.originalEvent);
let feature = this.map.mapObj.forEachFeatureAtPixel(
pixel,
(feature) => {
return feature;
}
);
if (feature) {
if (feature.values_.id) {
map.getTargetElement().style.cursor = "pointer";
}
} else {
if (that.cursorPointer == "crosshair") {
map.getTargetElement().style.cursor = "crosshair";
} else {
map.getTargetElement().style.cursor = "auto";
}
}
});
},
②点击事件:常与弹出层搭配使用,点击对应矢量,弹出相关信息。
var selectSingleClick = new Select();
selectSingleClick.on("select", (e) => {
let features = e.target.getFeatures().getArray();
if (features.length > 0) {
let feature = features[0];
let featureObj = feature.values_.data;
let coordinate = null;
// 获取点击元素的feature
if (featureObj) {
}
selectSingleClick.getFeatures().clear();
});
map.mapObj.addInteraction(selectSingleClick);
8、弹出层(overlay)
通常情况下,我们可以在html代码中先声明好弹出层的组成结构和样式,然后再将其与overlay对象绑定,从而即可达到理想中的效果。
<div id="popOverLay" class="pop-content" v-show="isShow">
</div>
let overlay = map.getOverlayById('popOverLay')
let view = map.getView();
view.animate({center: coordinate},{zoom: 15})
setTimeout(() => {
if (overlay) {
overlay.setPosition(coordinate)
} else {
this.popup = new Overlay({
id: 'popOverLay',
autoPan: true,
autoPanAnimation: {
duration: 250
},
autoPanMargin: 250,
element: document.getElementById('popOverLay'),
position: coordinate,
positioning: 'bottom-center',
offset: [-1, -40]
})
map.addOverlay(this.popup)
}
}, 1000);