leaflet adds different types of marker s to different layers and realizes layer switching

Posted by pulsedriver on Fri, 07 Jan 2022 09:07:15 +0100

leaflet is widely used in the development of two-dimensional gis, and I am also engaged in gis related development recently. While these two days are not very busy, quickly record the development process of these two days as a reference for future work.

General steps for adding marker to leaflet:

The figure above shows the general steps of adding marker to leaflet.

Initialize map:

The map uses the leaflet plug-in @ SuperMap / iclient leaflet of hypergraph. The official address is: https://github.com/SuperMap/iClient-JavaScript/tree/master/src/leaflet . The reason for choosing hypergraph is that it is convenient to call the service of hypergraph when drawing the path in the later stage. On the other hand, the project framework is based on hypergraph.

First, introduce plug-ins into the project, as shown in the figure:

 

For convenience, I downloaded the two css locally. The download link is as follows: https://unpkg.com/leaflet@1.3.1/dist/leaflet.csshttps://iclient.supermap.io/dist/leaflet/iclient-leaflet.min.css , these two download links are available in the official website. After downloading, you can introduce them in the html page. After the plug-in is imported, the map is initialized. The code is as follows:

initMap () {
      const host = window.isLocal
        ? window.server
        : 'https://iserver.supermap.io'
      const url = host + '/iserver/services/map-china400/rest/maps/China'
      this.mapObj = L.map(this.mapId, {
        // center: [0, 0],
        center: [45.7413805110411, 127.165046475283],
        maxZoom: 18,
        zoom: 6,
        zoomControl: false
      })
      L.supermap.tiledMapLayer(url).addTo(this.mapObj)
      this.rootLayerGroup = L.featureGroup().addTo(this.mapObj) // Add root layer (easy to manage other layers)
    },

Then call it in mounted, as follows:

mounted () {
    this.$nextTick(() => {
      this.initMap()
    })
  },

Create icon object

In the project, there are different types of markers, and each marker corresponds to an icon, so different icons are required. In addition, when the marker clicks the highlighted icon, two icon objects need to be prepared for each type of mrker, one is the default and the other is highlighted, Here, two objects defaultIcons and focusIcons are used to save the default icon and highlighted icon respectively (the two objects are actually two map structures, with the type as key and the corresponding icon as value). The background data of several markers shall prevail. Here is a json file simulation data:

{
    "code": 200,
    "data": [
        {
            "id": 1,
            "lat": "",
            "lng": "",
            "poiName": "bridge",
            "poiType": "bridge",
            "children": [
                {
                    "id": 2,
                    "lat": 44.9255,
                    "lng": 127.2017,
                    "poiName": "Jiamusi Bridge",
                    "poiType": "bridge"
                },
                {
                    "id": 3,
                    "lat": 45.7933,
                    "lng": 128.6749,
                    "poiName": "Jiamusi medium bridge",
                    "poiType": "bridge"
                },
                {
                    "id": 4,
                    "lat": 44.9194,
                    "lng": 128.5764,
                    "poiName": "Jiamusi Bridge",
                    "poiType": "bridge"
                },
                {
                    "id": 12,
                    "lat": 46.500976,
                    "lng": 125.049838,
                    "poiName": "Bridge A",
                    "poiType": "bridge"
                },
                {
                    "id": 13,
                    "lat": 46.11039,
                    "lng": 125.305188,
                    "poiName": "Bridge B",
                    "poiType": "bridge"
                },
                {
                    "id": 14,
                    "lat": 46.657439,
                    "lng": 125.026459,
                    "poiName": "Bridge C",
                    "poiType": "bridge"
                },
                {
                    "id": 15,
                    "lat": 47.744832,
                    "lng": 128.859247,
                    "poiName": "Bridge D",
                    "poiType": "bridge"
                },
                {
                    "id": 16,
                    "lat": 48.668639,
                    "lng": 130.477707,
                    "poiName": "Bridge E",
                    "poiType": "bridge"
                },
                {
                    "id": 17,
                    "lat": 47.424955,
                    "lng": 124.107461,
                    "poiName": "Bridge F",
                    "poiType": "bridge"
                },
                {
                    "id": 18,
                    "lat": 47.39034,
                    "lng": 123.920893,
                    "poiName": "Bridge G",
                    "poiType": "bridge"
                }
            ]
        },
        {
            "id": 5,
            "lat": "",
            "lng": "",
            "poiName": "culvert",
            "poiType": "culvert",
            "children": [
                {
                    "id": 6,
                    "lat": 45.7404,
                    "lng": 127.1621,
                    "poiName": "Culvert 1",
                    "poiType": "culvert"
                },
                {
                    "id": 7,
                    "lat": 45.44,
                    "lng": 126.41,
                    "poiName": "Culvert 2",
                    "poiType": "culvert"
                },
                {
                    "id": 8,
                    "lat": 45.73832834,
                    "lng": 127.1584935,
                    "poiName": "Culvert 3",
                    "poiType": "culvert"
                },
                {
                    "id": 19,
                    "lat": 44.599933,
                    "lng": 129.616987,
                    "poiName": "Tunnel A",
                    "poiType": "culvert"
                }
            ]
        },
        {
            "id": 9,
            "lat": "",
            "lng": "",
            "poiName": "sign",
            "poiType": "trafficSafe",
            "children": [
                {
                    "id": 10,
                    "lat": 45.74045209,
                    "lng": 127.1617092,
                    "poiName": "Mandatory Sign",
                    "poiType": "trafficSafe"
                },
                {
                    "poiName": "traffic signs",
                    "poiType": "trafficSafe",
                    "lat": 45.74045209,
                    "lng": 128.1617843,
                    "id": 11
                }
            ]
        }
    ]
}

It can be seen that the data here is a tree structure, with a total of 3 markers (number of parent nodes). To facilitate naming the picture as the corresponding type, as shown in the figure:

Initialize icon after obtaining data. The code is as follows:

async getData () {
      const dataRes = await axios.get('/static/json/elTreeData.json')
      if (dataRes) {
        const treeData = dataRes.data.data
        this.setIcons(treeData)
      }
    },
    /**
     * Initialize Icons
     */
    setIcons (data) {
      data.forEach((item) => {
        this.defaultIcons[item.poiType] = L.icon({
          iconUrl: '/static/images/' + item.poiType + 'DefaultIcon.png',
          iconSize: [48, 60],
          iconAnchor: [24, 60],
          popupAnchor: [0, -30]
        })
        this.focusIcons[item.poiType] = L.icon({
          iconUrl: '/static/images/' + item.poiType + 'FocusIcon.png',
          iconSize: [48, 60],
          iconAnchor: [24, 60],
          popupAnchor: [0, -30]
        })
      })
    },

Create marker layers and marker points

Point aggregation is required when creating a marker. Point aggregation uses leaflet, a plug-in of leaflet Markercluster, please refer to the official website for specific usage https://github.com/Leaflet/Leaflet.markercluster , the code for creating marker is as follows:

initMarkers (data) {
      data.forEach((item) => {
        // marker aggregation markerClusterGroup is essentially a layer, similar to featuregroup
        const markerLayer = L.markerClusterGroup({
          spiderfyOnMaxZoom: false,
          showCoverageOnHover: false,
          zoomToBoundsOnClick: false
        })
        item.children.forEach((item1) => {
          const marker = L.marker([item1.lat, item1.lng], {
            icon: this.defaultIcons[item1.poiType],
            markerId: item1.id,
            type: item1.poiType
          }).on('click', (ev) => {
            this.resetMarker()
            ev.target.setIcon(this.focusIcons[ev.target.options.type])
            this.focusMaker = ev.target
          })
          markerLayer.addLayer(marker)
        })
        this.rootLayerGroup.addLayer(markerLayer) // Add markerLayer to the root layer
      })
    },
    /**
     * Reset the last click on the marker to the default icon
     */
    resetMarker () {
      if (this.focusMaker) {
        const iconType = this.focusMaker.options.type
        this.focusMaker.setIcon(this.defaultIcons[iconType])
      }
    }

Add layer switching function

Layer switching uses the addLayer() and clearLayers() methods of layerGroup. The main codes are as follows:

/**
     * Initialize checkbox value
     */
    initCheckGroup (data) {
      data.forEach((item) => {
        this.checkedMarkerLayerKey.push(item.poiType)
        this.markerLayerKeys.push({
          name: item.poiName,
          poiType: item.poiType
        })
      })
    },
    /**
     * Layer check
     */
    checkGroupChange (val) {
      this.rootLayerGroup.clearLayers()
      val.forEach((item) => {
        this.rootLayerGroup.addLayer(this.layersObj[item])
      })
    }

Final effect:

 

This article is the reference, copy and paste source of my actual project, so some details are not mentioned. Finally, the complete code of the map vue file is attached.

mapVue complete code

<template>
  <div class="map-2d">
    <div class="markerLayer-control">
      <el-checkbox-group
        v-model="checkedMarkerLayerKey"
        @change="checkGroupChange"
      >
        <el-checkbox
          v-for="item in markerLayerKeys"
          :key="item.poiType"
          :label="item.poiType"
        >
          {{ item.name }}
        </el-checkbox>
      </el-checkbox-group>
    </div>
    <div class="map2d-container" :id="mapId"></div>
  </div>
</template>
<script>
import 'leaflet.markercluster/dist/MarkerCluster.css'
import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
import 'leaflet.markercluster'
import axios from 'axios'
export default {
  data () {
    return {
      mapId: 'map2d', // Map id
      mapObj: null, // Map object
      rootLayerGroup: null, // Root layer
      checkedMarkerLayerKey: [], // Layer check value - checkbox group binding value
      markerLayerKeys: [], // Layer type - for checkbox
      defaultIcons: {}, // Default icon
      focusIcons: {}, // Highlight Icon
      layersObj: {} // Store markerLayer layer to facilitate layer switching
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.initMap()
    })
  },
  methods: {
    initMap () {
      const host = window.isLocal
        ? window.server
        : 'https://iserver.supermap.io'
      const url = host + '/iserver/services/map-china400/rest/maps/China'
      this.mapObj = L.map(this.mapId, {
        // center: [0, 0],
        center: [45.7413805110411, 127.165046475283],
        maxZoom: 18,
        zoom: 6,
        zoomControl: false
      })
      L.supermap.tiledMapLayer(url).addTo(this.mapObj)
      this.rootLayerGroup = L.featureGroup().addTo(this.mapObj) // Add root layer (easy to manage other layers)
      this.getData()
    },
    async getData () {
      const dataRes = await axios.get('/static/json/elTreeData.json')
      if (dataRes) {
        const treeData = dataRes.data.data
        this.setIcons(treeData)
        this.initMarkers(treeData)
        this.initCheckGroup(treeData)
      }
    },
    /**
     * Initialize Icons
     */
    setIcons (data) {
      data.forEach((item) => {
        this.defaultIcons[item.poiType] = L.icon({
          iconUrl: '/static/images/' + item.poiType + 'DefaultIcon.png',
          iconSize: [48, 60],
          iconAnchor: [24, 60],
          popupAnchor: [0, -30]
        })
        this.focusIcons[item.poiType] = L.icon({
          iconUrl: '/static/images/' + item.poiType + 'FocusIcon.png',
          iconSize: [48, 60],
          iconAnchor: [24, 60],
          popupAnchor: [0, -30]
        })
      })
    },
    initMarkers (data) {
      data.forEach((item) => {
        // marker aggregation markerClusterGroup is essentially a layer, similar to featuregroup
        const markerLayer = L.markerClusterGroup({
          spiderfyOnMaxZoom: false,
          showCoverageOnHover: false,
          zoomToBoundsOnClick: false
        })
        item.children.forEach((item1) => {
          const marker = L.marker([item1.lat, item1.lng], {
            icon: this.defaultIcons[item1.poiType],
            markerId: item1.id,
            type: item1.poiType
          }).on('click', (ev) => {
            this.resetMarker()
            ev.target.setIcon(this.focusIcons[ev.target.options.type])
            this.focusMaker = ev.target
          })
          markerLayer.addLayer(marker)
        })
        this.layersObj[item.poiType] = markerLayer
        this.rootLayerGroup.addLayer(markerLayer) // Add markerLayer to the root layer
      })
    },
    /**
     * Reset the last click on the marker to the default icon
     */
    resetMarker () {
      if (this.focusMaker) {
        const iconType = this.focusMaker.options.type
        this.focusMaker.setIcon(this.defaultIcons[iconType])
      }
    },
    /**
     * Initialize checkbox value
     */
    initCheckGroup (data) {
      data.forEach((item) => {
        this.checkedMarkerLayerKey.push(item.poiType)
        this.markerLayerKeys.push({
          name: item.poiName,
          poiType: item.poiType
        })
      })
    },
    /**
     * Layer check
     */
    checkGroupChange (val) {
      this.rootLayerGroup.clearLayers()
      val.forEach((item) => {
        this.rootLayerGroup.addLayer(this.layersObj[item])
      })
    }
  }
}
</script>
<style scoped lang='scss'>
.map-2d {
  height: 100%;
  position: relative;
  .map2d-container {
    height: 100%;
  }
  .markerLayer-control {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    z-index: 999;
  }
}
</style>

       

Topics: Javascript Vue Vue.js html gis