openlayers添加标注(含聚合标注)、覆盖物、绘制路线

如何用openlayers加载手绘地图可以看另一篇文章:https://www.jianshu.com/p/0b4fd0173b56

一、加载矢量标注及聚合标注

通常需要在地图上标注出一些景点、建筑或者公共设施,可以选择使用矢量标注或者聚合标注。openlayers 添加矢量标注的原理是将标注添加到一个新建的矢量层上,再将矢量层添加到地图上叠加显示;聚合标注的原理同上,但它适用于标注的数据量非常大的场景,随着层级的放大,会展示更多的标注,缩小时,则将标注聚合显示,能够在大量加载标注时提高渲染性能。
1、矢量标注

矢量标注.png

// 引入的对象和方法
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、聚合标注

矢量标注较多时出现重叠.png

聚合标注效果.png

使用聚合标注后,标注间隙过密甚至出现重合的问题得以解决,待用户放大地图后再加载更多的标注。

// 引入的对象和方法
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端的覆盖物无法进行点击操作)。
因此如果要添加可以点击并且不影响地图拖动的标注时,建议使用矢量层标注,而如果要展示自定义的一些内容,如点击地图弹出对话信息框、地图上的自定义按钮等则使用覆盖层更加合适。

点击弹出对话框.png

1、加载覆盖层

import Overlay from 'ol/Overlay.js'

/*创建覆盖物
*/
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)
})
三、绘制路线

原理大致与添加矢量标注相同,都是添加在矢量图层上,不过这里添加的是线对象。


路线.png
import OlGeomLine from 'ol/geom/LineString'

/*绘制路线
 *@param{array}  routeList  路线数据
*/
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) => {
        k++
        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],
    }),
    zIndex: 196
    });
},

你可能感兴趣的:(openlayers添加标注(含聚合标注)、覆盖物、绘制路线)