准备工作,需要先下载好离线地图的瓦片文件

安装openlayers地图:npm install ol

瓦片下载工具:全能瓦片下载工具

openlayer mbtiles 离线 openlayers 离线地图_vue.js


openlayer mbtiles 离线 openlayers 离线地图_vue.js_02

openlayers 官方api:官方api英文文档 地图的行政区划json名为“canton.json”,下载需要的行政区json:json下载地址

openlayer mbtiles 离线 openlayers 离线地图_json_03

本地的地图瓦片需要跑一个服务才能使用,本地运行时地图瓦片文件夹使用http-server创建服务

安装:http-server 全局安装后去到需要瓦片文件夹里执行:

openlayer mbtiles 离线 openlayers 离线地图_json_04


此时就已经可以在浏览器查看对应的http://192.168.100.90:8081,成功如下所示。

openlayer mbtiles 离线 openlayers 离线地图_javascript_05

项目中加入一个vue文件,我原本的自定义内容比较多,删掉了一大部分自定义的信息窗内容,样式也基本删掉,但下面的代码几乎是离线地图标题中的功能了

<template>
  <div style="width: 100%;height: 100%;position: relative;">
    <div class="map"
         id="map"></div>
    <div id="people_info">
      <div class="tipContainer"></div>
    </div>
  </div>
</template>

<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import Feature from 'ol/Feature';
import VectorSource from 'ol/source/Vector';
import Overlay from 'ol/Overlay';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import View from 'ol/View';
import { transform } from 'ol/proj';
import XYZ from 'ol/source/XYZ'
import Point from 'ol/geom/Point';
import GeoJSON from 'ol/format/GeoJSON';
import { Fill, Stroke, Icon, Style } from 'ol/style'
import markerImg from '@/assets/big-screen/icon-build.png'//图标资源
import { LineString, Polygon } from 'ol/geom'
export default {

  name: "openlayersMap",
  data () {
    return {
      mapObj: null,
      mapDom: null,
      mapPointList: [],
      pointLayerSource: null,
      pointLayer: null,
      markerIcon: markerImg,
    }
  },
  mounted () {
    this.initMap()
  },
  methods: {
    // 清除地图 某些情况 地图容器会存在两个 导致地图无法正常显示 这个问题折腾了我半天。
    // 找了半天官方貌似也没有提供 对应的 api,自己动手了。
    mapClear () {
      if (this.mapDom) {
        this.mapDom.innerHTML = ''
        this.mapDom = null
      }
    },
    // 初始化地图
    initMap () {
      // 先尝试清除
      this.mapClear()
      // 获取地图容器
      this.mapDom = document.getElementById('map')
      // 初始化地图配置
      this.mapObj = new Map({
        target: this.mapDom, // 地图容器
        view: new View({
          center: [107.975994, 26.602712], // 地图中心点
          zoom: 9, // 缩放
          projection: 'EPSG:4326' // 坐标系
        })
      })

      // 添加一个使用离线瓦片地图的层
      const offlineMapLayer = new TileLayer({
        source: new XYZ({
            url: 'http://192.168.100.90:8081' + '/{z}/{x}/{y}.png'  // 设置本地离线瓦片所在路径
        //   url: 'http://83.218.0.40:812/map' + '/{z}/{x}/{y}.png'  // 设置内网离线瓦片所在路径
        })
      })
      // 将图层添加到地图
      this.mapObj.addLayer(offlineMapLayer)

      // 地图点击事件
      this.mapOnClick()
      //地图hover事件
      this.mapOnenterMove()
      //画出行政区划边界
      this.addAreaPolygon()
      // 加载地理坐标,放在后面则为上层
      this.addPoint()
      //用于hover的点坐标,mark参数需要自己传
      this.addPointPeople()
    },
    // 地图点击事件
    mapOnClick () {
      const self = this
      // 地图点击事件
      this.mapObj.on('click', function (evt) {
        console.log(evt)
        // 获取点击位置的数据
        var feature = self.mapObj.forEachFeatureAtPixel(evt.pixel, (feature) => {
          return feature
        })
        // 判断数据,
        if (feature) {
            //此处可以去开启处理自定义的信息窗
          self.getBuildInfo(feature.values_.data)
        }
      })
    },
    mapOnenterMove () {
      const self = this
      const tipDom = document.getElementById('people_info')
      // 创建 tip
      const tip = new Overlay({
        element: tipDom,
        positioning: 'bottom-center',
        stopEvent: false
      })
      // // 加载到地图
      this.mapObj.addOverlay(tip)
      // 地图鼠标移入事件
      this.mapObj.on('pointermove', function (evt) {
        // 获取点击位置的数据
        var feature = self.mapObj.forEachFeatureAtPixel(evt.pixel, (feature) => {
          return feature
        })
        // 根据 点击元素 className 判断是否点击在自定义popup上
        const isMoveTip = evt.originalEvent.path.map(item => item.className).includes('people_info')
        if (!isMoveTip) {
          tipDom.style.display = 'none'
        }
        // 官方示例 采用 jq + bootstrap弹窗,但是我觉得没有必要 如果大量使用bootstrap 组件可以考虑引入。
        const tipContainer = document.getElementsByClassName('tipContainer')[0]
        // 判断数据
        if (feature) {
          // feature.values_.data ,data字段是在 addPoint 函数创建point时添加 可以自定义
          if (feature.values_.data) {
            const pointData = feature.values_.data
            // console.log(pointData)
            tip.setPosition(evt.coordinate)
            if (!pointData.name) return
            var infoShow = pointData.realname ? `${pointData.name}--${pointData.realname}` : 'not info'
            tipContainer.innerHTML = `<div>${infoShow}</div>`
            tipDom.style.display = 'block'
          }
        }
      })
    },
    // 添加地理坐标
    addPoint (mark) {
      this.delPointAll()
      // 地理坐标数组
      var defaultData = [
        // { longitude: 108.042078, latitude: 26.549856, nickname: '李大壮' },
        // { longitude: 107.956612, latitude: 26.56404, nickname: '李大壮2' },
      ]
      var pointData = (mark !== undefined) ? mark : defaultData

      pointData.map(item => {
        console.log('point_item', item)
        // 创建点
        const point = new Feature({
          geometry: new Point([Number(item.longitude), Number(item.latitude)]),
          data: item
        })
        // 点的样式
        const iconStyle = new Style({
          image: new Icon({
            color: '#ffffff',
            crossOrigin: 'anonymous',
            src: this.markerIcon2,
            scale: 0.5,//放大缩小
          }),
        })
        // 设置样式
        point.setStyle(iconStyle)
        // 保存到数据  方便删除
        this.mapPointList.push(point)
      })
      // 创建geojson据源
      this.pointLayerSource = new VectorSource({ features: this.mapPointList })
      // 创建图层 并加载数据
      this.pointLayer = new VectorLayer({ source: this.pointLayerSource })
      // 将图层添加地图上
      this.mapObj.addLayer(this.pointLayer)
    },
    //hover的坐标
    addPointPeople (mark) {
      var defaultData = [
        { longitude: 108.242078, latitude: 26.749856, name: '李大壮' },
        { longitude: 107.756612, latitude: 26.36404, name: '李大壮2' },
      ]
      //   var pointData = defaultData
      var pointData = mark ? mark : defaultData
      pointData.map(item => {
        // console.log('point_item', item)
        // 创建点
        const point = new Feature({
          geometry: new Point([Number(item.longitude), Number(item.latitude)]),
          data: item
        })
        // 点的样式
        const iconStyle = new Style({
          image: new Icon({
            color: '#ffffff',
            crossOrigin: 'anonymous',
            src: this.markerIcon3,
            scale: 0.5,//放大缩小
          }),
        })
        // 设置样式
        point.setStyle(iconStyle)
        // 保存到数据  方便删除
        this.mapPointList.push(point)
      })
      // 创建geojson据源
      this.pointLayerSource = new VectorSource({ features: this.mapPointList })
      // 创建图层 并加载数据
      this.pointLayer = new VectorLayer({ source: this.pointLayerSource })
      // 将图层添加地图上
      this.mapObj.addLayer(this.pointLayer)
    },
    addAreaPolygon () {
      let geoJson = require('@/utils/canton.json')
      console.log('geoJson', geoJson.features)
      var borderList = []
      geoJson.features.map((item, index) => {
        console.log(item)
        var border_item = {}
        border_item.ad_name = item.properties.name
        border_item.border = item.geometry.coordinates[0]
        borderList.push(border_item)
      })
      //多个区域遍历画出边界
      borderList.map((item, idx) => {
        let polygonFeature = new Feature({
          type: 'polygon',
          name: item.ad_name,
          geometry: new Polygon(item.border)
        })
        polygonFeature.setStyle(new Style({
          stroke: new Stroke({
            width: 2,
            color: [0, 0, 205, 0.8]
          }),
          fill: new Fill({
            color: [0, 206, 209, 0.2]
          }),
          //   text: new Text({
          //     text: item.name
          //   })
        }))
        let polygonLayer = new VectorLayer({
          source: new VectorSource({
            features: [polygonFeature]
          })
        })
        this.mapObj.addLayer(polygonLayer)
      })
      //   var arr = geoJson.features[0].geometry.coordinates[0]
    },
    // 地理点位删除
    delPointAll () {
      // 判断 删除的数据源是否存在
      if (this.pointLayerSource) {
        // 遍历删除
        this.mapPointList.map(item => {
          this.pointLayerSource.removeFeature(item)
        })

        // 删除图层 重置数据
        this.mapObj.removeLayer(this.pointLayer)
        this.pointLayerSource = null
        this.pointLayer = null
        this.mapPointList = []
      }
    },
    //重置地图中心点位置,按自己需求地图需要移动时传入参数即可
    restMapCenetr (mk) {
      console.log(mk, this.mapObj)
      if (mk) {
        this.mapObj.getView().animate({ // 只设置需要的属性即可
          center: [mk.longitude, mk.latitude], // 中心点
          zoom: 12, // 缩放级别
          rotation: undefined, // 缩放完成view视图旋转弧度
          duration: 1000 // 缩放持续时间,默认不需要设置
        })
      }
    },
  },
  beforeDestroy () {
    this.mapClear()
  }
}
</script>

<style lang="scss" scoped>
.map {
  width: 100%;
  height: 100%;
}
.tipContainer {
  background-color: #fff;
  padding: 8px;
  border-radius: 4px;
}
.popup {
    //自定义的样式
  position: absolute;
  z-index: 998 !important;
  width: 120%;
  height: 100%;
  border: 2px solid #02d3ea;
  left: -10%;
  top: -10%;
  display: none;
}
</style>