<template lang="pug">
.map_options(:class="{unfold:!collapsed}" )
.map_options__inner(v-show="showMapOptions")
.toggle_button(@click="collapsed=!collapsed")
span {{$t('common.map.options.title')}}
em.fas.fa-chevron-up(v-show="!collapsed")
em.fas.fa-chevron-down(v-show="collapsed")
.map_options_content(v-show="showMapOptions && !collapsed")
.row.m-0.map_options_content_layout
.map_options_content__left
LinestringSelect(
v-if="isCircuitMap===false && hasSpeedPolylines"
v-model="linestringType" :showSpeedPolylinesOption="hasSpeedPolylines")
PositionsToggleButton(
v-show="showPositionsLayerToggle"
v-model="positions")
InlineToggleButton(
v-show="showTripHistoryPolylinesLayerToggle"
v-model="tripHistoryPolylines"
:text="$t('common.map.options.trip_history__label')"
)
template(v-slot:icon="")
HistoryTraceIcon(color="var(--color-dark-blue)")
ContactToggleButton(
:text="$t('location.history_tab.item.contact_on')"
:color="'var(--color-silver-tree)'"
v-show="showContactON"
v-model="contactOn")
ContactToggleButton(
:text="$t('location.history_tab.item.contact_off')"
:color="'var(--color-coral-red)'"
v-show="showContactOFF"
v-model="contactOff")
InlineToggleButton(
v-show="showCircuitPolylinesLayerToggle"
v-model="circuitPolylines"
:text="$t('common.Circuit')"
)
template(v-slot:icon="")
CircuitIcon(color="var(--color-dark-blue)")
ArrowsToggleButton(
:text="$t('map_options.trip_history_arrows')"
v-show="hasLeafletLayerGroupWithName('circuit_execution_arrows')"
v-model="arrows"
)
InlineToggleButton(
v-show="eventsMarkers.length>0"
v-model="eventsMarkersToggle"
:text="$t('common.Événements')"
)
template(v-slot:icon="")
EventsIcon(color="var(--color-sandy-brown)")
LinestringsToggleButton(
v-show="alertsMarkers.length>0"
v-model="alertsMarkersToggle"
:text="$t('common.Alertes')"
)
InlineToggleButton(
v-show="identificationBacsMarkers.length>0"
v-model="bacsMarkersToggle"
:text="$t('common.map.options.identification')"
)
template(v-slot:icon="")
IdentBacsIcon
InlineToggleButton(
v-show="shouldShowZonesToogle"
v-model="zonesMarkersToggle"
:text="$t('common.Zones')"
)
template(v-slot:icon="")
ZonesIcon(
class="mr-1"
color="var(--color-dark-blue)"
)
InlineToggleButton(
v-show="chronoMarkers.length>0"
v-model="chronoMarkersToggle"
:text="'Imputations chrono'"
)
template(v-slot:icon="")
ChronoIcon(
class="mr-1"
color="var(--color-dark-blue)"
:size="24"
)
.dynamic-section(v-for="item in $store.state.map_options.sections" :key="item.uniqueName")
component(
v-show="dynamicSectionsVisibility[item.uniqueName]"
:is="item.componentToRender" v-model="dynamicSectionsState[item.uniqueName]" :text="$t(item.i18nLabel)")
template(v-slot:icon="")
component(v-if="item.materialIcon" :is="item.materialIcon"
class="mr-1"
fillColor="var(--color-dark-blue)"
:size="24"
)
SpeedFilter(v-if="isCircuitMap===false && hasSpeedPolylines && positions===true" v-model="speedFilter" @change="speedFilterValueChange")
.map_options_content__center
SensorsConfig(v-show="!!sensorsConfig.id" :config="sensorsConfig"
@update="updateSensorConfig"
)
.map_options_content__right
ToggleButton(:value="true" @click="showAllLayers") {{$t('common.map.options.all')}}
ToggleButton(:value="false" @click="hideAllLayers") {{$t('common.map.options.none')}}
MapCircuitLegends(v-show="showCircuitActivitiesLegend")
</template>
<script>
import PositionsToggleButton from './PositionsToggleButton.vue'
import LinestringsToggleButton from './LinestringsToggleButton.vue'
import ContactToggleButton from './ContactToggleButton.vue'
import LinestringSelect from './LinestringSelect.vue'
import SensorsConfig from './SensorsConfig/SensorsConfig.vue'
import SpeedFilter from './SpeedFilter.vue'
import ToggleButton from './ToggleButton.vue'
import MapCircuitLegends from './MapCircuitLegends.vue'
import ArrowsToggleButton from '@c/location/MapOptions/ArrowsToggleButton.vue'
import Vue from 'vue'
import { mapGetters } from 'vuex'
import InlineToggleButton from '@c/location/MapOptions/InlineToggleButton.vue'
import CircuitIcon from '@c/shared/icons/CircuitIcon.vue'
import HistoryTraceIcon from '@c/shared/icons/HistoryTraceIcon.vue'
import ZonesIcon from '@c/shared/icons/ZonesIcon.vue'
import EventsIcon from '@c/shared/icons/EventsIcon.vue'
import IdentBacsIcon from '@c/shared/icons/IdentBacsIcon.vue'
import ChronoIcon from '@c/location/LocationChrono/assets/ChronoIcon.vue'
import MapMarkerIcon from 'vue-material-design-icons/MapMarker.vue'
import { removeNativeTooltipFromMaterialIconsMixin } from '@/mixins/icons-mixin.js'
/**
* @typedef {Object} dynamicToggleControlSectionsMixin
* @description
* Dynamic toggle control sections allow us to define toggle controls once.
* Each toggle control will automatically show/hide itself and show/hide related leaflet layers.
* @todo Refactor existing layers toggles (i.g zone) into a dynamic section
* Note: Add extra sections in the related vuex store "map_options/index.js"
*/
const dynamicToggleControlSectionsMixin = {
data() {
return {
dynamicSectionsState: {},
dynamicSectionsVisibility: {},
}
},
watch: {
/**
* React to manual/auto toggle
*/
dynamicSectionsState: {
handler() {
Object.keys(this.dynamicSectionsState).forEach((key) => {
this.updateDynamicSectionRelatedLeafletLayersGroupsVisibility(
key,
this.dynamicSectionsState[key]
)
})
},
deep: true,
},
},
methods: {
/**
* Toggle all on/off support
*/
toggleDynamicSectionsControls(areEnabled) {
Object.keys(this.dynamicSectionsState).forEach((key) => {
this.dynamicSectionsState[key] = areEnabled
})
},
/**
* @example
* i.g Routing results (geocoding_routing_instructions) will toggle to layers: start/end markers and result polyline.
*/
updateDynamicSectionRelatedLeafletLayersGroupsVisibility(
uniqueName,
isEnabled
) {
let section = this.$store.state.map_options.sections.find(
(s) => s.uniqueName == uniqueName
)
if (section.willToggleLeafletMapLayerGroups) {
section.willToggleLeafletMapLayerGroups.forEach((layerGroupName) => {
this.toggleLayer(layerGroupName, isEnabled)
})
}
},
/**
* Workaround to keep the toggle buttons visibility in sync with the layer groups available in leaflet
* (Only for showRule "layerGroupExists" and sections with "willToggleLeafletMapLayerGroups" supplied)
*/
bindCheckDynamicSectionsVisibilityInterval() {
if (this._checkDynamicSectionsVisibilityInterval) {
this.unbindCheckDynamicSectionsVisibilityInterval()
}
this._checkDynamicSectionsVisibilityInterval = setInterval(() => {
return this.$store.state.map_options.sections.forEach((section) => {
let isDynamicSectionVisible = false
if (
section.showRule === 'layerGroupExists' &&
!!section.willToggleLeafletMapLayerGroups.find((n) =>
this.hasLeafletLayerGroupWithName(n)
)
) {
isDynamicSectionVisible = true
}
this.$set(
this.dynamicSectionsVisibility,
section.uniqueName,
isDynamicSectionVisible
)
})
}, 2000)
},
unbindCheckDynamicSectionsVisibilityInterval() {
clearInterval(this._checkDynamicSectionsVisibilityInterval)
this._checkDynamicSectionsVisibilityInterval = null
},
/**
* Dynamic state need to be set with this.$set / Vue.$set
*/
initializeDynamicSectionsState() {
this.$store.state.map_options.sections.forEach((section) => {
if (
typeof this.dynamicSectionsState[section.uniqueName] === 'undefined'
) {
const initialValue =
section.initialValue !== undefined ? section.initialValue : false
this.$set(this.dynamicSectionsState, section.uniqueName, initialValue)
}
})
},
},
}
/**
* @vue-event {Number} toggleAllLayers - The user has click Show All/None buttons
*/
export default {
components: {
PositionsToggleButton,
LinestringsToggleButton,
ContactToggleButton,
LinestringSelect,
SensorsConfig,
SpeedFilter,
ToggleButton,
MapCircuitLegends,
ArrowsToggleButton,
InlineToggleButton,
CircuitIcon,
HistoryTraceIcon,
ZonesIcon,
EventsIcon,
IdentBacsIcon,
ChronoIcon,
MapMarkerIcon,
},
mixins: [
dynamicToggleControlSectionsMixin,
removeNativeTooltipFromMaterialIconsMixin,
],
componentType: 'container',
inject: {
simplicitiMapName: {
default: '',
},
isTripHistoryTableMap: {
default: false,
},
isLocationMainSearch: {
default: false,
},
isCircuitMap: {
default: false,
},
isEventsMap: {
default: false,
},
isAlertsMap: {
default: false,
},
isIdentificationBacsMap: {
default: false,
},
isZonesMap: {
default: false,
},
isChronoMap: {
default: false,
},
showGPSPositionMarkersWhenAvailable: {
default: () => ({}),
},
},
props: {
/**
* One way binding (toggle values are exposed to parent, i.g: {positions:false} )
*/
value: {
type: Object,
default: () => ({}),
},
initialContactCheckboxesValue: {
type: Boolean,
default: false,
},
initialSensorsVisibilityValue: {
type: Boolean,
default: true,
},
},
data() {
return {
locateAddressMarkerToggle: true,
chronoMarkersToggle: this.isChronoMap,
eventsMarkersToggle: this.isEventsMap,
alertsMarkersToggle: this.isAlertsMap,
bacsMarkersToggle: this.isIdentificationBacsMap,
zonesMarkersToggle: false,
collapsed: true,
positions: this.isTripHistoryTableMap || this.isCircuitMap,
circuitPolylines: !this.isLocationMainSearch && this.isCircuitMap,
tripHistoryPolylines: !this.isLocationMainSearch && !this.isCircuitMap,
contactOff: this.initialContactCheckboxesValue,
contactOn: this.initialContactCheckboxesValue,
linestringType: 'normal',
speedFilter: {
value: '',
},
alerts: false,
arrows: false,
hasLocateAddressMarker: false,
}
},
computed: {
...mapGetters({
vehiclePositionMarkers: 'simpliciti_map/vehiclePositionMarkers',
singleCircuitExecPolylines: 'simpliciti_map/singleCircuitExecPolylines',
singleTripHistoryPolylines: 'simpliciti_map/singleTripHistoryPolylines',
sensorsConfig: 'map_options/sensorsConfig',
speedPolylines: 'simpliciti_map/speedPolylines',
eventsMarkers: 'simpliciti_map/eventsMarkers',
alertsMarkers: 'simpliciti_map/alertsMarkers',
identificationBacsMarkers: 'simpliciti_map/identificationBacsMarkers',
zonesMarkers: 'zones/clientZones',
chronoMarkers: 'simpliciti_map/chronoMarkers',
}),
/**
* Disable zones toogle (Generic zones on any map) if current module is zones (To avoid duplicated zones)
*/
shouldShowZonesToogle() {
return this.zonesMarkers.length > 0 && !this.isZonesMap
},
/**
* Show only if there is any geometry to toggle on/off
*/
showMapOptions() {
//Trip history positions speed filter
if (this.isCircuitMap === false && this.hasSpeedPolylines) {
return true
}
//Positions
if (this.showPositionsLayerToggle) {
return true
}
//Trip history polylines
if (this.showTripHistoryPolylinesLayerToggle) {
return true
}
//Trip history contact on/off markers
if (this.showContactON || this.showContactOFF) {
return true
}
//Circuit polylines
if (this.showCircuitPolylinesLayerToggle) {
return true
}
//Events
if (this.eventsMarkers.length > 0) {
return true
}
//Alerts
if (this.alertsMarkers.length > 0) {
return true
}
//Bacs
if (this.identificationBacsMarkers.length > 0) {
return true
}
//Zones
if (this.shouldShowZonesToogle) {
return true
}
//Chrono (?)
if (this.chronoMarkers.length > 0) {
return true
}
//Trip history speed polylines
if (
this.isCircuitMap === false &&
this.hasSpeedPolylines &&
this.positions === true
) {
return true
}
//Sensor config
if (this.sensorsConfig.id) {
return true
}
//Circuit legends
if (this.showCircuitActivitiesLegend) {
return true
}
//Dynamic sections
let hasDynamicSections =
Object.keys(this.dynamicSectionsVisibility).findIndex(
(k) => this.dynamicSectionsVisibility[k] === true
) !== -1
if (hasDynamicSections) {
return true
}
return false
},
showContactON() {
return (
!this.isLocationMainSearch &&
this.$store.getters['simpliciti_map/hasTripStepDataOfType'](
'contact_on'
)
)
},
showContactOFF() {
return (
!this.isLocationMainSearch &&
this.$store.getters['simpliciti_map/hasTripStepDataOfType'](
'contact_off'
)
)
},
showCircuitActivitiesLegend() {
return (
(
this.$store.getters['location_module/circuitExecutionSteps']
.troncons || []
).length > 0
)
},
showPositionsLayerToggle() {
return this.vehiclePositionMarkers.length > 0
},
showTripHistoryPolylinesLayerToggle() {
return this.singleTripHistoryPolylines.length > 0
},
showCircuitPolylinesLayerToggle() {
return this.singleCircuitExecPolylines.length > 0
},
hasSpeedPolylines() {
return this.speedPolylines.length > 0
},
sensorsConfig() {
return this.$store.getters['map_options/sensorsConfig']
},
hasArrows() {
return (
this.$store.getters['simpliciti_map/circuitExecutionsPolylines']
.length > 0
)
},
hideTripHistoryPolylinesIfCircuitTab() {
return this.$store.state.location_module
.hideTripHistoryPolylinesIfCircuitTab
},
},
watch: {
hideTripHistoryPolylinesIfCircuitTab() {
if (
this.isCircuitMap &&
this.hideTripHistoryPolylinesIfCircuitTab === false
) {
this.tripHistoryPolylines = true
}
},
showGPSPositionMarkersWhenAvailable() {
this.positions = this.showGPSPositionMarkersWhenAvailable.value
},
contactOn() {
this.toggleLayer('trip_steps_contact_on', this.contactOn)
},
contactOff() {
this.toggleLayer('trip_steps_contact_off', this.contactOff)
},
positions: {
handler() {
//this.$emit("positions", this.positions);
this.toggleLayer('positions', this.positions)
},
immediate: true,
},
tripHistoryPolylines() {
this.updateTripHistoryPolylinesType()
},
circuitPolylines() {
this.toggleLayer('circuitPolylines', this.circuitPolylines)
},
linestringType() {
this.tripHistoryPolylines = true
this.updateTripHistoryPolylinesType()
},
locateAddressMarkerToggle() {
this.toggleLayer('locateAddressMarker', this.locateAddressMarkerToggle)
},
chronoMarkersToggle() {
this.toggleLayer('vehicle_chrono_messages', this.chronoMarkersToggle)
},
eventsMarkersToggle() {
this.toggleLayer('vehicle_events', this.eventsMarkersToggle)
},
alertsMarkersToggle() {
this.toggleLayer('vehicle_alerts_messages', this.alertsMarkersToggle)
},
bacsMarkersToggle() {
this.toggleLayer('bacs_markers', this.bacsMarkersToggle)
},
zonesMarkersToggle() {
if (this.zonesMarkersToggle) {
this.toggleLayer('clientZones', this.zonesMarkersToggle)
} else {
this.toggleLayer('clientZones', this.zonesMarkersToggle)
}
this.$emit('zonesMarkersToggle', this.zonesMarkersToggle)
},
arrows() {
this.toggleLayer('circuit_execution_arrows', this.arrows)
},
hasArrows() {
this.arrows = this.hasArrows
},
},
created() {
this.initializeDynamicSectionsState()
},
mounted() {
if (this.initialSensorsVisibilityValue === false) {
this.$store.dispatch('map_options/toggleSensorsConfigVisibility', false)
}
this.$watch(
'$data',
() => {
let payload = Object.keys(this.$data)
.filter((k) => !['collapsed'].includes(k))
.reduce((a, v) => {
a[v] = this.$data[v]
return a
}, {})
this.$emit('input', payload)
},
{
deep: true,
}
)
this.bindCheckDynamicSectionsVisibilityInterval()
},
destroyed() {
this.unbindCheckDynamicSectionsVisibilityInterval()
},
methods: {
/**
* Based on "tripHistoryPolylines", the polyline will be normal (blue), speed (colored based on speed) or hidden.
*/
updateTripHistoryPolylinesType() {
if (this.tripHistoryPolylines) {
this.toggleLayer(
'tripHistoryPolylines',
this.linestringType === 'normal'
)
this.toggleLayer('speedPolylines', this.linestringType === 'speed')
} else {
this.toggleLayer('tripHistoryPolylines', false)
this.toggleLayer('speedPolylines', false)
}
},
/**
* Toggles flag "showMarkers" for a single sensor configuration
* Used when user toggles a single sensor layer
*/
updateSensorConfig({ sensorName, payload }) {
this.$store.dispatch('map_options/updateSensor', { sensorName, payload })
this.$emit('sensors')
},
/**
* Toggles flag "showMarkers" for all sensor configurations
* Used when user toggles all map layers at once
*/
toggleSensorsMarkers(value) {
if (this.sensorsConfig && !!this.sensorsConfig.sensors) {
this.$store.dispatch(
'map_options/updateSensors',
this.sensorsConfig.sensors.map((configItem) => {
return {
code: configItem.code,
payload: {
showMarkers: value,
},
}
})
)
}
this.$emit('sensors')
},
/**
* Used when user toggles all map layers at once
*/
toggleLayers(value) {
this.toggleSensorsMarkers(value)
//Remove speedFilter
if (!value) {
this.speedFilter.value = ''
this.$store.dispatch('map_options/setFilter', {
name: 'speedFilter',
condition: this.speedFilter.condition,
value: '',
})
}
//Toggle all the $data boolean properties
Object.keys(this.$data)
.filter((k) => !['collapsed'].includes(k))
.forEach((key) => {
if (typeof this.$data[key] === 'boolean') {
this.$data[key] = value
}
})
this.toggleDynamicSectionsControls(value)
//SimplicitiMap will toggle Leaflet layers
this.$emit('toggleAllLayers', value)
},
showAllLayers() {
this.toggleLayers(true)
},
hideAllLayers() {
this.toggleLayers(false)
},
speedFilterValueChange() {
this.$store.dispatch('map_options/setFilter', {
name: 'speedFilter',
condition: this.speedFilter.condition,
value: parseInt(this.speedFilter.value),
})
},
/**
* Toggle a layer group in LeafletMap component
* @todo Refactor: Improve communication with LeafletMap
*/
toggleLayer(layerName, enabled, extraOptions = {}) {
this.$emit('toggleLayer', { layerName, enabled, ...extraOptions })
},
/**
* @todo Refactor: Improve communication with LeafletMap (Remove $parent)
*/
hasLeafletLayerGroupWithName(layerName) {
return (
this.$parent.getLeafletMapWrapper() &&
this.$parent.getLeafletMapWrapper().layerGroups &&
this.$parent.getLeafletMapWrapper().layerGroups[layerName] &&
this.$parent.getLeafletMapWrapper().layerGroups[layerName].getLayers()
.length > 0
)
},
},
}
</script>
<style lang="scss" scoped>
.map_options {
width: 100%;
background: white;
position: relative;
}
.map_options.unfold {
z-index: 9999;
}
.map_options__inner {
margin: 5px 15px;
}
.map_options_content {
position: absolute;
height: fit-content;
width: 100%;
z-index: 99999;
left: 0px;
background: white;
padding: 10px 15px;
display: flex;
flex-direction: column;
row-gap: 10px;
& .map_options_content_layout {
display: flex;
column-gap: 20px;
justify-content: space-between;
& .map_options_content__left,
& .map_options_content__center,
& .map_options_content__right {
display: flex;
flex-wrap: wrap;
row-gap: 3px;
column-gap: 10px;
flex-direction: column;
width: fit-content;
}
& .map_options_content__center {
flex-basis: calc(60%);
}
& .map_options_content__right {
justify-content: flex-end;
}
}
}
.toggle_button {
user-select: none;
cursor: pointer;
font-size: 14px;
}
</style>
Source