Source

components/shared/geocoding/geocoding-mixin.js

import L from 'leaflet'
import colors from '@/styles/colors.js'

export const mapIcons = {
  routing_marker_end: require('./assets/routing_marker_end.svg'),
  routing_marker_step: require('./assets/routing_marker_step.svg'),
  routing_marker_start: require('./assets/routing_marker_start.svg'),
}

/**
 *
 * Geocoding map operations
 *
 * @requires simpliciti-map-mixin.js::mapClearMarkersFromLayer
 */
export default {
  computed: {
    /**
     * Returns natural geocoding provider set by client. Defaults to OSM.
     * Use along AddressAutocomplete.vue
     * @returns
     */
    userAutocompleteProviderName() {
      let table = {
        osm: 'simpliciti_v3',
        google: 'simpliciti_v3_google',
      }
      return (
        table[
          this.$store.getters['settings/getParameter'](
            'naturalGeocodingProvider'
          )
        ] || table.osm
      )
    },
  },
  methods: {
    /**
     * Will render results markers on the map (start, end and step markers).
     * @requires simpliciti-map-mixin.js::mapClearMarkersFromLayer
     */
    async addRoutingResultMarkers(markers) {
      if (markers.length > 0) {
        this.mapClearMarkersFromLayer('routingSearchMarkers')
      }
      await this.$map.getLeafletWrapperVM().drawGeometries({
        layer: 'routingResultsMarkers',
        data: markers,
        generate(item) {
          return L.marker([item.lat, item.lng], {
            icon: L.divIcon({
              className: 'routing-results-markers',
              html: `<img 
              style="position: absolute;
              left: -9px;
              bottom: 0;"
              src="${mapIcons['routing_marker_' + item.type]}" />`,
            }),
          })
        },
      })
    },
    /**
     * When the user add some addresses, we show a marker right away
     */
    async addRoutingSearchMarkers(markers) {
      this.addMultipleSimpleMarkers(markers, {
        layer: 'routingSearchMarkers',
      })
      //this.mapFitBounds(markers.map((i) => [i.lat, i.lng]));
    },
    /**
     * Will render instruction polylines on the main map
     */
    async addRoutingInstructionsPolylines(instructions) {
      await this.$map.getLeafletWrapperVM().drawPolylines(
        instructions.map((instruction) => {
          return {
            id: instruction.id || instruction.number,
            data: instruction.coordinates.map((coord) => coord.reverse()),
            styles: {
              color: colors.color_main,
            },
          }
        }),
        {
          layer: 'routingInstructionsPolylines',
        }
      )
    },
    unhightlightRoutingInstructionPolyline(number) {
      this.$map
        .getLeafletWrapperVM()
        .layerGroups.routingInstructionsPolylines.getLayers()
        .forEach((geometry) => {
          if (geometry.externalId == number && !!geometry.normalColor) {
            geometry.setStyle({
              color: geometry.normalColor,
            })
          }
        })
    },
    highlightRoutingInstructionPolyline(number) {
      this.$map
        .getLeafletWrapperVM()
        .layerGroups.routingInstructionsPolylines.getLayers()
        .forEach((geometry) => {
          if (geometry.externalId == number) {
            if (!geometry.normalColor) {
              geometry.normalColor = geometry.options.styles.color
            }
            geometry.setStyle({
              color: '#00ff00',
            })
          }
        })
    },
    /**
     * Used internally
     * @internal
     */
    async addMultipleSimpleMarkers(markers, options = {}) {
      if (options.layer) {
        if (this.mapClearMarkersFromLayer) {
          await this.mapClearMarkersFromLayer(options.layer)
        } else {
          await this.$map.getLeafletWrapperVM().drawGeometries({
            ...options,
            data: [],
          })
        }
      }
      return Promise.all(
        markers.map((m) => {
          return this.addLocateAddressMarker(
            m.lat,
            m.lng,
            m.address || m.formattedAddress || m.formatted,
            {
              preserveExistingLayers: true,
              ...options,
            }
          )
        })
      )
    },
    /**
     * Used by geocoding features: Locate address form, Locate address natural, Locate address lat/lng
     */
    async addLocateAddressMarker(
      lat,
      lng,
      formattedAddress = '',
      options = {}
    ) {
      let mapVM = await this.$map.getLeafletWrapperVM()
      if (!mapVM) {
        return console.warn('addLocateAddressMarker::No-map-VM')
      }

      await drawLocateAddressMarker(mapVM, lat, lng, formattedAddress)

      //Enable marker toggle in map options
      if (this.$map.getSimplicitiMapVM().$refs.mapOptions) {
        this.$map.getSimplicitiMapVM().$refs.mapOptions.hasLocateAddressMarker = true
      } else {
        console.warn('Cannot enable marker toogle in map options') //Use case: Zone module map options is disabled
      }
    },
  },
}

/**
 * Used by
 * - LocationAddressNatural.vue (Autocomplete)
 * - LocateAddressFeature (Form)
 * - LocateAddressLatLng (Reverse)
 *
 * @param {*} mapVm
 * @param {*} lat
 * @param {*} lng
 * @param {*} formattedAddress
 * @param {*} options
 */
export async function drawLocateAddressMarker(
  mapVm,
  lat,
  lng,
  formattedAddress = '',
  options = {}
) {
  await mapVm.drawGeometries({
    layer: 'locateAddressMarker',
    data: [
      {
        lat: lat,
        lng: lng,
      },
    ],
    generate(item) {
      const svgIcon = L.divIcon({
        html: `<svg xmlns="http://www.w3.org/2000/svg" width="16.8" height="24" viewBox="0 0 16.8 24">
<path id="map-marker_8_" data-name="map-marker(8)" d="M13.4,13.4a3,3,0,1,1,3-3,3,3,0,0,1-3,3M13.4,2A8.4,8.4,0,0,0,5,10.4C5,16.7,13.4,26,13.4,26s8.4-9.3,8.4-15.6A8.4,8.4,0,0,0,13.4,2Z" transform="translate(-5 -2)" fill="#014470"/>
</svg>`,
        className: '',
        iconSize: [16.8, 24],
        //iconAnchor: [12, 40],
      })

      //return new L.Marker([item.lat, item.lng])
      return L.marker([item.lat, item.lng], { icon: svgIcon })
    },
    popup: {
      template: `<p class="px-2" style="padding: 5px;font: normal normal normal 12px/17px Open Sans;letter-spacing: 0px;">${formattedAddress}</p>`,
    },
    popupOptions: {
      style: 'width:300px',
    },
    ...options,
  })
}