Vue 项目中基于maptalks 封装 2D 地图

1,021 阅读1分钟

前言

maptalk.js 是一个用于创建 2D/3D 的轻量 JavaScript 库。本文主要介绍在 Vue2 项目中封装 2D 地图的核心步骤。

步骤

1.  安装 maptalks

"maptalks": "^1.0.0-alpha.26"

2.  DOM 节点设置

<template>
  <div class="map-wrapper">
    <div id="map" class="container"></div>
  </div>
</template>

3.  初始化地图实例

<script>
import 'maptalks/dist/maptalks.css'
import * as maptalks from 'maptalks'
import { shenzhenArea } from './shenzhen-area'

export default {
    methods: {
        initMap () {
          let resolutions = [0.001373291015625, 6.866455078125E-4, 3.433227539063E-4, 1.716613769531E-4, 8.58306884766E-5, 4.29153442383E-5, 2.14576721191E-5, 1.07288360596E-5, 5.3644180298E-6, 2.6822090149E-6, 1.3411045074E-6]
          let mapurl = 'http://10.253.102.69/gw/OGC/Map/SZ_VEC_B4490/?LAYER=w_shenzhen&style=&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&TILEMATRIXSET=EPSG%3A4490&FORMAT=image%2Fpng&TILEMATRIX=EPSG%3A4490%3A{z}&TileRow={y}&TileCol={x}&szvsud-license-key=ndLg0mxz3dbSZiGU5izQ4iGI2cdx/8YGya02K9UgrviZHIR/LZ72feWTJVJsOsYv'

          this.map = new maptalks.Map('map', {
            center: [114.477026, 22.615358],
            zoom: 0.9,
            minZoom: 0.9,
            maxZooom: 6,
            pitch: 0,
            spatialReference: {
              projection: 'EPSG:4326',
              resolutions: resolutions
            },
            attribution: false,
            baseLayer: new maptalks.TileLayer('base', {
              tileSize: [256, 256],
              tileSystem: [1, -1, -180, 90],
              subdomains: ['1', '2', '3', '4', '5'],
              urlTemplate: mapurl
            })
          })
    },
    mounted () {
        this.$nextTick(() => {
          this.initMap()
        })
    }
}
</script>

4.  准备地图数据

地图数据需要符合 GeoJSON 标准。

export const shenzhenArea = {
  'type': 'GeometryCollection',
  'geometries': [
    {
      'type': 'Polygon',
      'properties': {
        'adcode': 440303000000,
        'name': 'xx区',
        'center': [114.181377,22.58274],
        'centroid': [114.148158, 22.57487],
        'childrenNum': 0,
        'level': 'district',
        'parent': { 'adcode': 440300 },
        'subFeatureIndex': 0,
        'acroutes': [100000, 440000, 440300]
      },
      'coordinates': [
        [
          [114.194116624, 22.60783299700006],
          ...
          [114.194116624, 22.60783299700006]
        ]
      ]
    },

5.  绘制区域和文字标记

区域绘制和文字标记分别通过 MultiPolygon、Label API 进行实现,初始化完成后加入同一个图层,最后再添加到地图实例上。

initPolygons () {
      const { geometries } = shenzhenArea
      const polygons = []
      const labels = []

      for (let i = 0, len = geometries.length; i < len; i++) {
        const { coordinates } = geometries[i]
        const { name, adcode, center } = geometries[i].properties
        const _polygonCfg = {
          name,
          adcode,
          center
        }

        // 区域块生成
        let polygon = new maptalks.MultiPolygon(coordinates, {
          visible: true,
          editable: false,
          cursor: 'pointer',
          shadowBlur: 0,
          shadowColor: 'black',
          draggable: false,
          dragShadow: false,
          drawOnAxis: null,
          symbol: {
            'lineColor': 'black',
            'lineWidth': 1,
            // 'polygonFill': 'rgba(135,196,240,0.6)',
            // 'polygonOpacity': 0.2,
            'polygonFill': this.getRegionPolygonColor(adcode)
          },
          extraCfg: _polygonCfg
        })

        polygon.on('dblclick', this.onAreaDblClick)
        polygon.on('click', this.onAreaClick)
        polygons.push(polygon)

        // 文字标记生成
        let label = new maptalks.Label(name.replace(/省|市|办事处|居委会/gi, ''), center, {
          'draggable': true,
          'textSymbol': {
            'textFaceName': 'monospace',
            'textFill': '#34495e',
            'textHaloFill': '#fff',
            'textHaloRadius': 4,
            'textSize': 18,
            'textWeight': 'bold',
            'textVerticalAlignment': 'top'
          }
        })

        labels.push(label)
      }

      if (this.polygonsLayer) {
        this.polygonsLayer.clear()
        this.map && this.map.removeLayer(this.map.getLayers())
      } else {
        this.polygonsLayer = new maptalks.VectorLayer('vector')
      }

      this.polygonsLayer && this.polygonsLayer.addGeometry([...polygons, ...labels])
      this.polygonsLayer.addTo(this.map)
    },

6.  信息弹窗

信息弹窗使用 InfoWindow 实现。

showAreaInfoWindow (param = null) {
      if (this.areaInfoWindow) {
        this.hideAreaInfoWindow()
      }

      if (!param) {
        return
      }

      let cfg = param.target.options.extraCfg

      const _matchedItem = this.getMatchedAreaInfo(cfg)

      if (!_matchedItem) {
        return
      }

      const coordinate = param.coordinate
      const _infoMap = this.getAreaInfoMap()

      let _html = ''

      _matchedItem && (_infoMap.map(info => {
        _html += `<div class="info-item-container"><span class="title">${info.title}:</span><span class="value">${_matchedItem[info.key] ? _matchedItem[info.key] + ' ' + info.unit : '-'}</span></div>`
      }))

      var options = {
        'single': true,
        'width': 183,
        'height': 105,
        'custom': true,
        'dx': -3,
        'dy': -12,
        'amination': 'fade',
        'eventsPropagation': false,
        'eventsToStop': false,
        'content': `<div class="pop-info-window-wrapper">${_html}</div>`
      }

      this.areaInfoWindow = new maptalks.ui.InfoWindow(options)
 this.areaInfoWindow.addTo(this.polygonsLayer).show(coordinate)
    }

7.  下钻

下钻时需要记录当前层级的边界数据以及获取下一层级的边界数据进行绘制,返回上一层级进行绘制时需要控制中心点及缩放层级。

效果

352db1dbb59b6c0ddd911f36b214b7f.png

完整代码

在 Vue2 中基于 maptalks 封装 2D 地图