openlayer的基本使用(区域绘制、点线绘制、手动绘制轨迹)

实现如图所示效果:

openlayer的基本使用(区域绘制、点线绘制、手动绘制轨迹)_第1张图片

 html部分

{{isDraw ? '结束绘制' : '开始绘制'}}{{drawTypeText}} 清除绘制 {{isDelete ? '确认删除' : '删除轨迹'}}
名称:飞燕一号
名称:泰坦尼克号
飞行速度:2.25马赫(2400公里/小时)
航速:40节
在这拐了个弯

 需求需要的数据如下:

data(){
  return {
    map: null,
    areaLayer: null,  //区域
    pointLayer: null, //点
    trailLayer: null,  //轨迹
    pointInfo: {},   //鼠标点击点信息
    hoverPointInfo: {},  //鼠标移入点信息
    drawLayer: null,   //绘图的轨迹
    pointTempLayer: null,  //绘制轨迹时添加的临时点
    isDraw: false,  //是否正在绘制
    isDelete: false, //是否在删除
    clickPoints: [],  //绘制时暂存的点
    tempLine: null,  //临时边
    tempPoint: null,  //临时点
    drawType: '',    //地图绘制类型
  }
},
computed: {
  drawTypeText(){
    let text = ''
    let map = {
      plane: '飞机',
      ship: '船舰',
    }
    if(this.drawType){
      text = map[this.drawType]
    }
    return (text ? ('(' + text + ')') : '')
  }
},
绘制地图
initMap(){
  this.map = null
  this.layer = null
  this.pointLayer = null
  this.trailLayer = null
  // 图层
  this.layer = new TileLayer({
    source: new XYZ({
      visible: true,
      url: 'http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=2&scale=1&style=8',
      wrapX: true,
    }),
  })

  //区域
  this.areaLayer = new Vector({
    source: new VectorSource(),
  })

  //点
  this.pointLayer = new Vector({
    source: new VectorSource(),
  })
  //轨迹
  this.trailLayer = new Vector({
    source: new VectorSource(),
  })
  //临时点
  this.pointTempLayer = new Vector({
    source: new VectorSource(),
  })

  // 初始化地图到指定DOM元素
  this.map = new Map({
    layers: [this.layer, this.trailLayer, this.areaLayer,  this.pointLayer, this.pointTempLayer],
    target: "map",
    view: new View({
      projection: 'EPSG:4326',
      center: [135.403218, 30.92372],
      zoom: 4,
      maxZoom: 11,
      constrainResolution: true,  // 设置缩放级别为整数
      smoothResolutionConstraint: false,  // 关闭无级缩放地图
    }),
  });


  //鼠标点击点图层,获取该点的数据
  let selectInteraction = new Select({
    layers: [this.pointLayer],
  });
  this.map.addInteraction(selectInteraction)
  selectInteraction.on('select', e => {
    const selectedFeature = (e.selected || [])[0];
    if(selectedFeature){
      this.pointInfo = selectedFeature.getProperties()
      console.log(this.pointInfo)
    }
  })

  //鼠标移入显示id为overPlay的div
  let hoverFeature = null
  this.map.on('pointermove',(e) => {
    let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {
      return feature
    },{hitTolerance: 5})
    //有feature且feature变化才执行
    if(feature != hoverFeature){
      hoverFeature = feature
      if(feature && feature.getGeometry().getType() == 'Point'){
        this.map.getTargetElement().style.cursor = "pointer";
        this.hoverPointInfo = feature.getProperties()
        this.addOverlay(this.hoverPointInfo.coords,'overPlay')
      }else{
        this.map.getTargetElement().style.cursor = "";
        this.hoverPointInfo = {}
        this.removeOverlays()
      }
    }
  })

},
地图上加区域
//地图上加区域
addArea(data){
  let feature = new Feature({
    geometry: new Polygon(data),
  })
  feature.setStyle(mapStyle.redAreaStyle)
  this.areaLayer.getSource().addFeature(feature)
},
 地图上加点
//地图上加点
addPoint(type, data){
  if(type == 'plane'){
    let point = new Point(data.coords)
    let pointFeature = new Feature({
      geometry: point,
      ...data
    })
    pointFeature.setStyle(mapStyle.pointRedPlane)
    this.pointLayer.getSource().addFeature(pointFeature)
  }
  if(type == 'ship'){
    let point = new Point(data.coords)
    let pointFeature = new Feature({
      geometry: point,
      ...data
    })
    pointFeature.setStyle(mapStyle.pointRedShip)
    this.pointLayer.getSource().addFeature(pointFeature)
  }
  if(type == 'red'){
    let point = new Point(data.coords)
    let pointFeature = new Feature({
      geometry: point,
      ...data
    })
    pointFeature.setStyle(mapStyle.pointRed)
    this.pointLayer.getSource().addFeature(pointFeature)
  }

},
地图上加轨迹
//地图上加轨迹
addTrail(type,data){
  data.forEach(e => {
    let feature = new Feature({
      geometry: new LineString(e),
    })
    feature.setStyle(mapStyle.redLineArrow(feature))
    this.trailLayer.getSource().addFeature(feature)
  })
},
 地图上加div

        删除overlay后,再次调用addOverlay方法新增overlay不显示,所以鼠标移除时隐藏overlay。调用addOverlay方法后会创建dom,避免出现过多无用dom情况,下次新增时只改变overlay的位置。

//地图上加div
addOverlay(data,id){
  if(!this.map.getOverlayById(id)){
    let marker = new Overlay({
      id,
      position: data,
      element: document.getElementById(id),
      offset: [10, 20]
    });
    this.map.addOverlay(marker);
    marker.setPositioning("top-left");
  } else{
    let marker = this.map.getOverlayById(id)
    marker.setPosition(data)
  }
},
地图上删除div
//地图上删除div
removeOverlays() {
  let overlays = this.map.getOverlays();
  for (let i = 0, len = overlays.getLength(); i < len; i++) {
    overlays.item(i).setPosition(undefined)
  }
},
手动绘制轨迹

        点击开始绘制按钮后为地图新增点击事件,用户需要在地图上点击地图生成临时点,当临时点数量大于等于2时,临时点连接生成临时边,当点击结束绘制按钮后,关闭该点击事件,临时点和临时线转化为真实点和真实线。

//修改绘制类型
changeDrawType(type){
  this.drawType = type
},
//开始绘制地图
clickDraw(){
  if(this.isDraw){
    this.endDraw()
  }else{
    if (!this.drawType) {
      this.$message.warning('请选择绘制类型')
      return
    }
    this.drawTrail()
  }
},
//进入开始手动绘制状态
drawTrail(){
  if(!this.isDraw){
    this.isDraw = true
    this.clickPoints = []
    this.map.on('click', this.handleMapClick)
  }
},
//结束手动绘制状态
endDraw(){
  if(this.isDraw){
    this.isDraw = false
    this.map.un('click', this.handleMapClick)
    //唯一标识,便于统一管理
    let groupId = 'point-' + Date.now()
    //临时点改为真实点
    if(this.clickPoints){
      this.pointTempLayer.getSource().clear()
      this.tempPoint = null
      this.clickPoints.forEach((e, index) => {
        if(index == 0 || index == (this.clickPoints.length - 1)){
          this.addPoint(this.drawType, {
            type: this.drawType,
            coords: e,
            groupId
          })
        }
      })
    }
    //临时线改为真实线
    if(this.clickPoints.length >= 2){
      let feature = new Feature({
        geometry: new LineString(this.clickPoints),
        groupId
      })
      feature.setStyle(mapStyle.redLineArrow(feature))
      this.trailLayer.getSource().addFeature(feature)
      if(this.tempLine){
        this.trailLayer.getSource().removeFeature(this.tempLine)
        this.tempLine = null
      }
      this.clickPoints = []
    }
  }
},
//绘制的点击事件
handleMapClick(e){
  if(!this.isDraw) return;
  const coord = e.coordinate
  this.clickPoints.push(coord)

  if(this.tempLine){
    this.trailLayer.getSource().removeFeature(this.tempLine)
  }
  if(this.clickPoints.length >= 2){
    this.tempLine = new Feature({
      geometry: new LineString(this.clickPoints),
    })
    this.tempLine.setStyle(mapStyle.tempLineArrow(this.tempLine))
    this.trailLayer.getSource().addFeature(this.tempLine)
  }
  if(coord){
    this.tempPoint = new Feature({
      geometry: new Point(coord)
    })
    this.tempPoint.setStyle(mapStyle.positionPointTemp)
    this.pointTempLayer.getSource().addFeature(this.tempPoint)
  }

}
清除绘制

        清除临时点和临时线

//清除绘制
clearDraw(){
  this.pointTempLayer.getSource().clear()
  this.tempPoint = null
  if(this.tempLine){
    this.trailLayer.getSource().removeFeature(this.tempLine)
    this.tempLine = null
  }
  this.clickPoints = []
},
删除绘制内容

        临时点和临时线转为真实点和真实线时,为其加上groupId属性表示该轨迹为手绘轨迹,仅有手绘轨迹可删除。该删除为删除掉有groupId的真实点和真实线。

//删除轨迹
deleteDraw(){
  this.isDelete = !this.isDelete
  if(this.isDelete){
    this.map.on('click',this.handleMapDelete)
  }else{
    this.map.un('click',this.handleMapDelete)
  }
},
handleMapDelete(e){
  let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {
    return feature
  },{hitTolerance: 5})
  if(!feature.get('groupId')){
    this.$message.warning('该轨迹非手绘轨迹,不可删除')
    return
  }
  const pointFeatures = this.pointLayer.getSource().getFeatures()
  pointFeatures.forEach(f => {
    if(f.get('groupId') == feature.get('groupId')){
      this.pointLayer.getSource().removeFeature(f)
    }
  })
  const lineFeatures = this.trailLayer.getSource().getFeatures()
  lineFeatures.forEach(f => {
    if(f.get('groupId') == feature.get('groupId')){
      this.trailLayer.getSource().removeFeature(f)
    }
  })
},
样式
import Fill from "ol/style/fill";
import Stroke from "ol/style/stroke";
import Style from "ol/style/style";
import Icon from "ol/style/icon";
import Circle from "ol/style/circle";
import Point from "ol/geom/point";

//红色多边形样式
function redAreaStyle(){
    let fillColor = new Fill({
        color: 'rgba(255, 0, 0, 0.2)'
    })
    let stroke = new Stroke({
        color: 'red',
        width: 1,
    })
    return new Style({
        stroke,
        fillColor
    })
}

//红色船
function pointRedPlane(){
    return new Style({
        image: new Icon({
            src: require('../img/redPlane.svg'),
            scale: 0.2,  //缩放比例
        })
    })
}
//红色飞机
function pointRedShip(){
    return new Style({
        image: new Icon({
            src: require('../img/redShip.svg'),
            scale: 0.2,  //缩放比例
        })
    })
}
//红色点
function pointRed(){
    return new Style({
        image: new Circle({
            radius: 5,
            fill: new Fill({
                color: 'red'
            })
        })
    })
}

//红色轨迹线
function redLineArrow(feature) {
    let geometry = feature.getGeometry();
    let styles = [new Style({
        stroke: new Stroke({
            color: '#d71106',
            width: 2,
            lineDash: [6,5]
        })
    })];
    geometry.forEachSegment(function (start, end) {
        let dx = end[0] - start[0];
        let dy = end[1] - start[1];
        let rotation = Math.atan2(dy, dx);
        const kx = (end[0] + start[0]) / 2
        const ky = (end[1] + start[1]) / 2
        console.log(kx,ky)
        //arrows
        styles.push(new Style({
            geometry: new Point([kx, ky]),
            image: new Icon({
                src: require('../img/arrow_red.png'),
                anchor: [0.75, 0.5],
                rotateWithView: false,
                rotation: -rotation
            })
        }));
    });
    return styles
}

//临时箭头
function tempLineArrow(feature) {
    let geometry = feature.getGeometry();
    let styles = [new Style({
        stroke: new Stroke({
            color: '#ffcc33',
            width: 2,
            lineDash: [6,5]
        })
    })];
    geometry.forEachSegment(function (start, end) {
        let dx = end[0] - start[0];
        let dy = end[1] - start[1];
        let rotation = Math.atan2(dy, dx);
        const kx = (end[0] + start[0]) / 2
        const ky = (end[1] + start[1]) / 2
        //arrows
        styles.push(new Style({
            geometry: new Point([kx, ky]),
            image: new Icon({
                src: require('../img/arrow.png'),
                anchor: [0.75, 0.5],
                rotateWithView: false,
                rotation: -rotation
            })
        }));
    });

    return styles;
}
//临时点
function positionPointTemp(){
    return new Style({
        image: new Circle({
            radius:5,
            fill:new Fill({
                color: '#ffcc33'
            })
        }),
    });
}


let mapStyle = {
    redAreaStyle,
    pointRedPlane,
    pointRedShip,
    pointRed,
    redLineArrow,
    positionPointTemp,
    tempLineArrow,
}
export default mapStyle

项目地址

你可能感兴趣的:(vue.js,javascript,ecmascript)