OpenLayers版本为6的使用

927 阅读4分钟

1.定位,移动图标,清空图标,地图级别

openlayers官网: openlayers.org/en/latest/d…

npm init 初始化 再安装 npm i ol // "ol": "^6.5.0"

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *{margin: 0;padding: 0;}
    #map{
      width: 100vw;
      height: 100vh;
    }
    #icon1{
      cursor: pointer;
    }
    @keyframes zoom{
      from {top: 0; left: 0; width: 32px; height: 32px;}
      50% {top: -16px; left: -16px; width: 64px; height: 64px;}
      to {top: 0; left: 0; width: 32px; height: 32px;}
    }
    @-moz-keyframes zoom{ /* Firefox */
      from {top: 0; left: 0; width: 32px; height: 32px;}
      50% {top: -16px; left: -16px; width: 64px; height: 64px;}
      to {top: 0; left: 0; width: 32px; height: 32px;}
    }
    @-webkit-keyframes zoom{ /* Safari 和 Chrome */
      from {top: 0; left: 0; width: 32px; height: 32px;}
      50% {top: -16px; left: -16px; width: 64px; height: 64px;}
      to {top: 0; left: 0; width: 32px; height: 32px;}
    }
    @-o-keyframes zoom{ /* Opera */
      from {top: 0; left: 0; width: 32px; height: 32px;}
      50% {top: -16px; left: -16px; width: 64px; height: 64px;}
      to {top: 0; left: 0; width: 32px; height: 32px;}
    }
    /* 应用css动画到图标元素上 */
    #iconImg1{
      display: block;
      position: absolute;
      animation: zoom 5s;
      animation-iteration-count: infinite; /* 一直重复动画 */
      -moz-animation: zoom 5s; /* Firefox */
      -moz-animation-iteration-count: infinite; /* 一直重复动画 */
      -webkit-animation: zoom 5s;  /* Safari 和 Chrome */
      -webkit-animation-iteration-count: infinite; /* 一直重复动画 */
      -o-animation: zoom 5s; /* Opera */
      -o-animation-iteration-count: infinite; /* 一直重复动画 */
    }
    #iconImg2{
      display: block;
      position: absolute;
      animation: zoom 5s;
      animation-iteration-count: infinite; /* 一直重复动画 */
      -moz-animation: zoom 5s; /* Firefox */
      -moz-animation-iteration-count: infinite; /* 一直重复动画 */
      -webkit-animation: zoom 5s;  /* Safari 和 Chrome */
      -webkit-animation-iteration-count: infinite; /* 一直重复动画 */
      -o-animation: zoom 5s; /* Opera */
      -o-animation-iteration-count: infinite; /* 一直重复动画 */
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <div class="control">
      <button @click="location(118.09853733, 24.47033414, 18)">定位到厦门市计量检定测试院</button>
      <button @click="clearMarker">清空图标</button>
      <button @click="renderArea">根据经纬度画出区域</button>
      <button @click="showText">文字显示</button>
      <button @click="addIcon(118.09853733, 24.47233414, 1)">添加外部图标1</button>
      <button @click="addIcon(118.09980333, 24.47337838, 2)">添加外部图标2</button>
      <button @click="moverIcon(0.0001, 0.00002)">移动外部图标1</button>
      <button @click="moverIcon(0.001, 0.0002)">移动外部图标2</button>
      <button @click="addSvg">添加svg图片</button>
      <div id="myposition"></div>
    </div>
    <div id="map"></div>
    <div id="icon1">
      <img id="iconImg1" src="http://linwei.xyz/ol3-primer/img/anchor.png" alt="示例锚点">
    </div>
    <div id="icon2">
      <img id="iconImg2" src="http://linwei.xyz/ol3-primer/img/anchor.png" alt="示例锚点">
    </div>
  </div>
</body>
<script src="./index.js"></script>
</html>

index.js

import 'ol/ol.css'
import { Map, View, Feature, Overlay } from 'ol'
import {FullScreen, defaults as defaultControls, MousePosition} from 'ol/control'
// import MultiPoint from 'ol/geom/MultiPoint'
import { Point, MultiPoint, Polygon } from 'ol/geom'
import { transform, fromLonLat } from 'ol/proj.js'
import GeoJSON from 'ol/format/GeoJSON'
import { Circle as CircleStyle, Fill, Stroke, Style, Icon, Text } from 'ol/style'
// import OSM from 'ol/source/OSM'
// import XYZ from 'ol/source/XYZ'
import { OSM, XYZ, Vector as VectorSource } from 'ol/source'
// import TileLayer from 'ol/layer/Tile'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'

const app = new Vue({
  el: '#app',
  data: {
    normalMap: null,
    map: null,
    vectorLayer: null,
    vectorSource: null,
    timer: null,
    shoIcon: false,
    shoIcon2: false,
    icon1: null,
    icon2: null,
    lng: 118.098537,
    lat: 24.47233414,
  },
  mounted() {
    this.mapInit()
    this.mousePosition()
    this.draw()
    // this.renderArea()
    this.watchMap()
  },
  methods: {
    mapInit() {
      this.normalMap = new TileLayer({ // 标准地图,类似再找卫星地图链接
        visible: true, // 显示地图
        source: new XYZ({
          attributions: '我是右边最下面 i 点我下展开,默认空',
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
          // url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7'
          // url: 'http://webst0{1-4}.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}'
          // url: 'https://mt0.google.cn/vt/lyrs=m&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}'
        })
      })
      // const offlineMapLayer = new TileLayer({ // 离线加载瓦片地图
      //   visible: false,
      //   source: new XYZ({
      //     url: '.../{z}/{x}/{y}.png' // z表示的是层级,如果瓦片地图都放在一个目录下,那么url参数就得写成: {z}-{x}-{y}.png
      //   })
      // })
      // this.map.addLayer(offlineMapLayer)
      this.map = new Map({
        target: 'map',
        layers: [this.normalMap],
        // projection: 'EPSG:3857', // 投影
        view: new View({
          // extent: [102, 29, 104, 31],
          center: transform([118.09853733, 24.47033414], 'EPSG:4326', 'EPSG:3857'),
          zoom: 16,
          maxZoom: 18,
          minZoom: 6
        })
      })
      this.vectorSource = new VectorSource({})
      this.marker(118.09853733, 24.47033414, 12)
      this.marker(118.09893733, 24.47333414, 22)
      this.timer = setInterval(this.translate, 500, 12)
    },
    location (lng, lat, size) { // 定位指定位置
      let view = this.map.getView()
      view.setCenter(transform([lng, lat], 'EPSG:4326', 'EPSG:3857')) // 设置中心点
      view.setZoom(size) // 地图放大级别
      // console.log(view.getCenter()) // 获取中心点坐标
    },
    marker (lng, lat, id, img) { // 标记点(经纬度和id)
      if (!lng || !lat) return false
      let iconFeature = new Feature({ // 创建图标特性
        id, // 用来区分多个点
        geometry: new Point(transform([lng, lat], 'EPSG:4326', 'EPSG:3857'))
      })
      this.vectorSource.addFeature(iconFeature)
      this.vectorLayer = new VectorLayer({ // 创建矢量层
        source: this.vectorSource,
        fill: new Fill({ // 自定义个标记点
          color: 'rgba(255, 0, 0, 1)'
        }),
        stroke: new Stroke({
          color: 'red',
          width: 1
        }),
        style: new Style({ // 使用图片
          image: new Icon({
            opacity: 1,
            src: 'https://www.amap.com/assets/img/pos_marker.png',
            anchor: [0, 0] // 设置图标位置
          }),
          text: new Text({
            font: '12px sans-serif', //  默认这个字体,可以修改成其他的,格式和css的字体设置一样
            text: '无人机1号',
            offsetX: 40, // 文字位置(x偏移量)
            offsetY: 0, // 文字位置(y偏移量)
            fill: new Fill({
              color: 'red',
            })
          })
        })
      })
      this.map.addLayer(this.vectorLayer) // 添加进map
    },
    translate(id) {
      this.vectorSource.forEachFeature(f => {
        // console.log(f.values_.id) // 用来区分不同的图标id
        if (id === f.values_.id) {
          const x = Math.random() * 5
          const y = Math.random() * 3
          f.getGeometry().translate(x, y)
        }
      })
    },
    clearMarker() {
      clearInterval(this.timer)
      this.vectorSource.clear() // 清空标记
    },
    mousePosition() { // 鼠标在地图上显示经纬度
      const mousePositionControl = new MousePosition({
        className: 'mosuePosition',
        projection: 'EPSG:4326',
        target: document.getElementById('myposition')
      })
      this.map.addControl(mousePositionControl)
    },
    drawArea() { // 根据多个经纬度点画出区域
      const styles = [
        new Style({
          stroke: new Stroke({
            color: 'blue',
            width: 3
          }),
          fill: new Fill({
            color: 'red'
          })
        }),
        new Style({
          image: new CircleStyle({
            radius: 5,
            fill: new Fill({
              color: 'orange'
            })
          }),
          geometry: function(feature) {
            const coordinates = feature.getGeometry().getCoordinates()[0]
            return new MultiPoint(coordinates)
          }
        })
      ]
      const geojsonObject = {
        'type': 'FeatureCollection',
        'crs': {
          'type': 'name',
          'properties': {
            'name': 'EPSG:3857',
          },
        },
        'features': [
          {
            'type': 'Feature',
            'geometry': {
              'type': 'Polygon',
              'coordinates': [
                [[118.0959624, 24.4715889], [118.096413, 24.4703976], [118.10038268, 24.4715889], [118.09924543, 24.4733466]]
              ]
            }
          }
        ]
      }
      const source = new VectorSource({
        features: new GeoJSON().readFeatures(geojsonObject)
      })
      const layer = new VectorLayer({
        source: source,
        style: styleFunction,
      })
      const styleFunction = feature => {
        return styles[feature.getGeometry().getType()]
      }
      console.log(styleFunction)

      feature = new Feature({
        geometry: new Polygon(coordinatesPolygona)
      })
    },
    draw() {
      let coordinatesPolygon = []
      const coordinates = [
        [[118.0959624, 24.4715889], [118.096413, 24.4703976], [118.10038268, 24.4715889], [118.09924543, 24.4733466]]
      ]
      // for (let i = 0; i < coordinates.length; i++) {
      //   let pointTransform = fromLonLat([coordinates[i][0], coordinates[i][1]], 'EPSG:3857')
      //   coordinatesPolygon.push(pointTransform)
      // }
      let polygon = new Polygon([coordinates])
      let feature = new Feature({
        geometry: polygon
      })
      let source = new VectorSource()
      source.addFeature(feature)
      let vector = new VectorLayer({
        source: source,
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.1)'
          }),
          stroke: new Stroke({
            color: 'red',
            width: 2
          }),
          // image: new Circle({
          //   radius: 10,
          //   fill: new Fill({
          //     color: '#ffcc33'
          //   })
          // })
        })
      })
      // 将经纬度坐标转换为map对应的坐标
      // let geom = new Polygon(coord)
      // geom = geom.transform('EPSG:4326', map.getView().getProjection())
    },
    renderArea() {
      const data = [[118.0959624, 24.4715889], [118.096413, 24.4703976], [118.10038268, 24.4715889], [118.09924543, 24.4733466]]
      // 创建要素
      const features = [
        new Feature({
          geometry: new Polygon([data])// 使用多边形类型
        })
      ]
      // 创建矢量数据源
      const source = new VectorSource({
        features
      })
      // 创建样式
      const style = new Style({
        stroke: new Stroke({
          color: '#4C99F8',
          width: 3,
          lineDash: [5]
        }),
        fill: new Fill({
          color: 'rgba(255,255,255,0.1)'
        })
      })
      // 创建矢量图层
      const areaLayer = new VectorLayer({
        source,
        style,
        zIndex: 1
      })
      areaLayer.on('postrender', evt => { // 添加阴影
        evt.context.shadowBlur = 0
        evt.context.shadowColor = 'rgba(0, 0, 0, 0.20)'
      })
      this.map.addLayer(areaLayer) // 添加到地图实例
    },
    showText() { // 显示文字
      let layer = new VectorLayer({
        source: new VectorSource()
      })
      let anchor = new Feature({
        geometry: new Point(transform([118.0959624, 24.4715889], 'EPSG:4326', 'EPSG:3857'))
      })
      anchor.setStyle(new Style({
        text: new Text({
          font: '12px sans-serif', //  默认这个字体,可以修改成其他的,格式和css的字体设置一样
          text: '最帅的那个男人在这里',
          fill: new Fill({
            color: 'red',
          })
        })
      }))
      layer.getSource().addFeature(anchor)
      this.map.addLayer(layer)
    },
    addGeoJSON() { // 加载矢量地图
      const data = [] // 矢量地图数据
      let layer = new VectorLayer({
        source: new VectorSource({
          features: (new GeoJSON()).readFeatures(data, { // 用readFeatures方法可以自定义坐标系
            dataProjection: 'EPSG:4326', // 设定JSON数据使用的坐标系
            featureProjection: 'EPSG:3857' // 设定当前地图使用的feature的坐标系
          })
        })
      })
    },
    addIcon(lng, lat, id) { // 外部添加图标到地图上
      let icon = 'icon' + id
      icon = new Overlay({
        element: document.getElementById(icon)
      })
      icon.setPosition(transform([lng, lat], 'EPSG:4326', 'EPSG:3857'))
      this.map.addOverlay(icon)
      this.location(lng, lat, 18)
    },
    moverIcon(x, y) {
      this.icon1.setPosition(transform([this.lng + x, this.lat + y], 'EPSG:4326', 'EPSG:3857'))
    },
    addSvg() { // 添加svg图片
      let lng = 118.09853733
      let lat = 24.47033414
      let anchor = new Feature({
        geometry: new Point(transform([lng, lat], 'EPSG:4326', 'EPSG:3857'))
      })
      const svg = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">'+    
      '<path fill="#156BB1" d="M22.906,10.438c0,4.367-6.281,14.312-7.906,17.031c-1.719-2.75-7.906-12.665-7.906-17.031S10.634,2.531,15,2.531S22.906,6.071,22.906,10.438z"/>'+
      '<circle fill="#FFFFFF" cx="15" cy="10.677" r="3.291"/></svg>'
      let mysvg = new Image()
      mysvg.src = 'data:image/svg+xml,' + escape(svg)
      anchor.setStyle(new Style({
        image: new Icon({
          img: mysvg, // 设置Image对象
          imgSize: [30, 30] // 及图标大小
          // src: 'http://www.williambuck.com/portals/0/Skins/WilliamBuck2014/images/location-icon.svg',
          // size: [30, 30]
        })
      }))
      let layer = new VectorLayer({
        source: new VectorSource()
      })
      layer.getSource().addFeature(anchor)
      this.map.addLayer(layer)
    },
    watchMap() { // 监听地图事件
      this.map.getView().on('change:resolution', () => { // 监听地图缩放
      })
      let click = this.map.on('singleclick', evt => { // 监听单击地图
        let coordinate = evt.coordinate
        console.log(evt)
      })
    },
    test() {
      // 长时间不操作
      let minute = 2
      setInterval(() => {
        minute--
        if (minute <= 0) {
          console.log(1)
        }
      }, 1000 * 6)
      addEventListener('mousemove', () => minute = 2)
    }
  }
})