import Vue from 'vue'
import colors from '@/styles/colors.js'
const torCodes = [
'TOR1',
'TOR2',
'TOR3',
'TOR4',
'TOR5',
'TOR6',
'TOR7',
'TOR8',
'TOR+',
]
export default {
inject: {
isTripHistoryTableMap: {
default: false,
},
enableRenderVehiclePositionsMarkers: {
default: false,
},
isCircuitMap: {
default: false,
},
},
computed: {
/**
* @todo Remove isTripHistoryTableMap
*/
showPositionMarkersByDefault() {
return (
this.isCircuitMap ||
this.isTripHistoryTableMap ||
this.enableRenderVehiclePositionsMarkers
)
},
},
watch: {
/**
* Used by:
* Location - Real-time by any - Last trip history
* Location - History by Vehicle/Driver - Main search (details)
*/
vehiclePositionMarkers: {
handler() {
this.onPositionsChange(this.mapOptions.positions)
},
deep: true,
immediate: true,
},
},
methods: {
/**
* Will be trigered any time positions data change or positions toggle button is pressed
*/
onPositionsChange(isPositionsLayerToggleButtonChecked) {
if (!this.isLocationMainSearch) {
this.drawPositionsMarkers({
visible: isPositionsLayerToggleButtonChecked, //Ignored?
})
this.waitForMapRef(this.drawSensorMarkers)
}
},
/**
* Draw sensor markers when user toggle layers
*/
onSensorLayerToggleChange() {
if (!(this.sensorsConfig && this.sensorsConfig.sensors)) {
return
}
this.waitForMapRef(() => {
//TOR 1..8 layers (bind to each button: i.g Tor1 enables Tor1 layers)
this.sensorsConfig.sensors
.filter((item) => item.code !== 'TOR+')
.forEach((configItem) => {
this.toggleMapLayers({
layerName: `positions_${configItem.code}`, //i.g positions_TOR5
enabled: configItem.showMarkers,
})
this.toggleMapLayers({
layerName: `positions_multiple_tors_${configItem.code.toLowerCase()}`,
enabled: configItem.showMarkers,
})
})
//TOR+ layers
const enableMultipleTors = (
this.sensorsConfig.sensors.find((item) => item.code === 'TOR+') || {
showMarkers: false,
}
).showMarkers
torCodes
.filter((c) => c !== 'TOR+')
.forEach((code) => {
this.toggleMapLayers({
layerName: `positions_multiple_tors_${code.toLowerCase()}`,
enabled: enableMultipleTors,
})
})
/*
Re initializing leaflet layers is hardware intensive
this.drawSensorMarkers({
ignoreVisibilityByDefault: true,
})
*/
})
},
/**
* Draw position markers on the map
* - Waits until map ref is available
* - Filters only common positions (without sensor data)
*/
drawPositionsMarkers(options = {}) {
this.$nextTick(() => {
this.waitForMapRef(() => {
drawPositionsMarkersFromData.apply(this, [
this.vehiclePositionMarkers.filter(
(i) => !i.code || i.code === 'POS'
),
{
...options,
//Hot-fix: Removed due to invalid position in some clients
//after: ({ map, geometries }) =>
//map.fitBounds(geometries.map((g) => g.getLatLng())),
},
])
})
})
},
/**
* Draw positions with sensor data using dataset from store
*
* Markers will be visible by default if each marker type has showMarkers equals true
* Markers will not be visible if computed showPositionMarkersByDefault equals false
* showPositionMakrersByDefault has no effect if ignoreVisibilityByDefault equals true
*/
drawSensorMarkers(options = {}) {
const getSensorConfig = (code) =>
(this.sensorsConfig.sensors || []).find((i) => i.code === code) || null
const shouldRenderMarkersFromType = (config) =>
options.ignoreVisibilityByDefault
? config.showMarkers
: this.showPositionMarkersByDefault
? config.showMarkers
: false
let configs = {}
torCodes.forEach((code) => (configs[code] = getSensorConfig(code)))
torCodes.forEach((code) => {
let sensorConfig = configs[code]
//Clear previous colored gps positions
drawSensorMarkersFromData.apply(this, [
[],
{
name: `multiple_tors_${code}`.toLowerCase(),
},
])
drawSensorMarkersFromData.apply(this, [
[],
{
name: code,
},
])
if (!sensorConfig) {
return
}
let filteredItems = this.vehiclePositionMarkers.filter(
(i) => i.code === code
)
//Tor 1..8 also contains Tor+ positions containing Tor 1..8 sensors
filteredItems = filteredItems.concat(
this.vehiclePositionMarkers.filter(
(p) =>
p.code === 'TOR+' &&
!!p.code_capteurs.find((torCode) => torCode == code)
)
)
if (code === 'TOR+') {
//Multiple activations of TORs will create a marker per valid TOR
let multipleSensors = {}
filteredItems.forEach((item) => {
item.code_capteurs.forEach((torCode) => {
if (configs[torCode]) {
multipleSensors[torCode] = multipleSensors[torCode] || []
multipleSensors[torCode].push(item)
}
})
})
Object.keys(multipleSensors).forEach((torCode) => {
drawSensorMarkersFromData.apply(this, [
multipleSensors[torCode],
{
name: `multiple_tors_${torCode}`.toLowerCase(),
//Color will be the color from TOR+ (Black)
color: configs[code].color,
//i.g: TOR1 will be visible if TOR1 layer is enabled or if TOR+ layer is enabled
visible: shouldRenderMarkersFromType(configs[torCode]), //|| shouldRenderMarkersFromType(configs["TOR+"]),
},
])
})
} else {
//Normal TORs (1,2,3,4,5,6,7,8) goes here
drawSensorMarkersFromData.apply(this, [
filteredItems,
{
name: code,
color: sensorConfig.color,
visible: shouldRenderMarkersFromType(sensorConfig),
},
])
}
})
},
},
}
function getDrawGeometriesPopupOptions(options = {}) {
return {
popupOptions: {
style: 'min-width:267px;',
},
popup:
options.popup ||
(() =>
/* webpackChunkName "shared_components" */
import('./PositionMarkerPopup.vue')),
}
}
function getPositionsClusterIcon(cluster, options = {}) {
let style = `${
options.backgroundColor
? 'background: ' + options.backgroundColor + ';'
: ''
}${options.color ? 'color: ' + options.color + ';' : ''}${
options.borderColor ? 'border: 2px solid ' + options.borderColor + ';' : ''
}`
return L.divIcon({
className: 'cluster_marker',
html: `<div class="cluster_position_marker" style="${style}">${cluster.getChildCount()}</div>`,
})
}
/**
* Border color: same as trip history polyline if available
*
*/
function getPositionBorderColor() {
let color = colors.color_main
let singlePolyline =
(this.$store.getters['location_module/selectedItem'] || {})
?.tripHistoryPolyline || {}
if (singlePolyline instanceof Array) {
singlePolyline = singlePolyline[0]
}
if (singlePolyline.color) {
color = singlePolyline.color
}
return color
}
/**
* Draw common position markers (without sensor data)
* Border: Same as trip history
* Fill: #cccccc (Same as V2)
*/
function drawPositionsMarkersFromData(positions = [], options = {}) {
let color = getPositionBorderColor.apply(this)
positions = positions.filter(validPositionsFilter).map((pp) => {
let p = { ...pp }
p.lat = p.lat || p.latitude || p.latitude_mapmatch
p.lng = p.lng || p.lon || p.longitude || p.longitude_mapmatch
p.radius = 3
p.color = color
p.fillColor = '#cccccc'
p.weight = 2
return p
})
let visible = this.showPositionMarkersByDefault
//Update visible if layer is toggle off in map options
if (!this.mapOptions.positions) {
visible = false
}
this.$refs.map.drawCircles(positions, {
...options,
/*clusterOptions: {
iconCreateFunction: function (cluster) {
return getPositionsClusterIcon(cluster, {
borderColor: color,
});
},
},*/
layer: options.layer || 'positions',
zIndex: options.zIndex || 5,
type: 'positions',
visible,
...getDrawGeometriesPopupOptions(options),
after() {
options.after && options.after.apply(this, arguments)
},
})
}
/**
* There might be data with invalid lat/lng, which should be ignored
* @todo Move to services/utils
* @memberof SimplicitiMapComponent
* @returns {Boolean}
*/
function validPositionsFilter(p) {
return (
(!!p.lat || !!p.latitude_mapmatch) &&
(!!p.lng || !!p.lon || !!p.longitude_mapmatch)
)
}
/**
* Draw sensor markers (positions with sensor data) using LeafletMap::drawGeometries
* Border: Trip history polyline color
* Fill: Sensor color
*/
function drawSensorMarkersFromData(data = [], options = {}) {
let self = this
/*
if (data.length === 0) {
this.$refs.map.clearLayers &&
this.$refs.map.clearLayers(`positions_${options.name}`)
return
}*/
data = data.map((item) => {
item.lng = item.lng || item.lon
return item
})
const drawOptions = {
...options,
leafletType: 'marker',
visible: options.visible || false,
type: `positions_${options.name}`,
layer: `positions_${options.name}`,
zIndex: options.zIndex || 5,
/*clusterOptions: {
iconCreateFunction: function (cluster) {
return getPositionsClusterIcon(cluster, {
borderColor: options.color,
});
},
},*/
data,
...getDrawGeometriesPopupOptions(options),
generate(item) {
try {
const circle = L.circle([item.lat, item.lng], {
color: getPositionBorderColor.apply(self),
fillColor: options.color,
fillOpacity: 1,
radius: 3,
})
return circle
} catch (err) {
console.error({
err,
item,
})
return null
}
},
}
this.$refs.map.drawGeometries(drawOptions)
}
Source