<template>
<div class="mw-container" ref="mw-container">
<Viewer v-if="isReady" />
<Tour :prop_steps="tourSteps" @finish_tour="finishTour"/>
<Overlay />
</div>
</template>
<style>
.mw-container {
position: absolute;
overflow: hidden;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.test-responsive {
width: 100px;
background-color: #ffffff;
margin: 0 auto;
position: fixed;
top: 10px;
left: 10px;
}
</style>
<script>
// Constants
import { WidgetConstants } from './widgets/WidgetConstants.js';
import { FunctionsConstants } from '@/components/FunctionsConstants.js';
import { ElLoading } from 'element-plus';
// Utils
import { Utils } from '@/assets/js/utils/Utils.js';
import { HttpClient } from '@/assets/js/utils/HttpClient.js';
// Stores
import { envStore } from '@/stores/envStore.js';
import { authStore } from '@/stores/authStore';
import { userSettingsStore } from '@/stores/userSettingsStore';
import { contextStore } from '@/stores/contextStore';
import { termsofuseStore } from '@/stores/termsofuseStore';
import { paramsStore } from '@/stores/paramsStore';
import { componentStore } from "@/stores/componentStore";
import { mapStore } from '@/stores/mapStore';
import { layerStore } from '@/stores/layerStore';
import { toolStore } from '@/stores/toolStore';
import { styleStore } from '@/stores/styleStore';
import { panelStore } from '@/stores/panelStore';
import { searchStore } from '@/stores/searchStore';
import { projectStore } from '@/stores/projectStore';
import { MapsWidgetService } from './mapswidget.service.js';
import { ToolsConstants } from '@/components/widgets/tools/ToolsConstants.js'
// Components
import Viewer from "./map/Viewer.vue";
import Tour from '@/components/tour/Tour.vue';
import Overlay from "@/components/overlay/Overlay.vue";
// Tour
import { TourSteps } from '@/components/tour/TourSteps.js'
// Openlayers drawing condition
import {drawingCondition, finishDrawCondition} from "@/components/widgets/tools/editing/interactions/conditions"
// ---------------
// MODULES
// ---------------
let editingBcStore;
(async () => {
// Modules to load
const modules = await import('@/modules/modules.js');
// Module BC component/objects to use
editingBcStore = modules?.ModuleEditingBC?.editingBcStore;
})();
import projectService from '@/services/project.service';
import { transformExtent } from 'ol/proj';
import { ElNotification, ElMessage } from 'element-plus';
// import LocalStorage from '@/assets/js/utils/LocalStorage';
// import { DrawMeasureToolConfig } from '@/components/widgets/tools/draw-measure/DrawMeasureToolConfig.js';
let scopeApi = null;
/**
* @component
* @description Componente di mappa
*
* @vue-event mounted Raised when components has been mounted
* @vue-event map_loaded Raised when map has finished to load all its components (controls and layers)
* @vue-event drawn_geometry Raised when geometry has been drawn from "activateDrawgeometry" control (see related API)
* @vue-event drawn_geometry_clear Raised when drawn geometries drawn by "activateDrawgeometry" have been removed
* @vue-event finish_tour Raised when the presentation tour was over
* @vue-event identify_result Raised when identifying features of selected themes are passed to the component
* @vue-event new_notification Raised when a new notification is detected/added
* @vue-event change_lang Raised when the application language changes
* @vue-event search_result Raised when a result is selected from the list using the search tool
*/
export default {
/**
* Props passed to widget
* - **current_user_iam**
* User logged in IAM
*
* **current_user**
* User logged in application
*
* - **context_path**
* The path to be pre-appended to the URL paths used in the requests.
*
* Ex.
* ~~~
* basiccore
* ~~~
*
* - **base_url**
* The API URL of "maps" to be used when the widget is loaded within an application with a domain different from that of maps.
*
* Ex.
* ~~~
* https:/deve-mapsview.civis.bz.it
* ~~~
*
* - **context_identifier**
* Identifier of the context to load.
* It is possible to provide the identifier instead of the entire context configuration.
* The widget will make the appropriate request to the server to obtain the correct configuration.
* It is not necessary to pass the "context_configs" parameter to the widget.
*
* - **context_configs**
* Context configurations to run widget.
* For details of this configurations see response of maps API:
* ~~~
* /maps/api/v1/contexts/<context_identifier>
* ~~~
*
* - **language**
* Language to localized widget
*
* Ex.
* ~~~
* it
* ~~~
*
* - **initial_extent**
* Initial extent of the map
* ~~~
* [<minX>, <minY, <maxX>, <maxY>]
* ~~~
*
* - **initial_extent_epsg**
* Coordinate system of initial extent
*
* Ex.
* ~~~
* EPSG:25832
* ~~~
*
* - **filtered_layers**
* Layers of the context to load that can not be visualized
*
* Ex.
* ~~~
* {
* contexts: ['BC-BASIC-CORE'],
* identifiers: ['PROV-ADMINISTRATIVE-UNITS-MUNICIPALITIES'],
* }
* ~~~
*
* - **cmp_configs**
* Tools and widgets configurations
* This JSON configuration defines the **component settings (`cmpConfigs`)** for a mapping or GIS web application. It specifies which features, tools, and behaviors should be enabled or customized in different parts of the application, such as overview maps, catalogs, tools, and layer controls (TOC – Table of Contents). Here's a breakdown of its structure and functionality:
* ---
*
* ### **Top-Level Keys in `cmpConfigs`:**
*
* ---
*
* #### 1. **`overview`**
*
* * **Purpose**: Sets the base layer for the overview map (typically a mini-map or context map).
* * **Key**:
*
* * `layerIdentifier`: Uses layer as the background layer.
*
* ---
*
* #### 2. **`catalogs`**
*
* * **Purpose**: Manages the visibility and availability of layer and data catalogs displayed on the left side of the widget interface.
*
* * **Keys**:
*
* * `enabled`: Activates catalogs in the desktop version of the application
* * `mobile`: Specifies which catalogs are available when the application is used on mobile devices.
*
* ---
*
* #### 3. **`tools`**
*
* * **Purpose**: Defines which map tools are available to the user.
* * **Keys**:
*
* * `enabled`: List of desktop tools like:
*
* * `drawMeasure`: Drawing and measuring on the map
* * `selection`: Spatial or attribute-based selection
* * `identifyMap`: Identify features on the map
* * `printMap`: Print the current map view
* * `downloadMap`: Download the map as an image or file
* * `downloadLayer`: Download geodata
* * `editingMap`: Edit spatial features
* * `geoprocess`: Run geospatial processing functions
* * `timeseriesTool`: Time slider for temporal data
* * `externalThemes`: Add external WMS Themes
* * `default`: Index in the enabled list marks the default active
* * `mobile`: specifies which map tool are available when the application is used on mobile devices.
*
* ---
*
* #### 4. **`functions`**
*
* * **Purpose**: Activates additional application-wide features accessible through various submenus within the application.
*
* * **Keys**:
* * `enabled`: List of desktop tools like:
*
* * `fnBaseMaps`: Switch between base maps
* * `fnViewTools`: Toggle map view tools
* * `fnMasterDetails`: Use master-detail UI layout
* * `fnDocumentsRead`, `fnDocumentsWrite`: Document management (read/write)
* * `fnExportData`: Exporting data
* * `fnImportData`: Importing data
* * `fnScalebar`: Show scale bar
* * `fnSearch`: Search capabilities
* * `fnLocation`: Geolocation tools
* * `fnGoogleStreetView`: Integration with Google Street View
* * `fn3dView`: 3D map viewing
* * `fnViewTools`: 2D map viewing tools
*
* ---
*
* #### 5. **`toc` (Table of Contents)**
*
* * **Purpose**: Manages available tools for each layer in the layer list panel.
*
* * **Keys**:
* * `tools.enabled`: For desktop, includes:
*
* * `infoLayer`: View metadata or description
* * `layerLegend`: Show legend
* * `filterLayer`: Filter data within layer
* * `layerTransparency`: Adjust layer opacity
* * `removeLayer`: Remove the layer
* * `shortInfo`: Show short information tooltip
* * `downloadLayer`: Download layer data
* * `zoomToExtent`: Download layer data
* * `tools.mobile`: specifies which map tool are available when the application is used on mobile devices.
*
* ---
* Ex.
* ~~~
* cmpConfigs: {
* overview: {
* layerIdentifier: "PROV-BASEMAP-STANDARD",
* },
* catalogs: {
* enabled: ['contextCatalog','geoCatalog'],
* mobile: ['contextCatalog']
* },
* tools: {
* enabled: ['drawMeasure','selection','identifyMap','printMap','downloadMap','downloadLayer','editingMap','geoprocess','timeseriesTool'],
* default: 2,
* mobile: ['identifyMap']
* },
* functions: {
* enabled: ['fnBaseMaps','fnViewTools','fnMasterDetails','fnDocumentsRead','fnDocumentsWrite','fnExportData','fnImportData','fnScalebar','fnSearch','fnLocation','fnGoogleStreetView','fn3dView']
* },
* toc: {
* tools: {
* enabled: ['infoLayer','layerLegend','filterLayer','layerTransparency','removeLayer','shortInfo', 'downloadLayer'],
* mobile: ['layerLegend','layerTransparency','removeLayer', 'shortInfo']
* }
* }
* }
* ~~~
*
* - **territory**
* Territory parameter: This parameter consists of two values separated by a colon (:).
* - Territory name
* - Territory id (code)
*
* Ex.
* ~~~
* MUNICIPALITY:21001
* ~~~
*
* - **maps_api_env**
* Env code of maps api envinment to use.
* ~~~
* DEV - TEST - DEMO - PROD
* ~~~
*
* - **panel_tools_catalogs_visible**
* Boolean parameter to show or hide the buttons of tools and themes panel.
*
* Ex.
* ~~~
* true
* ~~~
*
* - **panel_active_themes_visible**
* Boolean parameter to show or not the right panel that shows active themes.
*
* Ex.
* ~~~
* true
* ~~~
*
* - **ctrl_zoom**
* Boolean parameter to enable the Zoom In/Out function on the map with ctrl + scroll.
*
* Ex.
* ~~~
* true
* ~~~
*
* - **disable_identify_display**
* Boolean parameter to disable the display of identifying information in the template elements
* of some components (e.g., `Map.vue`, `IdentifyTool.vue`) for the selected layers.
*
* Ex.
* ~~~
* true
* ~~~
*
* - **enable_search_event**
* Boolean parameter to enable the event generated by selecting an item from the search results.
* If not defined, event is disabled by default.
*
* Ex.
* ~~~
* true
* ~~~
*/
props: {
current_user_iam: {
type: Object,
default: null
},
current_user: {
type: Object,
default: null
},
context_path: {
type: String,
default: ""
},
context_identifier: {
type: String,
default: ""
},
context_configs: {
type: Object,
default: null
},
base_url: {
type: String,
default: ""
},
language: {
type: String,
default: "it"
},
initial_extent: {
type: Array,
default: () => []
},
initial_extent_epsg: {
type: String,
default: ""
},
filtered_layers: {
type: Object,
default: () => ({})
},
cmp_configs: {
type: Object,
default: () => ({})
},
territory: {
type: String,
default: ""
},
maps_api_env: {
type: String,
default: ""
},
bc_data: {
type: Object,
default: null
},
panel_tools_catalogs_visible: {
type: Boolean,
default: true
},
panel_active_themes_visible: {
type: Boolean,
default: true
},
ctrl_zoom: {
type: Boolean,
default: false
},
disable_identify_display: {
type: Boolean,
default: false
},
enable_search_event: {
type: Boolean,
default: false
},
},
expose: [
"activateTour",
"loadFeatures",
"activateLayer",
"activateDrawGeometry",
"toggleIdentify",
"filterLayerWms",
"zoomToExtent",
"search",
],
emits: [
"mounted",
"map_loaded",
"center_changed",
"drawn_geometry",
"drawn_geometry_clear",
"finish_tour",
"identify_result",
"new_notification",
"change_lang",
"search_result",
// Only for BC
"bc_editing_complete",
],
events: {
'map_loaded': 'onMapLoaded',
"map_ready": 'onMapReady',
'center_changed': 'onCenterChanged',
'handle_identify_result': 'handleIdentifyResult',
'new_notification': 'onNewNotification',
'handle_search_result': 'handleSearchResult',
// Only for BC
'bc_editing_complete': 'onCompleteBcEditing',
'apply_project': 'applyProject',
'changeLang': 'changeLang'
},
components: {
Viewer,
Tour,
Overlay,
ElNotification,
ElMessage
},
computed: {
isReady() {
return (
this.componentStore.initialized &&
this.contextStore.initialized &&
this.authStore.currentUserIam &&
this.userSettingsStore.userSettingsInitialized &&
this.territoryReady &&
this.initialExtentReady &&
this.initialExtentEpsgReady
);
},
tourSteps() {
return TourSteps ? TourSteps : [];
},
projectsEnabled() {
return this.componentStore.getEnabledFunctions().includes(FunctionsConstants.projects);
}
},
created() {
this.$registerEvents(this);
},
mounted() {
scopeApi = this;
this.panelStore.elementRoot = this.$refs['mw-container'];
this.$emit("mounted");
// Memorizza il parametro disable_identify_display nello store
this.componentStore.setDisableIdentifyDisplay(this.disable_identify_display);
window.addEventListener("dragover",function(e){
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e.preventDefault();
},false);
},
data() {
return {
// Stores
envStore: envStore(),
authStore: authStore(),
userSettingsStore: userSettingsStore(),
contextStore: contextStore(),
termsofuseStore: termsofuseStore(),
paramsStore: paramsStore(),
panelStore: panelStore(),
componentStore: componentStore(),
mapStore: mapStore(),
layerStore: layerStore(),
toolStore: toolStore(),
styleStore: styleStore(),
editingBcStore: editingBcStore ? editingBcStore() : null,
searchStore: searchStore(),
projectStore: projectStore(),
// Params
territoryReady: false,
initialExtentReady: false,
initialExtentEpsgReady: false,
loadingProject: null
};
},
methods: {
handleSearchResult(feature) {
this.$emit('search_result', feature);
},
handleIdentifyResult(features) {
this.$emit('identify_result', features);
},
finishTour(value){
this.$emit("finish_tour", value);
},
getDefinedUserStyles(contextId) {
HttpClient.get('./maps/api/v1/contexts/' + contextId + "/symbols", {
headers: {
"maps-user-context": this.contextStore.getContext()
},
onSuccess: (response) => {
this.styleStore.init(response.data);
}
});
},
getUserSettings() {
this.createMapSession();
const contextId = this.contextStore.getContextId();
HttpClient.get('./maps/api/v1/contexts/' + contextId + "/settings"
+ '?uid=' + localStorage.getItem("session-uid")
+ '&id=' + localStorage.getItem("session-id"), {
onSuccess: (response) => {
this.userSettingsStore.setSettings(response.data);
}
});
},
getSpatialOptions() {
HttpClient.get('./maps/api/v1/features/spatialops', {
headers: {
"maps-user-context": this.contextStore.getContext()
},
onSuccess: (response) => {
this.toolStore.spatialOptions = response.data;
}
});
},
createMapSession() {
const uuid = localStorage.getItem("session-uid") ? localStorage.getItem("session-uid") : Utils.generaGUID();
const id = localStorage.getItem("session-id") ? localStorage.getItem("session-id") : Math.floor(Math.random() * 100000);
localStorage.setItem("session-uid", uuid);
localStorage.setItem("session-id", id);
},
resetStores() {
this.contextStore.destroy();
this.mapStore.destroy();
//this.toolStore.destroy();
this.layerStore.destroy();
this.userSettingsStore.destroy();
},
// #############################################
// Init context with received configs (init all)
// #############################################
handleTermsOfUse(contextConfigs) {
if(!contextConfigs) return;
// Retrieve terms of use before set context
// Layers have to be load depending on terms of use
// If logged in
if(this.authStore.isAuthenticated()) {
HttpClient.get('./maps/api/v1/termsofuse/accepted', {
loading: true,
headers: {
"maps-user-context": contextConfigs.identifier
},
onSuccess: (response) => {
this.termsofuseStore.accepted = response.data;
setTimeout(() => {
// Set context and load map
this.setContextConfigs(contextConfigs);
}, 300);
}
});
}
// No logged in
else {
const accepted = localStorage.getItem("tou-accepted-ids");
this.termsofuseStore.accepted = accepted ? accepted : [];
setTimeout(() => {
// Set context and load map
this.setContextConfigs(contextConfigs);
}, 300);
}
},
setContextConfigs(contextConfigs) {
// Retrieve defined user styles
this.getDefinedUserStyles(contextConfigs.id);
this.contextStore.backupConfigs = Utils.cloneDeep(contextConfigs); //copia clone per caricamento progetto
// Change baselayers ids
MapsWidgetService.updateBaselayersIds(contextConfigs.baseMaps);
this.contextStore.init(contextConfigs);
this.mapStore.init(contextConfigs);
this.toolStore.init(contextConfigs);
// Retrieve defined user styles
this.getDefinedUserStyles(contextConfigs.id);
// Get user settings: last saved configurations
this.getUserSettings();
// Get spatial options
this.getSpatialOptions();
},
initLayers() {
// Map layer: layerTree and layerGroups from json config
const layerTree = this.contextStore.getLayerTree();
const layerGroups = this.contextStore.getLayerGroups();
let wmsExternalTheme = this.userSettingsStore.getWmsThemes();
let mapLayers = layerTree.concat(layerGroups);
if (wmsExternalTheme && wmsExternalTheme.items && Array.isArray(wmsExternalTheme.items) && wmsExternalTheme.items.length > 0) {
mapLayers = mapLayers.concat(wmsExternalTheme);
console.log('concateno anche i wmsExternal trovati',mapLayers);
}
// Add imported data
MapsWidgetService.addImportedVectorData(mapLayers);
// Set user tree state configurations (if present)
if(this.userSettingsStore.getLayerTreeState()) {
MapsWidgetService.setLayerTreeUserState(mapLayers, {
childrenTag: "items"
});
}
// Get protected layers from configs
const protectedLayers = MapsWidgetService.getProtectedLayers(mapLayers);
if(protectedLayers.length == 0 || !this.authStore.isAuthenticated()) {
this.initLayerStore(mapLayers);
return;
}
let protectedServers = new Set();
protectedLayers.forEach(layer => {
protectedServers.add(layer.serverIdentifier);
});
const todoCalls = protectedServers.size;
let completedCalls = 0;
protectedServers.forEach(server => {
HttpClient.post('./maps/api/v1/tokens/' + server, {
onSuccess: (response) => {
completedCalls++;
this.authStore.setAuthServerToken(server, response.data.token);
if(todoCalls == completedCalls) {
this.initLayerStore(mapLayers);
}
},
onFail: (error) => {
completedCalls++;
if(todoCalls == completedCalls) {
this.initLayerStore(mapLayers);
}
}
})
});
},
initLayerStore(mapLayers) {
// Set prefix in group id
MapsWidgetService.setPrefixToFolderId(mapLayers);
// set parent group for layers
MapsWidgetService.addGroupToLeafs(mapLayers);
// If children layer transparency is not specified, the parent's one is used
MapsWidgetService.applyGroupTransparencyToChildren(mapLayers);
// Update external layers group name, useful on language switch
MapsWidgetService.updateExternalLayersGroupName(mapLayers);
// Catalog layers (if catalog is present)
let catalogLayers = [];
if (this.componentStore.hasCatalog()) {
catalogLayers = mapLayers.filter(layer =>
!layer.isImportGroup && !layer.importedFile);
}
// Set active layers filtering maplayers by "layer_filtered" parameter
function isLayerActive(layer) {
let visible = true;
let matchContext = false;
let matchIdentifier = false;
if (scopeApi?.filtered_layers?.contexts?.length > 0) {
visible = false;
matchContext = scopeApi.filtered_layers.contexts.includes(layer.serverIdentifier);
}
if (scopeApi?.filtered_layers?.identifiers?.length > 0) {
visible = false;
matchIdentifier = scopeApi.filtered_layers.identifiers.includes(layer.identifier);
}
// Filter if layer has terms of use not already accepted
const touAccepted = MapsWidgetService.isTermsOfUseLayerAccepted(layer);
return (matchContext || matchIdentifier || visible) && touAccepted;
}
// console.log("Active layers: " + activeLayers.length);
function filterGroupVisibleLayers(group){
group.items = group.items.filter((item) => {
if (item["@type"] === "layer") {
item.visible = Boolean(item.visible); //set false if null
item.isActive = 'isActive' in item ? item.isActive : item.visible; // init isActive if not retrieved from settings
if (!componentStore().hasCatalog() || (item.visible && isLayerActive(item))) {
return true;
} else {
return false;
}
} else {
const filteredGroup = filterGroupVisibleLayers(item);
if (filteredGroup.items.length > 0) {
filteredGroup.visible = filteredGroup.items.some((i) => i.visible);
filteredGroup.isActive = 'isActive' in filteredGroup ? filteredGroup.isActive : filteredGroup.visible; // init isActive if not retrieved from settings
return true;
}
}
});
return group;
}
let activeLayers = Utils.cloneDeep(mapLayers).filter((item) => {
if (item["@type"] === "layer") {
item.visible = Boolean(item.visible); //set false if null
item.isActive = 'isActive' in item ? item.isActive : item.visible; // init isActive if not retrieved from settings
if (item.visible || !componentStore().hasCatalog()) {
return true;
} else {
return false;
}
} else {
const filteredGroup = filterGroupVisibleLayers(item);
if (filteredGroup.items.length > 0) {
filteredGroup.visible = filteredGroup.items.some((i) => i.visible);
filteredGroup.isActive = 'isActive' in filteredGroup ? filteredGroup.isActive : filteredGroup.visible; // init isActive if not retrieved from settings
return true;
}
}
})
this.layerStore.initCatalogLayers(catalogLayers);
//inizializzo gli active layers ordinando l'albero in base alla proprietà index
this.layerStore.initActiveLayers(Utils.orderTree(activeLayers, 'index', 'items'));
this.layerStore.initExpandedLayers(this.layerStore.activeLayers);
},
onMapLoaded() {
this.initLayers();
if (this.projectsEnabled) {
this.initProjects();
}
},
onMapReady() {
this.$emit("map_loaded");
this.$trigger("updateMapSize");
},
onNewNotification(notification) {
this.$emit('new_notification', notification);
},
onCenterChanged(center) {
this.$emit("center_changed", {
lon: center[0],
lat: center[1]
});
},
onDrawnGeometry(epsg, wkt) {
epsg = epsg.split(":")[1];
scopeApi.$emit("drawn_geometry", {
wkt: wkt,
epsg: epsg
});
},
onDrawnGeometryClear() {
scopeApi.$emit("drawn_geometry_clear");
},
/**
* BC: emit event of completed editing by the user
* (From EditingBcTool)
*/
onCompleteBcEditing(sessionId) {
this.$emit("bc_editing_complete", sessionId);
},
// ###########
// API
// ###########
/**
* API -
* Load a list of vector features into map
*
* @param {JSON} jsonFeatures Json object with list of features in geojson format and their EPSG
*
* @example
* {
* features: [
* <geojsonFeature>,
* <geojsonfeature>,
* ...
* ...
* ]
* epsg: 28532
* }
*/
loadFeatures(jsonFeatures) {
console.log("MW - API: Loading features into map");
// Handle layer to load in map if it exists as feature property
if(jsonFeatures?.features) {
let layerIdentifiers = jsonFeatures.features.map(geojsonFeature => {
return geojsonFeature.properties?.layerIdentifier;
});
scopeApi.$trigger('activateLayers', [ layerIdentifiers ]);
}
let epsg = "EPSG:" + jsonFeatures.epsg;
scopeApi.$trigger("loadFeatures", [jsonFeatures.features, epsg, true]);
},
/**
* API -
* Activates tour widget.
* The widget displays a wizard at startup to describe the base functionalities of maps-widget
*
* @param {JSON} parentSteps List of parent application elements to insert into tour widget.
*
* @example
* parentSteps = [
* ...
* {
* // Identifier class of parent element
* target: '.tour-target-1',
* // Relative position of popup
* position: 'bottom-right',
* // Content of popup: title and text
* content: {
* title: 'TOUR.steps.parent.1.title', //
* text: 'TOUR.steps.parent.1.text'
* },
* },
* ...
* ]
*
* WARNING: "text" and "title" parameters are the localization tag of text to display.
* They have to be added in localization file of maps-widget
*/
activateTour(parentSteps) {
console.log("MW - API: activating tour..");
let steps = null;
if(parentSteps) {
// Merge steps parent with widget steps
if(scopeApi.tourSteps && scopeApi.tourSteps[0]?.once) {
steps = Utils.mergeAtIndex(scopeApi.tourSteps, parentSteps, (scopeApi.tourSteps.length));
}
else {
steps = parentSteps.concat(scopeApi.tourSteps);
//steps = scopeApi.tourSteps.concat(parentSteps);
}
}
scopeApi.$trigger('activateTour', [steps]);
},
/**
* API -
* Turn on / off a layer in map.
*
* @param {String} layerIdentifier Identificativo del layer
* @param {Boolean} active Stato del layer: acceso / spento
* @param {Boolean} visible (opzionale) se il layer è acceso, indica se deve essere visibile o no
*/
activateLayer(layerIdentifier, active, visible=true) {
console.log("MW - API: activate layer in map " + layerIdentifier);
if(layerIdentifier) {
if(active == true || active == null || active == undefined) {
const layerIdentifiers = [layerIdentifier]
this.$nextTick(() => {
scopeApi.$trigger('activateLayers', [layerIdentifiers]);
this.$nextTick(() => {
Utils.setPropertyTreeById(scopeApi.layerStore.activeLayers, layerIdentifier, 'isActive', visible, true);
});
});
}
else if(active == false){
scopeApi.layerStore.removeActiveLayerByIdentifier(layerIdentifier);
}
}
},
/**
* API -
* Enable control to draw geometry in map
*
* @param {String} Identifier of draw geometry control that will be initialized. User can interact later with same control passing the same identifier
* @param {('Point'|'LineString'|'Polygon')} type Geometry type to draw
* @param {String} epsgOutput Coordinate system of drawn geometry returned by map control (Only identifier code)
* @param {JSON} options Extra params to handle draw control
*
* @example
* epsgOutput = 25832
*
* options = {
* // Geometry format of drawn geometry: geojson, wkt..
* outputFormat: "WKT",
* // If clean previus drawn geometries when user starts to draw new one
* cleanOnStart: true,
* // If drawn geometries have to be removed after deactivating draw control.
* cleanOnDeactivate: true
* }
*/
activateDrawGeometry(identifierControl, type, epsgOutput, options) {
console.log("MW - API: activate draw geometry ");
const epsgOutputCode = "EPSG:" + epsgOutput;
//scopeApi.$trigger('activateDrawGeometry', [type, epsgOutputCode, scopeApi.onDrawnGeometry, scopeApi.onDrawnGeometryClear]);
// Init control draw
scopeApi.$trigger('initDrawGeometry', [{
identifier: identifierControl,
onAdd: scopeApi.onDrawnGeometry,
onClear: scopeApi.onDrawnGeometryClear,
epsgOutput: epsgOutputCode,
tooltip: false,
drawingConditionFn: drawingCondition,
finishConditionFn: finishDrawCondition,
outputFormat: options?.outputFormat,
cleanOnStart: options?.cleanOnStart,
cleanOnDeactivate: options?.cleanOnDeactivate
}]);
scopeApi.$trigger('activateDrawGeometry', [{
identifier: identifierControl,
geometryType: type
}]);
},
/**
* API -
* Turn on / off the identify tool.
*
* @param {Boolean} active Identify tool state: on / off
*/
toggleIdentify(active) {
if (typeof active === 'boolean') {
if (active) {
this.toolStore.activeTool = ToolsConstants.tools.identify;
} else {
if (this.toolStore.activeTool == ToolsConstants.tools.identify) {
this.toolStore.activeTool = '';
}
}
}
},
/**
* API -
* Filter WMS layer
*
* @param {JSON} filter list of cql filters to apply for specific layers
*
* @example
* filter = [
* {
* layerIdentifier: BC-SESSIONS,
* cql_filter: <cql_filter_string>,
* columns: [<column1>, <column2>, ...]>
* }
* ]
*/
filterLayerWms(filters) {
console.log("MW - API: filter WMS layer " + JSON.stringify(filters));
scopeApi.$trigger('filterWms', [filters]);
},
/**
* API -
* Zoom to extent
*
* @param {JSON} extent List of coordinates of extent
* @param {String} epsg Coordinate system of extent
*
* @example
* extent = [ <minX>, <minY>, <maxX>, <maxY> ]
*
* epsg = 25832
*/
zoomToExtent(extent, epsg) {
console.log("MW - API: Zoom to extent " + extent);
const epsgOutputCode = "EPSG:" + epsg;
scopeApi.$trigger('zoomToExtent', [extent, epsgOutputCode]);
},
/**
* API -
* Allows to make a search on different levels and displays results on map.
* The search has been performed through the maps search API: 'maps/api/v1/search/\<searchTypeId\>/features'.
*
* searchTypeId -> one of params of 'searchParams' object parameter.
*
* *For more details of how "searchParms" is defined see documentation of maps search API service.*
*
* @param {Boolean} active If tool has to activate or to be closed.
* @param {JSON} searchParams Search parameters.
*
*/
search(active, searchParams) {
console.log("MW - API: Search in map..");
if (!active) {
scopeApi.$trigger('toggleTableResults', [false, null]);
} else {
const params = {
q: searchParams.searchText,
center: searchParams.center.lat + "," + searchParams.center.lon
}
const headers = {
'maps-user-context': searchParams.context
}
HttpClient.get('./maps/api/v1/search/' + searchParams.searchType.id + '/features', {
params: params,
headers: headers,
onSuccess: (response) => {
let results = [];
if (response?.data && response?.data.length) {
results = response.data.map(featureCollection => {
return {
...featureCollection,
...{
label: searchParams.searchType.name,
epsg: 'EPSG:' + featureCollection.crs?.properties.name.split('EPSG::')[1]
}
}
});
}
scopeApi.$trigger('toggleTableResults', [true, results, null, false, false, true, 'search']);
}
});
}
},
initProjects() {
if (localStorage.getItem('projectRecovery')) {
this.loadingProject = ElLoading.service({lock: true, text: this.$t('PROJECTS.projectLoading')});
}
//ottengo i progetti associati
projectService.getAllProjects().then(res => {
if (res?.data?.length) {
this.projectStore.setProjects(res.data);
if (localStorage.getItem('projectRecovery')) {
let recProject = JSON.parse(localStorage.getItem('projectRecovery'));
this.userSettingsStore.userSettings = Utils.cloneDeep(recProject.settings);
this.layerStore.destroy();
this.applyProject(recProject);
}
}
this.$nextTick(() => {
if (localStorage.getItem('projectRecovery')) {
this.loadingProject.close();
localStorage.removeItem('projectRecovery');
}
})
this.projectStore.setInitProjects();
}).catch((error) => {
ElMessage({
appendTo: this.panelStore.elementRoot,
message: `${this.$t('MESSAGES.error')} ${error?.message}`,
type: 'error',
grouping: true
});
this.projectStore.setInitProjects();
if (localStorage.getItem('projectRecovery')) {
this.loadingProject.close();
localStorage.removeItem('projectRecovery');
}
});
},
/* Applico il progetto selezionato */
applyProject(project) {
this.$trigger('deactivateAllControls');
if (this.mapStore.use3D) {
this.$trigger('deactivateAllControls3D');
}
this.$nextTick(() => {
//ricarico context settings (senza dover richiamare il servizio)
this.contextStore.config = Utils.cloneDeep(this.contextStore.backupConfigs);
//ricarico basemap
if (this.userSettingsStore.getBasemap()) {
let baseMap = this.mapStore.getBaseLayers().find(el => el.identifier == this.userSettingsStore.getBasemap());
if (baseMap) {
this.$trigger('set_active_baseLayer', [baseMap]);
}
else {
this.restoreEmptyBaseMap();
}
this.layerStore.setBaseLayersInitialized(true);
}
//ricarico extent
if (this.userSettingsStore.getExtent()) {
let extent = Utils.cloneDeep(this.userSettingsStore.getExtent());
let transfExtent = transformExtent(this.userSettingsStore.getExtent(), 'EPSG:3857', project.crs);
this.$trigger('zoomToExtent', [transfExtent, project.crs]);
if (this.mapStore.use3D) {
this.$trigger('saveExtent2D', [extent]);
this.$trigger('setExtent3D', [transfExtent, project.crs]);
}
}
//ricarico projection
if (this.mapStore.getCurrentViewedProjection() != project.crs) {
this.mapStore.setCurrentViewedProjection(project.crs);
}
//ricarico i layers
this.initLayers();
//aggiorno
this.$forceUpdate();
this.$nextTick(() => {
ElNotification({
type: 'success',
position: 'top-right',
title: this.$t('MESSAGES.success'),
message: this.$t('PROJECTS.successApplication', {projectName: project.title}),
duration: 5000
});
this.projectStore.selectedRecoveryProjectId = project.id;
this.toolStore.setActiveTool(this.toolStore.defaultTool);
this.$trigger('initDrawnFeaturesStore', [true]);
if (this.mapStore.use3D) {
this.$trigger('loadSavedFeatures3D', ['drawMeasures3D']);
}
});
});
},
restoreEmptyBaseMap() {
//ripristino basemap in caso fosse salvata quella vuota
const blankBaselayer = {
id: "blank",
identifier: "EMPTY_BASEMAP_IDENTIFIER",
name: this.$t('WIDGETS.baselayers.blank'),
blank: true
};
this.$trigger('set_active_baseLayer', [blankBaselayer]);
},
changeLang(lang) {
this.$emit('change_lang', lang);
}
},
watch: {
isReady: {
immediate: true,
handler(isReady) {
if (isReady) {
// Force to open left panel with activated editing tool
if(this.toolStore.defaultTool == ToolsConstants.tools.editingBc) {
this.$nextTick(() => {
this.panelStore.openLeftPanel(WidgetConstants.tools);
});
}
}
}
},
maps_api_env: {
immediate: true,
handler(env) {
if (env) {
this.envStore.setEnv(env);
}
}
},
language: {
immediate: true,
handler(language) {
if (language) {
this.$i18n.locale = language;
}
}
},
current_user_iam: {
immediate: true,
handler(currentUserIam) {
if (currentUserIam) {
this.authStore.setCurrentUserIam(currentUserIam);
}
}
},
current_user: {
immediate: true,
handler(currentUser) {
if (currentUser) {
this.authStore.setCurrentUser(currentUser);
}
}
},
context_path: {
immediate: true,
handler(contextPath) {
if (contextPath) {
this.paramsStore.setContextPath(contextPath);
}
}
},
base_url: {
immediate: true,
handler(baseUrl) {
if (baseUrl) {
this.paramsStore.setBaseUrl(baseUrl);
}
}
},
context_identifier: {
immediate: true,
handler(contextIdentifier) {
//this.resetStores();
if(contextIdentifier) {
console.log("MW - Getting context configuration by Identifier: " + contextIdentifier);
HttpClient.get('./maps/api/v1/contexts/' + contextIdentifier, {
onSuccess: (response) => {
// Retrieve terms of use
this.handleTermsOfUse(response.data);
}
});
}
}
},
context_configs: {
immediate: true,
handler(contextConfigs) {
//this.resetStores();
if (contextConfigs) {
// Retrieve terms of use
this.handleTermsOfUse(contextConfigs);
}
}
},
/**
* Listener for component configs:
* See "cmpConfigs" parameter in App.vue or documentation
*/
cmp_configs: {
immediate: true,
handler(config) {
console.log("MW - Comp. props:" + JSON.stringify(config));
if (config != null) {
// config.tools.enabled -> remove editing tools
MapsWidgetService.setAllowedMobileTools(config.tools);
MapsWidgetService.setAllowedMobileTools(config.toc.tools);
MapsWidgetService.setAllowedMobileCatalogs(config.catalogs);
// Put component config into componentStore
this.componentStore.init(config);
// Set default tool
if (config.tools.enabled?.length) {
this.toolStore.defaultTool = config.tools.enabled[config.tools.default];
}
// Set overview default layer to use if specified
this.mapStore.setOverviewLayerIdentifier(config.overview?.layerIdentifier);
}
},
},
/**
* Listener for initial extent
*/
initial_extent: {
immediate: true,
handler(extent) {
if(extent && extent.length) {
console.log("MW - Extent iniziale: " + extent);
this.mapStore.initialExtent.extent = extent.map(coord => parseFloat(coord));
}
this.initialExtentReady = true;
}
},
initial_extent_epsg: {
immediate: true,
handler(epsg) {
if(epsg) {
console.log("MW - EPSG extent iniziale: " + epsg);
this.mapStore.initialExtent.epsg = epsg;
}
this.initialExtentEpsgReady = true;
}
},
/**
* Territory props
*/
territory: {
immediate: true,
handler(territory) {
if(territory) {
this.paramsStore.setTerritory(territory);
}
this.territoryReady = true;
}
},
panel_tools_catalogs_visible: {
immediate: true,
handler(value) {
if (typeof value === 'boolean') {
this.componentStore.setPanelToolsCatalogsVisibile(value);
if (!value) {
this.panelStore.closeLeftPanel();
}
}
}
},
panel_active_themes_visible: {
immediate: true,
handler(value) {
if (typeof value === 'boolean') {
this.componentStore.setPanelActiveThemesVisible(value);
}
}
},
ctrl_zoom: {
immediate: true,
handler(ctrl_zoom) {
if(typeof ctrl_zoom === 'boolean') {
this.componentStore.setCtrlZoom(ctrl_zoom);
}
}
},
/**
* Props object passed only from basiccore
* bc_data is an object with:
* - user: basiccore user
* - session: basiccore session to edit
*/
bc_data: {
immediate: true,
handler(data) {
if(data) {
if(data.session && !this.editingBcStore) {
throw new Error("Can not load BC store. Missing BC module. Check if BC module has been loaded")
}
this.editingBcStore?.initMainData(data);
}
}
},
enable_search_event: {
immediate: true,
handler(value) {
if (typeof value === 'boolean') {
this.componentStore.setEnableSearchEvent(value);
}
}
},
}
};
</script>