Source

mixins/map.js

import L from 'leaflet'
import Vue from 'vue'
import { getVehicleIconHTML } from '@/services/vehicle-service.js'
import { getPolylineFromLinestring } from '@/utils/map.js'
import { generateShortId } from '@/utils/crypto.js'
const R = require('ramda')

/**
 * Used by Location module (Real-time) to render real-time results in the map (Vehicle markers).
 * @param {*} item Wrapper on top of location item (main results) that includes a Leaflet icon.
 * @returns
 */
export function createMarkerFromRealtimeItem(item = {}) {
  function getChronoStatusClassName(value) {
    return (
      {
        Travail: 'working',
        Repos: 'resting',
        Conduite: 'driving',
        Dispo: 'available',
      }[value] || value
    )
  }
  let degValue = item.cap < 0 ? 360 - item.cap : item.cap

  return Object.freeze({
    latlng: [item.lat, item.lng],
    normalizedItem: item,
    item: {
      ...item.raw,
      normalizedItem: R.omit(['raw'], item),
    },
    icon: L.divIcon({
      className: 'realtime__marker',
      html: `<div class="marker__content">
                  <div>
                    <img class="marker_icon" 
                        data-api-cap="${item.cap}"
                        data-computed-degrees="${degValue}"
                        style="transform:translate(-50%, -50%) rotate(${
                          degValue // > 180 ? 270 : 90
                        }deg)" 
                        src="./lib/realtimeMap/assets/picto_pins/Pin.svg">
                    ${getVehicleIconHTML(item.vehicleCategoryClassName, {
                      flipHorizontally: degValue > 180,
                    })}
                    <img class="marker__contact_icon" 
                      style="background-color:${item.vehicleStatusColor}"
                      src="./lib/realtimeMap/assets/picto_status/Contact.svg" />
          
                    ${
                      item.driverChronoEnabled
                        ? `
                    <div 
                      class="marker__chrono_icon ${getChronoStatusClassName(
                        item.driverChornoStatusOriginal
                      )}" 
                    ></div>
                    `
                        : ``
                    }
  
                  </div>
                  <p class="marker__label">
                    ${item.vehicleName}
                  </p >
                </div>
                `,
    }),
  })
}

/**
 * Wrapper for Leaflet polyline (Array of LatLng)
 *
 * @param {*} item
 * @param {*} singleLinestring
 * @param {*} options
 * @returns
 */
export function createSinglePolylineEntity(
  item,
  singleLinestring = '',
  options = {}
) {
  return {
    id: item.id || generateShortId('id_'),
    ...(item.number ? { stepNumber: item.number } : {}),
    smoothFactor: 0.5,
    weight: parseInt(process.env.VUE_APP_LOCATION_MAP_POLYLINE_WEIGHT) || 5,
    type: item.type || options.type || 'trip_history', //trip_history, circuit_execution (will draw arrows)
    polyline: getPolylineFromLinestring(singleLinestring),
    color: item.color || options.color || '#0b72b5', //couleur
  }
}

/**
 * Used by:
 * Location - Real-time - Circuit
 * Location - Circuit tab
 * Location - History tab
 * Diagnostics
 * Converts Array of items containing a linestring property (APV2 format) into an array of polylines (Format accepted by LeafletMap wrapper)
 * The linestring property can be either an string or an array (multiple linestrings) (#31781)
 * @param {String} linestrings Array of LatLng I.g: "lat1 lng1, lat2 lng2"
 * @returns
 */
export function linestringsToPolylines(array, options = {}) {
  let polylineEntities = []

  array.forEach((item) => {
    let singleLinestringOrArray = item[options.key || 'linestring'] || ''

    if (singleLinestringOrArray instanceof Array) {
      singleLinestringOrArray.forEach((singleLinestring) => {
        polylineEntities.push(
          createSinglePolylineEntity(
            item,
            singleLinestring.linestring !== undefined
              ? singleLinestring.linestring
              : singleLinestring,
            {
              ...options,
              color: singleLinestring.color || options.color || null,
            }
          )
        )
      })
    } else {
      let singleLinestring = singleLinestringOrArray
      polylineEntities.push(
        createSinglePolylineEntity(item, singleLinestring, options)
      )
    }
  })

  return polylineEntities
    .filter((item) => item.polyline.length !== 0)
    .map((item) => {
      if (options.transform) {
        item = options.transform(item)
      }
      return item
    })
}

export default {
  methods: {
    /**
     * Used by Location circuit tab
     * Used by Reference circuit feature
     * Used by Location (main search)
     * Used by Location history tab
     */
    linestringsToPolylines,
    /**
     * Used by Location module
     * Used by NearbyVehicles feature
     */
    createMarkerFromRealtimeItem,
    /**
     * Used by Leaflet wrapper to generate popups using VueJS components.
     * @param {*} geometry
     * @param {*} componentDefinitionOrPromise
     * @param {*} options
     */
    bindLeafletPopupComponent(
      geometry,
      componentDefinitionOrPromise,
      options = {}
    ) {
      let id = generateShortId('popup_')
      geometry.bindPopup(`<div id="${id}" style="${options.style || ''}">
      </div>`)

      let instance
      geometry.on('popupclose', () => {
        instance && instance.$destroy()
      })
      geometry.on('popupopen', () => {
        const componentDefinition =
          typeof componentDefinitionOrPromise !== 'object'
            ? {
                name: 'LeafletPopupWrapper',
                components: {
                  Popup: componentDefinitionOrPromise,
                },
                template: `<Popup :geometry="geometry" />`,
                computed: {
                  geometry() {
                    return geometry
                  },
                },
              }
            : componentDefinitionOrPromise
        const VueComponentClass = Vue.extend(componentDefinition)
        instance = new VueComponentClass({
          parent: options.parent || null,
        })
        instance.$mount()
        const popupWrapper = document.querySelector(`#${id}`)
        if (popupWrapper) {
          popupWrapper.appendChild(instance.$el)
        } else {
          Vue.$log.warn(
            `bindLeafletPopupComponent::Couldn't find the popup wrapper #${id}`
          )
        }
      })
    },
  },
}