Source

components/shared/SimplicitiMap/draw-zones-mixin.js

import { mapGetters } from 'vuex'

const shouldEnableClustering = (zoomLevel) => false //zoomLevel <= 14 //Enabling clustering at certain zoom level improves performance

export default {
  computed: {
    ...mapGetters({
      clientZones: 'zones/clientZones',
    }),
  },
  watch: {
    /**
     * Client zones can be available in any map
     * (Visible by default only if Zones module)
     */
    clientZones: {
      handler() {
        //console.log('watch::zones-dataset-change::drawLegacyZones')
        this.waitForMapRef(() => this.drawClientZones())
      },
      deep: true,
      immediate: true,
    },
    moveendTimestamp() {
      //Update markers if user pans the map only if non-clustering
      if (!shouldEnableClustering(this.zoomLevel)) {
        //console.log('watch::map-pan::drawLegacyZones')
        this.drawClientZones()
      }
    },
    zoomLevel() {
      //console.log('watch::zoomLevel::drawLegacyZones')
      this.drawClientZones()
    },
    mapOptions: {
      handler(newValue, oldValue) {
        if (newValue.zonesMarkersToggle !== oldValue.zonesMarkersToggle) {
          //console.log('watch::toggle::drawLegacyZones')
          this.drawClientZones()
        }
      },
      deep: true,
    },
  },
  methods: {
    /**
     * @function drawClientZones
     * @description Draws client zones on the map based on the current bounds. Clustering is enabled at certain zoom levels. If non-clustering, zones are filtered out if outside viewport.
     */
    drawClientZones() {
      const self = this

      if (this.clientZones.length === 0 || !this.getMap()) {
        return
      }

      if (this.isZonesMap) {
        return //Skip Generic zones if zones module (To avoid duplicated zones)
      }

      let enableClustering = shouldEnableClustering(this.zoomLevel)

      let clusteringOptions = {}
      if (enableClustering) {
        clusteringOptions = {
          clusterOptions: {
            singleMarkerMode: true,
            iconCreateFunction: function (cluster) {
              return getClusterIcon(cluster)
            },
          },
        }
        function getClusterIcon(cluster) {
          let size = 21
          size = cluster.getChildCount() > 99 ? 16 : size
          size = cluster.getChildCount() > 999 ? 12 : size
          return L.divIcon({
            className: 'cluster_marker',
            html: `<div class="marker__content">
            <div>
              <img class="marker_icon alert_marker_icon"
                  src="./lib/realtimeMap/assets/picto_pins/Pin.svg">
              <div class="alert_marker_icon_inner marker_icon_cluster_text" style="font-size:${size}px;">
                  ${cluster.getChildCount()}
              </div>
            </img>
          </div>`,
          })
        }
      }

      let visible = this.mapOptions.zonesMarkersToggle

      let data = []

      if (self.zoomLevel < 6) {
        visible = false //Do not render if zoom distance above 50km
      } else {
        if (enableClustering) {
          data = this.clientZones // Do not filter by bounds if clustering
        } else {
          // Function to filter the clientZones based on the bounds of a map instance (current viewport)
          const getFilteredZones = () => {
            let map = this.getMap()
            let mapBounds = map.getBounds()
            return this.clientZones.filter((item) =>
              mapBounds.contains(L.latLng(item.lat, item.lng))
            )
          }
          data = getFilteredZones()
        }
      }

      /*console.log('drawClientZones', {
        visible,
        enableClustering,
        dataLen: data.length,
      })*/

      this.$refs.map &&
        this.$refs.map.drawGeometries &&
        this.$refs.map.drawGeometries({
          visible,
          ...clusteringOptions,
          layer: 'clientZones',
          data: data,
          recreateLayerGroup: true,
          generate(item, { map }) {
            if (enableClustering) {
              return L.marker([item.lat, item.lng]) //Dummy marker
            }

            let color = item.categoryColor || 'green'
            let pathOptions = {
              weight: 2,
              color: '#014470',
              fill: true,
              fillOpacity: 0.8,
              fillColor: color,
            }
            let geometry =
              item.type === 'P'
                ? L.polygon(item.polygon, {
                    ...pathOptions,
                  })
                : L.circle([item.lat, item.lng], {
                    ...pathOptions,
                    radius: item.radius,
                  })

            let accessPointGeometry = L.marker(
              [item.access_lat, item.access_lng],
              {
                icon: L.divIcon({
                  className: 'zone_marker__access_point_icon',
                  html: `<svg xmlns="http: //www. W3. Org/2000/svg" width="18.385" height="18.385" viewbox="0 0 18.385 18.385" > <g class="a" transform="translate(9.192) rotate(45)" : fill="var(--color-dark-blue)" > <rect class="b" style="stroke: none" stroke="none" width="13" height="13" rx="2" /> <rect class="c" style="fill: none" fill="none" x="0.5" y="0.5" width="12" height="12" rx="1.5" /> </g> </svg>`,
                }),
              }
            )

            let textGeometry = new L.marker([item.lat, item.lng], {
              opacity: 1,
              icon: L.divIcon({
                html: `<div>
                <img
                src="/img/zones/${item.categoryImageName}"
                title="${item.name}"
              />
                  ${
                    self.zoomLevel > 16
                      ? `<div><span>${item.name}</span></div>`
                      : ''
                  }
                  </div>
                  `,
                iconAnchor: [16, 2],
                className: 'zone_marker__text_icon',
              }),
            })

            let layers = [geometry]
            if (self.zoomLevel > 14) {
              layers.push(textGeometry, accessPointGeometry)
            }
            return layers
          },
        })
    },
  },
}