import Vue from 'vue'
import mitt from '@/plugins/mitt.js'
import colors from '@/styles/colors.js'
const defaultHighlightColor = '#00ff00'
const defaultNormalColor = colors.color_main
/**
* Map singleton that holds references to active maps.
*/
const wrapper = {
defaultHighlightColor,
/**
* Refs to current loaded maps (Component instances = VM)
*/
vms: {},
/**
* @rule Should not overwrite existing refs.
* @rule Skip if no object (vm)
* @param {String} name Unique name
* @param {Object} vm Component instance (VM)
* @return {Boolean} Success
*/
registerVM(name = '', vm) {
if (['string', 'number'].includes(typeof vm)) {
console.warn('registerVM: Object required')
return false
}
//Unregister existing mainMap if destroyed
if (!!this.vms.mainMap && this.vms.mainMap._isDestroyed) {
delete this.vms.mainMap
}
if (!!this.vms.mainMap && name === 'mainMap') {
name = '' //Use case: Location - Main search - Table,Table+Map mode: Assign a differentn ame to avoid lossing ref to mainMap.
}
if (!name && !this.vms.mainMap) {
name = 'mainMap' //First map without name will be "mainMap" (i.g AlertModule's map)
}
name = name || `map${Object.keys(this.vms).length + 1}`
this.vms[name] = vm
vm.__mapName = name
return true
},
unregisterVM(vm) {
if (vm.__mapName) {
delete this.vms[vm.__mapName]
}
},
fitBounds() {
return this.getLeafletInstance().fitBounds.apply(
this.getLeafletInstance(),
Array.prototype.slice.call(arguments)
)
},
/**
* @param {String} name map name (Defaults to current map)
* @returns
*/
getLeafletInstance(name = '') {
name = name || this.getCurrentMapName()
return this.vms[name] && this.vms[name].getLeafletMapWrapper().map
},
/**
* @param {String} name map name (Defaults to current map)
* @returns
*/
getLeafletWrapperVM(name = '') {
name = name || this.getCurrentMapName()
return this.vms[name] && this.vms[name].getLeafletMapWrapper()
},
/**
* @param {String} name map name (Defaults to current map)
* @returns
*/
getSimplicitiMapBottomMenuVM(name = '') {
name = name || this.getCurrentMapName()
return this.vms[name] && this.vms[name].$refs.bottomMenu
},
/**
* @param {String} name map name (Defaults to current map)
* @returns
*/
getSimplicitiMapVM(name = '') {
name = name || this.getCurrentMapName()
return this.vms[name] && this.vms[name]
},
/*
* The current map name is mainMap or mapN if present (i.g map4 if mainMap, map1, map2, map3)
*/
getCurrentMapName(vms) {
vms = vms || this.vms
if (vms.mainMap && Object.keys(vms).length === 1) {
return 'mainMap'
} else {
let mapNumberMax = -1
Object.keys(vms)
.filter((k) => k !== 'mainMap' && k.includes('map') && k.length <= 4) //i.g map1, map2, map3
.map((k) => parseInt(k.split('map').join('')))
.forEach((mapNumber) => {
if (mapNumber > mapNumberMax) {
mapNumberMax = mapNumber
}
})
if (mapNumberMax === -1 && !!vms.mainMap) {
return 'mainMap'
}
return `map${mapNumberMax}`
}
},
/**
* @warn unused
* @param {*} groupName
* @param {*} newColor
* @param {*} options
*/
setLayersColor(groupName, newColor = defaultHighlightColor, options = {}) {
let defaultColor = options.defaultColor || defaultNormalColor
let filterHandler = options.filter || false
let layers =
this.getLeafletWrapperVM().layerGroups[groupName]?.getLayers() || []
layers = layers.map((layer) => {
if (filterHandler) {
return { layer, filtered: filterHandler(layer) }
}
return { layer, filtered: true }
})
layers.forEach(({ layer, filtered }) => {
layer.setStyle({
color: filtered ? newColor : defaultColor,
})
if (layer.arrowheads) {
layer.arrowheads({
color: filtered ? newColor : defaultColor,
})
}
})
this.getLeafletWrapperVM().map.invalidateSize()
options.after && options.after(layers)
},
/**
* Used by Location - History (List mode) (Table mode)
*
* Will add reactive property "highlightedColor" to each item related polyline.
* @param {Object} locationItem Location main search item
* @param {*} results
*/
highlightLocationItemPolylines(locationItem) {
if (!locationItem) {
throw new Error('INVALID_LOCATION_ITEM')
}
if (Object.keys(wrapper.getSimplicitiMapVM() || {}).length === 0) {
console.warn('vue-map', 'No SimplicitiMapVM found!')
return false
}
if (!locationItem.relatedPolylines) {
throw new Error('NO_RELATED_POLYLINES')
}
wrapper
.getSimplicitiMapVM()
.withLeafletMapLayerGroup('linestrings', (layerGroup) => {
//unhighlight existing
layerGroup.getLayers().forEach((layer) => {
layer.closePopup && layer.closePopup()
if (layer) {
//console.log("unhighlight", layer);
layer.options.originalColor =
layer?.options?.originalColor ||
layer?.options?.color ||
layer?.style?.color ||
layer.color ||
'darkgrey'
layer.setStyle({
color:
layer.originalColor ||
layer?.options?.originalColor ||
layer?.properties?.originalColor ||
'darkgray',
})
}
})
//highlight match
let lastMatch = null
layerGroup
.getLayers()
.filter(
(layer) =>
!!locationItem.relatedPolylines.find(
(p) => p.stepNumber == layer.options.stepNumber
)
)
.forEach((match) => {
//console.log("highlight", match);
lastMatch = match
match.closePopup && match.closePopup()
match.setStyle({
color: defaultHighlightColor,
})
})
lastMatch.openPopup && lastMatch.openPopup()
})
},
/**
* Used by Location module - Selectable polylines feature
*
* @param {String} stepNumber Used to filter geometries
*/
highlightPolylines(stepNumber) {
if (!stepNumber) {
throw new Error('INVALID_STEP_NUMBER')
}
if (Object.keys(wrapper.getSimplicitiMapVM() || {}).length === 0) {
console.warn('vue-map', 'No SimplicitiMapVM found!')
return false
}
wrapper
.getSimplicitiMapVM()
.withLeafletMapLayerGroup('linestrings', (layerGroup) => {
//unhighlight existing
layerGroup.getLayers().forEach((layer) => {
//console.log("unhighlight", layer);
layer.setStyle({
color:
layer.originalColor ||
layer?.options?.originalColor ||
layer?.properties?.originalColor ||
'darkgray',
})
})
//highlight match
layerGroup
.getLayers()
.filter((layer) => layer.options.stepNumber == stepNumber)
.forEach((match) => {
//console.log("highlight", match);
match.setStyle({
color: '#00ff00',
})
})
})
},
/**
* Used by Location module
* Location - Realtime - List/Table (main search) : Zoom on lat/lng
* Location - History - ListTable (main search): Fit Bound to related polylines
**/
zoomOnLocationItem(item) {
if (!item || !item.searchType) {
return false
}
if (item.searchType === 'realtime') {
if (!(!!item.lat && !!item.lng)) {
return false
}
mitt.emit('SIMPLICITI_MAP_FIT_TO_BOUNDS', [[item.lat, item.lng]])
} else {
if (!item.relatedPolylines) {
throw new Error('NO_RELATED_POLYLINES')
}
let bounds = item.relatedPolylines.reduce((acum, value) => {
return [...acum, value.polyline]
}, [])
if (bounds.length === 0) {
return false
}
mitt.emit('SIMPLICITI_MAP_FIT_TO_BOUNDS', bounds)
}
return true
},
}
/**
* Map singleton to that holds current maps references for access.
*/
Vue.use({
install() {
Vue.$map = Vue.prototype.$map = wrapper
},
})
export default wrapper
Source