如何用openlayers加载手绘地图可以看另一篇文章: https://www.jianshu.com/p/0b4fd0173b56
一、加载矢量标注及聚合标注
通常需要在地图上标注出一些景点、建筑或者公共设施,可以选择使用矢量标注或者聚合标注。openlayers 添加矢量标注的原理是将标注添加到一个新建的矢量层上,再将矢量层添加到地图上叠加显示;聚合标注的原理同上,但它适用于标注的数据量非常大的场景,随着层级的放大,会展示更多的标注,缩小时,则将标注聚合显示,能够在大量加载标注时提高渲染性能。
1、矢量标注
// 引入的对象和方法 import Vectors from 'ol/layer/Vector.js' import { WMTS, Vector } from 'ol/source.js' import Feature from 'ol/Feature' import OlGeomPoint from 'ol/geom/Point' import OlStyleStyle from 'ol/style/Style' import OlStyleIcon from 'ol/style/Icon' import Text from 'ol/style/Text' import Fill from 'ol/style/Fill' /*创建矢量标注 *@param{object} data 标注的数据 createLabel(data) { // 初始化标签要素 let feature = new Feature({ geometry: new OlGeomPoint(fromLonLat([+data.lng, +data.lat])), // 标签位置 name: data.name, // 标注显示的文字 img: require('./../../assets/imgs/map_icon_location.png'), // 标注显示的logo图片 feature.setId(data.id) // 设置ID feature.setStyle(this.createLabelStyle(feature)) // 设置标注样式 let source = new Vector({}) // 初始化矢量数据源 source.addFeature(feature) // 将标签要素添加至矢量数据源 let layer = new Vectors({ // 创建矢量图层 source: source this.map.addLayer(layer) // 将矢量图层添加至地图 /*创建标注样式 *@param{object} feature 标注要素 *@return {object} 返回创建的标注样式对象 createLabelStyle(feature) { //返回一个样式 return new OlStyleStyle({ //图标样式 image: new OlStyleIcon({ anchor: [10, 18], //设置图标偏移 scale: 0.6, // 图标缩小显示 anchorOrigin: 'top-right', //标注样式的起点位置 anchorXUnits: 'pixels', //X方向单位:分数 anchorYUnits: 'pixels', //Y方向单位:像素 offsetOrigin: 'bottom-left', //偏移起点位置的方向 opacity: 0.9, //透明度 src: feature.get('img') //图片路径 //文本样式 text: new Text({ textAlign: 'center', //对齐方式 textBaseline: 'middle', //文本基线 font: 'normal 12px 微软雅黑', //字体样式 text: feature.get('name'), //文本内容 offsetY: -25, // Y轴偏置 fill: new Fill({ //填充样式 color: '#ffffff' backgroundFill: new Fill({ // 填充背景 color: asString([0, 0, 0, 0.6]), padding: [2, 5, 2, 5], // 设置层级 zIndex: 199
2、聚合标注
使用聚合标注后,标注间隙过密甚至出现重合的问题得以解决,待用户放大地图后再加载更多的标注。
// 引入的对象和方法 import Cluster from 'ol/source/Cluster' import { WMTS, Vector } from 'ol/source.js' import Feature from 'ol/Feature' import OlGeomPoint from 'ol/geom/Point' import OlStyleStyle from 'ol/style/Style' import OlStyleIcon from 'ol/style/Icon' import Text from 'ol/style/Text' import Fill from 'ol/style/Fill' /*创建聚合标注 *@param{object} data 标注的数据 createClusterLabel(data) { // 初始化标签要素 let feature = new Feature({ geometry: new OlGeomPoint(fromLonLat([+data.lng, +data.lat])), // 标签位置 name: data.name, // 标注显示的文字 img: require('./../../assets/imgs/map_icon_location.png'), // 标注显示的logo图片 feature.setId(data.id) // 设置ID let source = new Vector({}) // 初始化矢量数据源 source.addFeature(feature) // 将标签要素添加至矢量数据源 let cluster = new Cluster({ // 创建聚合标注对象 distance: 25, // 设置聚合标注的距离 source: source let layer = new Vectors({ // 创建矢量图层 source: cluster, style: function(feature, resolutions) { // 这里可以参照上面的createLableStyle写,聚合标注在feature中单独设置的样式不生效 return new OlStyleStyle({ image: new OlStyleIcon({ src: feature.values_.features[0].values_.img // 图片路径 this.map.addLayer(layer) // 将聚合标注添加至地图
二、加载覆盖物(场景:点击标注弹出对话框)
openlayers 可以创建一个 Overlay 覆盖层,这个覆盖层能够展示自己写的 html 内容,从而实现添加各种所需的覆盖物。也可以通过这个方法来添加标注,但覆盖层添加的覆盖物会影响地图的拖动(即在覆盖物上进行滑动操作时地图无法响应,虽然可以通过设置 stopEvent 将滑动事件传递到地图上,但这样会导致在IOS端的覆盖物无法进行点击操作)。
因此如果要添加可以点击并且不影响地图拖动的标注时,建议使用矢量层标注,而如果要展示自定义的一些内容,如点击地图弹出对话信息框、地图上的自定义按钮等则使用覆盖层更加合适。
addOverlay() { this.overlay = new Overlay({ element: document.getElementById('overlay-dlg'), // 将自己写的 html 内容添加到覆盖层,html 内容略 positioning: 'bottom-center', // 覆盖层位置 autoPan: true, // 是否自动平移,当点击时对话框超出屏幕边距,会自动平移地图使其可见 autoPanMargin: 20, // 设置自动平移边距 offset: [0, -20], // 覆盖层偏移起点的位置 className: 'overlay-test' // 覆盖物在覆盖层的类名2、添加地图点击监听事件
/* 实现点击标注后在对应位置弹出信息框, 拿到标注的 feature 除了设置经纬度外, 还能通过其 id 向后台接口获取要展示的数据,再渲染到覆盖层的对话框上,这里代码给的比较简要, 有需要的可根据具体业务结合这个思路自行扩充代码 */ var content = ducoment.getElementsById('content') this.map.on('singleclick', (e) => { // 获取点击的标注 let features = this.map.forEachFeatureAtPixel(evt.pixel, function (feature, layerVetor) { return feature }) // 设置覆盖物的经纬度 this.overlay.setPosition([feature.values_.geometry.flatCoordinates[0], feature.values_.geometry.flatCoordinates[1]]) // 设置要显示的信息 content.html = '点击的 id 是' + feature.id_ // 将覆盖物添加到地图上 this.map.addOverlay(this.overlay)
三、绘制路线
原理大致与添加矢量标注相同,都是添加在矢量图层上,不过这里添加的是线对象。
createLineStroke(routeList) { this.lineFeature = new Vector({}) // 创建路线矢量数据源 for(let i = 0; i < routeList.length; i++) { // 注意我这里是同时绘制多条路线 let polyLine = routeList[i].polyline.split(';') let polyLintArray = [] polyLine.forEach(item => { // 处理接口传过来的路径数据,转换为 openlayers 所需的经纬度数据格式 item = item.split(',') item = fromLonLat([+item[0], +item[1]]) polyLintArray.push(item) let feature = new Feature({ // 创建路线属性 type: 'route', geometry: new OlGeomLine(polyLintArray) feature.setStyle(this.createLineStyle(i + 1)) // 添加路线箭头,不需要绘制箭头的可忽略 let img = require('./../../assets/imgs/icon_moer.png') let style = [this.createLineStyle(i + 1)] let geometry = feature.getGeometry() let k = 0 geometry.forEachSegment((start, end) => { if (k % 50 !== 0) { return let dx = end[0] - start[0] let dy = end[1] - start[1] let rotation = Math.atan2(dy, dx) // 获取子线段的角度 style.push(new OlStyleStyle({ geometry: new OlGeomPoint(end), image: new OlStyleIcon({ scale: 0.6, src: img, anchor: [0.75, 0.5], // 图标锚点 rotateWithView: true, // 与地图视图一起旋转 // 设置子线段箭头图标样式的角度 rotation: -rotation // 因为角度以顺时针旋转为正值,所以前面添加负号 zIndex: 200, feature.setStyle(style) this.lineFeature.addFeature(feature) // 将路线属性添加至矢量数据源中 this.lineLayer = new Vectors({ // 将路线矢量数据源添加至矢量层 source: this.lineFeature this.map.addLayer(this.lineLayer) // 将矢量层添加到地图 /*创建路线样式 *@param{int} index 路线顺序 createLineStyle(index) { //返回一个样式 return new OlStyleStyle({ stroke: new Stroke({ // 路线填充样式:宽度、颜色等 width: 8, color: [16,168,218, 1], text: new Text({ text: '路段' + index, // 路线标签文字 font: 'normal 12px 微软雅黑', //字体样式 fill: new Fill({ //文字填充样式 color: [16,168,218, 1] backgroundFill: new Fill({ color: asString([255, 255, 255, 0.9]), padding: [1, 2, 1, 2],