<template lang="pug">
//portal(to="MapToolboxPortalTarget")
.map-toolbox(ref="root" v-show="isVisible" :style="rootStyle" :data-id="_uid")
.map-toolbox-content
.map-toolbox-options(v-show="!isCollapsed")
.map-toolbox-option(
v-if="hasAccessRightToMapPredefinedViews"
@click="onFeatureLinkClick('predefined_views')",
:class="{ 'mto-selected': selectedItem === 'predefined_views' }"
v-b-tooltip.hover.viewport,
:title="$t('geocoding.tool_title.predefined_views')"
)
Icon(icon="carbon:zoom-area" :style="{fontSize:toolbarIconSize}"
:color="selectedItem === 'predefined_views' ? 'white' : colors.color_main")
.map-toolbox-option(
@click="onFeatureLinkClick('forward')",
:class="{ 'mto-selected': selectedItem === 'forward' }"
v-b-tooltip.hover.viewport
:title="$t('geocoding.tool_title.locate_address')"
)
GeocodingForwardFormIcon(
:fillColor="selectedItem === 'forward' ? 'white' : colors.color_main",
:size="toolbarIconSize"
)
.map-toolbox-option(
@click="onFeatureLinkClick('forwardNatural')",
:class="{ 'mto-selected': selectedItem === 'forwardNatural' }"
v-b-tooltip.hover.viewport,
:title="$t('geocoding.tool_title.locate_address_natural')",
)
GeocodingForwardNaturalIcon(
:fillColor="selectedItem === 'forwardNatural' ? 'white' : colors.color_main",
:size="toolbarIconSize"
)
.map-toolbox-option(
@click="onFeatureLinkClick('reverse')",
:class="{ 'mto-selected': selectedItem === 'reverse' }"
v-b-tooltip.hover.viewport,
:title="$t('geocoding.tool_title.locate_address_latlng')",
)
GeocodingReverseIcon(
:fillColor="selectedItem === 'reverse' ? 'white' : colors.color_main",
:size="toolbarIconSize"
)
.map-toolbox-option(
@click="onFeatureLinkClick('routing')",
:class="{ 'mto-selected': selectedItem === 'routing' }"
v-b-tooltip.hover.viewport,
:title="$t('geocoding.tool_title.routing')"
)
GeocodingRoutingIcon(
:fillColor="selectedItem === 'routing' ? 'white' : colors.color_main",
:size="toolbarIconSize"
aria-label=""
title=""
)
.map-toolbox-option(
@click="onFeatureLinkClick('circuit_reference')",
:class="{ 'mto-selected': selectedItem === 'circuit_reference' }"
v-b-tooltip.hover.viewport,
:title="$t('reference_circuit.title')"
)
RoadIcon(
:fillColor="selectedItem === 'circuit_reference' ? 'white' : colors.color_main",
:size="toolbarIconSize"
aria-label=""
title=""
)
MapToolboxContent(
v-if="!!selectedItem",
v-show="!isCollapsed",
:selectedItem="selectedItem"
)
.map-toolbox-toggle-wrapper
.map-toolbox-toggle-button(@click="onPanelClick"
v-b-tooltip.hover.viewport,
:title="$t('common.map_toolbox.toggle_button_tooltip')"
)
span.iconify(
data-icon="mdi:toolbox-outline",
data-inline="false",
:style="`color:${colors.color_main}`",
data-width="25",
data-height="25"
)
</template>
<script>
import GeocodingForwardFormIcon from 'vue-material-design-icons/HomeMapMarker.vue'
import GeocodingForwardNaturalIcon from 'vue-material-design-icons/MapMarker.vue'
import GeocodingReverseIcon from 'vue-material-design-icons/Compass.vue'
import GeocodingRoutingIcon from 'vue-material-design-icons/MapMarkerPath.vue'
import { Icon } from '@iconify/vue2'
import RoadIcon from 'vue-material-design-icons/Road.vue'
import MapToolboxContent from '@c/shared/MapToolbox/MapToolboxContent.vue'
import colors from '@/styles/colors'
import { isUnitTest } from '@/utils/unit.js'
import { removeNativeTooltipFromMaterialIconsMixin } from '@/mixins/icons-mixin.js'
import { useMouseInOutDelay } from '@/composables/mouse.ts'
import { ref, watch, computed, watchEffect } from 'vue'
import { useElementStyle } from '@vueuse/motion'
import { layoutStaticContext } from '@/components/shared/TLayout/TLayout.vue'
import { useRightsPlugin } from '@/mixins/rights-mixin.js'
import { useMapContextMenu } from '@/components/shared/SimplicitiMap/MapContextMenu.vue'
const { menuContextSelectedOption } = useMapContextMenu()
const { bindMouseInOutDelay, unbindMouseInOutDelay } = useMouseInOutDelay()
const zIndex = ref(1000000)
const { hasFeatureRight, rightsTable } = useRightsPlugin()
/**
*
* This was added to prevent the map toolbox from overlapping on top of other components (because of his position being absolute).
*
* Faq: This map toolbox is associated to the map, why is being present when the map is hidden? Because this component is wrapped in a portal (portal-vue)
*
* Used by Location (Full table mode)
* Used by Routing (Full table mode)
*
* Svelte module context patron: https://svelte.dev/tutorial/module-exports
*/
export function setLowerMapToolboxZIndex() {
console.log('setLowerMapToolboxZIndex')
zIndex.value = 100000
}
/**
* Svelte module context patron: https://svelte.dev/tutorial/module-exports
*/
export function setHigherMapToolboxZIndex() {
console.log('setHigherMapToolboxZIndex')
zIndex.value = 1000000
}
let createExitMixin = () => {}
if (!isUnitTest()) {
createExitMixin = require('@/mixins/exit-mixin.ts').default
}
export const MapToolboxIsolatedConfig = [
'MapToolbox',
async () => ({
name: 'MapToolboxIsolated',
components: {
SimplicitiMap,
//MapToolbox,
MapToolboxContent,
},
template: `<div>><MapToolbox/><MapToolboxContent/></div>`,
}),
{
props: {
//Custom props
},
beforeEnter: (to, from, next) => {
//Custom logic before routing in
return !!next && next()
},
},
]
/**
* Map toolbox in the top-right corner.
*
* Allows access to Geocoding tools and other map features such as reference circuit, missio model, last pass-by vehicles, etc.
*
* Develop in isolated mode (Will full HMR):
* http://georedv3:8082/#/components/MapToolbox?mockapp=1
*
* https://xd.adobe.com/view/00faf07a-1004-4873-89b8-45fe02de01f2-55a9/screen/41ae22cd-20f0-4c0e-adfa-d73a95171395
*/
export default {
name: 'MapToolbox',
components: {
GeocodingForwardFormIcon,
GeocodingReverseIcon,
GeocodingForwardNaturalIcon,
GeocodingRoutingIcon,
RoadIcon,
MapToolboxContent,
Icon,
},
mixins: [
createExitMixin({
attributeName: 'isCollapsed',
bindEscape: true,
}),
removeNativeTooltipFromMaterialIconsMixin,
],
provide() {
let self = this
const mapToolboxContext = {
toogleMouseInOutDelayPauseResume: () =>
self.mouseInOutDelayController.tooglePauseResume(),
setContentPanelVisible: (isVisible) => {
self.isCollapsed = !isVisible
console.log('setContentPanelVisible', {
isVisible,
isCollapsed: self.isCollapsed,
})
},
}
Object.defineProperties(mapToolboxContext, {
isMouseInOutDelayPaused: {
get() {
return self.mouseInOutDelayController.isPaused()
},
},
})
return {
mapToolboxContext,
disableDatatableSetHeightFromParent: computed(() => {
return self.isCollapsed ? true : false
}),
/**
* Prevent child maps to re-compute their size if hidden
*/
disableLeafletMapInvalidateSize: computed(() => {
return self.isCollapsed ? true : false
}),
}
},
data() {
return {
isCollapsed: true,
selectedItem: '',
rootStyleRightValue: 0.5,
}
},
computed: {
hasAccessRightToMapPredefinedViews() {
return hasFeatureRight(rightsTable.map_predefined_view_list)
},
toolbarIconSize() {
return 20
},
colors: () => colors,
/***
* 31655: We will hide the toolbox if Map+Table to avoid issues (Not enough visual space) (i.g Location module)
*/
isVisible() {
let data = layoutStaticContext.$data
if (data.isRightMenuVisible && data.isRightMenuBottomVisible) {
return false
}
return true
},
rootStyleRight() {
return `${this.rootStyleRightValue}px`
},
rootStyle() {
return `right: ${this.rootStyleRight}`
},
},
mounted() {
this.bindMouseInOutDelayInternal()
console.log('MapToolbox::mounted', this._uid)
this.bindModuleZIndexToRootStyle()
setHigherMapToolboxZIndex()
instances.value.push(this)
},
destroyed() {
instances.value.pop()
unbindMouseInOutDelay(this.$refs.root)
},
methods: {
/**
* zIndex is controlled by a global/static ref (Module context patron)
*/
bindModuleZIndexToRootStyle() {
if (!this.$refs.root) {
return setTimeout(() => this.bindModuleZIndexToRootStyle(), 250) //Wait for root ref
}
watch(
zIndex,
() => {
const { style, stop } = useElementStyle(ref(this.$refs.root))
this._rootStyle = style
style.zIndex = zIndex.value
console.log(
'bindModuleZIndexToRootStyle::' + this._uid + '::update',
zIndex.value
)
},
{
immediate: true,
}
)
},
/**
* Automatically reduce window size if mouseout for a certain time
*/
bindMouseInOutDelayInternal() {
let self = this
let el = () => this.$refs.root
let defaultRootStyleRightValue = 0.5
self.mouseInOutDelayController = bindMouseInOutDelay(el, {
delayTimeoutMilli: 1000 * 3,
onMouseIn() {
self.rootStyleRightValue = defaultRootStyleRightValue
},
onMouseOutDelay: () => {
if (!el()) {
return //Component has been destroyed
}
const shouldCollapse = self.selectedItem === 'circuit_reference'
const collapsedValue = (el().offsetWidth / 2 - 55) * -1
self.rootStyleRightValue = shouldCollapse
? collapsedValue
: defaultRootStyleRightValue
},
})
},
onPanelClick() {
this.isCollapsed = !this.isCollapsed
},
onFeatureLinkClick(name) {
this.selectedItem = name
},
},
}
const instances = ref([])
watchEffect(watchAndReactToMapMenuContextOptions)
/**
* - Will open reverse geocoding view automatically
*/
function watchAndReactToMapMenuContextOptions() {
let vm =
instances.value.length > 0
? instances.value[instances.value.length - 1]
: null
if (vm) {
if (menuContextSelectedOption.value === 'nearbyVehicles') {
openMapToolboxFeature('reverse')
}
}
}
/**
* Used internally to open reverse geocoding view if map menu context option "nearby vehicles" is clicked
* @param {*} featureName
*/
function openMapToolboxFeature(featureName) {
let vm = instances.value[instances.value.length - 1]
vm.isCollapsed = false //Open toolbox programatically
vm.onFeatureLinkClick(featureName)
}
/**
* @warn unused
*/
export function useMapToolbox() {
return {
openMapToolboxFeature,
}
}
</script>
<style lang="scss" scoped>
.map-toolbox {
position: absolute;
top: 0px;
/*right: 5px;*/
transition: right 0.8s;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.map-toolbox-content {
min-width: 465px;
background-color: white;
border-radius: 0px 0px 10px 10px;
}
.map-toolbox-toggle-wrapper {
background: #ffffff 0% 0% no-repeat padding-box;
box-shadow: 0px 2px 3px rgb(0 0 0 / 36%);
border-radius: 0px 0px 10px 10px;
padding: 5px;
justify-content: center;
align-items: center;
flex-direction: column;
width: 94px;
}
.map-toolbox-toggle-button {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.map-toolbox-options {
display: flex;
align-items: center;
column-gap: 10px;
justify-content: space-around;
padding: 5px 0px;
}
.map-toolbox-option {
cursor: pointer;
border-radius: 50%;
padding: 5px;
width: 30px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
}
.mto-selected {
background: var(--color-main);
}
</style>
Source