Skip to content
Snippets Groups Projects
Commit d37e0b52 authored by Sébastien DA ROCHA's avatar Sébastien DA ROCHA :bicyclist:
Browse files

Merge branch 'redmine-issues/14234' into 'develop'

REDMINE_ISSUE-14234|Liste et carte - Erreur couches requêtables avec plusieurs fonds

See merge request !427
parents 53915643 81f74c66
No related branches found
No related tags found
1 merge request!427REDMINE_ISSUE-14234|Liste et carte - Erreur couches requêtables avec plusieurs fonds
<template>
<div class="basemaps-items ui accordion styled">
<div
:class="['basemap-item title', { active }]"
@click="$emit('activateGroup', basemap.id)"
>
<i
class="map outline fitted icon"
aria-hidden="true"
/>
<span>{{ basemap.title }}</span>
</div>
<div
v-if="queryableLayersOptions.length > 0 && active"
:id="`queryable-layers-selector-${basemap.id}`"
>
<strong>Couche requêtable</strong>
<Dropdown
:options="queryableLayersOptions"
:selected="selectedQueryLayer"
:search="true"
@update:selection="onQueryLayerChange($event)"
/>
</div>
<div
:id="`list-${basemap.id}`"
:class="['content', { active }]"
:data-basemap-index="basemap.id"
>
<div
v-for="(layer, index) in basemap.layers"
:key="basemap.id + '-' + layer.id + '-' + index"
class="layer-item transition visible item list-group-item"
:data-id="layer.id"
>
<!-- layer id is used for retrieving layer when changing order -->
<p class="layer-handle-sort">
<i
class="th icon"
aria-hidden="true"
/>
{{ layer.title }}
</p>
<label>Opacité &nbsp;<span>(%)</span></label>
<div class="range-container">
<input
type="range"
min="0"
max="1"
:value="layer.opacity"
step="0.01"
@change="updateOpacity($event, layer)"
><output class="range-output-bubble">{{
getOpacity(layer.opacity)
}}</output>
</div>
<div class="ui divider" />
</div>
</div>
</div>
</template>
<script>
import Sortable from 'sortablejs';
import Dropdown from '@/components/Dropdown.vue';
import mapService from '@/services/map-service';
export default {
name: 'LayerSelector',
components: {
Dropdown,
},
props: {
basemap: {
type: Object,
default: null,
},
baseMaps: {
type: Array,
default: () => [],
},
active: {
type: Boolean,
default: false,
},
},
data() {
return {
baseMap: {},
selectedQueryLayer: null,
sortable: null,
};
},
computed: {
queryableLayersOptions() {
const queryableLayers = this.basemap.layers.filter((l) => l.queryable === true);
return queryableLayers.map((x) => {
return {
name: x.title,
value: x,
};
});
}
},
mounted() {
if (this.queryableLayersOptions.length > 0) {
this.selectedQueryLayer = this.queryableLayersOptions[0].name;
}
setTimeout(this.initSortable.bind(this), 1000);
},
methods: {
isQueryable(baseMap) {
const queryableLayer = baseMap.layers.filter((l) => l.queryable === true);
return queryableLayer.length > 0;
},
initSortable() {
const element = document.getElementById(`list-${this.basemap.id}`);
if (element) {
this.sortable = new Sortable(element, {
animation: 150,
handle: '.layer-handle-sort', // The element that is active to drag
ghostClass: 'blue-background-class',
dragClass: 'white-opacity-background-class',
onEnd: () => this.$emit('onlayerMove'),
});
} else {
console.error(`list-${this.basemap.id} not found in dom`);
}
},
onQueryLayerChange(layer) {
this.selectedQueryLayer = layer.name;
const baseMap = this.baseMaps[0].layers.find((l) => l.title === layer.name);
if (baseMap) {
baseMap.query = true;
} else {
console.error('No such param \'query\' found among basemap[0].layers');
}
layer.query = true;
},
getOpacity(opacity) {
return Math.round(parseFloat(opacity) * 100);
},
updateOpacity(event, layer) {
mapService.updateOpacity(layer.id, event.target.value);
layer.opacity = event.target.value;
},
}
};
</script>
<style>
.basemap-item.title > i {
margin-left: -1em !important;
}
.basemap-item.title > span {
margin-left: .5em;
}
.queryable-layers-dropdown {
margin-bottom: 1em;
}
.queryable-layers-dropdown > label {
font-weight: bold;
}
</style>
......@@ -46,89 +46,37 @@
Fonds cartographiques
</h4>
</div>
<div
<LayerSelector
v-for="basemap in baseMaps"
:key="`list-${basemap.id}`"
class="basemaps-items ui accordion styled"
>
<div
:class="['basemap-item title', { active: isActive(basemap) }]"
@click="activateGroup(basemap)"
>
{{ basemap.title }}
</div>
<div
v-if="isQueryable(basemap)"
:id="`queryable-layers-selector-${basemap.id}`"
>
<strong>Couche requêtable</strong>
<Dropdown
:options="getQueryableLayers(basemap)"
:selected="selectedQueryLayer"
:search="true"
@update:selection="onQueryLayerChange($event)"
/>
</div>
<div
:id="`list-${basemap.id}`"
:class="['content', { active: isActive(basemap) }]"
:data-basemap-index="basemap.id"
>
<div
v-for="(layer, index) in basemap.layers"
:key="basemap.id + '-' + layer.id + '-' + index"
class="layer-item transition visible item list-group-item"
:data-id="layer.id"
>
<!-- layer id is used for retrieving layer when changing order -->
<p class="layer-handle-sort">
<i
class="th icon"
aria-hidden="true"
/>
{{ layer.title }}
</p>
<label>Opacité &nbsp;<span>(%)</span></label>
<div class="range-container">
<input
type="range"
min="0"
max="1"
:value="layer.opacity"
step="0.01"
@change="updateOpacity($event, layer)"
><output class="range-output-bubble">{{
getOpacity(layer.opacity)
}}</output>
</div>
<div class="ui divider" />
</div>
</div>
</div>
:basemap="basemap"
:base-maps="baseMaps"
:active="activeBasemap.id === basemap.id"
@addLayers="addLayers"
@activateGroup="activateGroup"
@onlayerMove="onlayerMove"
/>
</div>
</template>
<script>
import { mapState } from 'vuex';
import Sortable from 'sortablejs';
import Dropdown from '@/components/Dropdown.vue';
import LayerSelector from '@/components/Map/LayerSelector.vue';
import mapService from '@/services/map-service';
export default {
name: 'SidebarLayers',
components: {
Dropdown,
LayerSelector
},
data() {
return {
selectedQueryLayer: null,
activeBasemap: null,
baseMaps: [],
expanded: false,
sortable: null
projectSlug: this.$route.params.slug
};
},
......@@ -137,27 +85,29 @@ export default {
'isOnline',
]),
...mapState('map', [
'availableLayers'
'availableLayers',
]),
activeBasemap() {
return this.baseMaps.find((baseMap) => baseMap.active);
},
},
mounted() {
this.baseMaps = this.$store.state.map.basemaps;
const project = this.$route.params.slug;
const mapOptions =
JSON.parse(localStorage.getItem('geocontrib-map-options')) || {};
if (mapOptions && mapOptions[project]) {
if (mapOptions && mapOptions[this.projectSlug]) {
// If already in the storage, we need to check if the admin did some
// modification in the basemaps on the server side. The rule is: if one layer has been added
// or deleted in the server, then we reset the localstorage.
const baseMapsFromLocalstorage = mapOptions[project]['basemaps'];
const baseMapsFromLocalstorage = mapOptions[this.projectSlug]['basemaps'];
const areChanges = this.areChangesInBasemaps(
this.baseMaps,
baseMapsFromLocalstorage
);
if (areChanges) {
mapOptions[project] = {
mapOptions[this.projectSlug] = {
'map-options': this.baseMaps,
'current-basemap-index': 0,
};
......@@ -172,7 +122,6 @@ export default {
if (this.baseMaps.length > 0) {
this.baseMaps[0].active = true;
this.activeBasemap = this.baseMaps[0];
this.addLayers(this.baseMaps[0]);
} else {
mapService.addLayers(
......@@ -182,120 +131,13 @@ export default {
this.$store.state.configuration.DEFAULT_BASE_MAP_SCHEMA_TYPE
);
}
setTimeout(this.initSortable.bind(this), 1000);
},
methods: {
isActive(basemap) {
return basemap.active !== undefined && basemap.active;
},
toggleSidebar(value) {
this.expanded = value !== undefined ? value : !this.expanded;
},
activateGroup(basemap) {
this.baseMaps.forEach((basemap) => (basemap.active = false));
basemap.active = true;
this.activeBasemap = basemap;
basemap.title += ' '; //weird!! Force refresh
this.addLayers(basemap);
let mapOptions = localStorage.getItem('geocontrib-map-options') || {};
mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {};
const project = this.$route.params.slug;
mapOptions[project] = {
...mapOptions[project],
'current-basemap-index': basemap.id,
};
localStorage.setItem(
'geocontrib-map-options',
JSON.stringify(mapOptions)
);
},
updateOpacity(event, layer) {
mapService.updateOpacity(layer.id, event.target.value);
layer.opacity = event.target.value;
},
getOpacity(opacity) {
return Math.round(parseFloat(opacity) * 100);
},
onQueryLayerChange(layer) {
this.selectedQueryLayer = layer.name;
if (this.baseMaps[0].layers.find((l) => l.title === layer.name)) {
this.baseMaps[0].layers.find((l) => l.title === layer.name).query = true;
} else {
console.error('No such param \'query\' found among basemap[0].layers');
}
layer.query = true;
},
isQueryable(baseMap) {
const queryableLayer = baseMap.layers.filter((l) => l.queryable === true);
return queryableLayer.length > 0;
},
onlayerMove() {
// Get the names of the current layers in order.
const currentLayersNamesInOrder = Array.from(
document.getElementsByClassName('layer-item transition visible')
).map((el) => parseInt(el.attributes['data-id'].value));
// Create an array to put the layers in order.
let movedLayers = [];
for (const layerName of currentLayersNamesInOrder) {
movedLayers.push(
this.activeBasemap.layers.filter((el) => el.id === layerName)[0]
);
}
// Remove existing layers undefined
movedLayers = movedLayers.filter(function (x) {
return x !== undefined;
});
const eventOrder = new CustomEvent('change-layers-order', {
detail: {
layers: movedLayers,
},
});
document.dispatchEvent(eventOrder);
// Save the basemaps options into the localstorage
this.setLocalstorageMapOptions(this.baseMaps);
},
setLocalstorageMapOptions(basemaps) {
let mapOptions = localStorage.getItem('geocontrib-map-options') || {};
mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {};
const project = this.$route.params.slug;
mapOptions[project] = {
...mapOptions[project],
basemaps: basemaps,
};
localStorage.setItem(
'geocontrib-map-options',
JSON.stringify(mapOptions)
);
},
initSortable() {
this.baseMaps.forEach((basemap) => {
const element = document.getElementById(`list-${basemap.id}`);
if (element) {
this. sortable = new Sortable(element, {
animation: 150,
handle: '.layer-handle-sort', // The element that is active to drag
ghostClass: 'blue-background-class',
dragClass: 'white-opacity-background-class',
onEnd: this.onlayerMove.bind(this),
});
} else {
console.error(`list-${basemap.id} not found in dom`);
}
});
},
// Check if there are changes in the basemaps settings. Changes are detected if:
// - one basemap has been added or deleted
// - one layer has been added or deleted to a basemap
......@@ -354,16 +196,6 @@ export default {
return !(isSameBasemaps && isSameLayers && isSameTitles);
},
getQueryableLayers(baseMap) {
const queryableLayer = baseMap.layers.filter((l) => l.queryable === true);
return queryableLayer.map((x) => {
return {
name: x.title,
value: x,
};
});
},
addLayers(baseMap) {
baseMap.layers.forEach((layer) => {
const layerOptions = this.availableLayers.find((l) => l.id === layer.id);
......@@ -375,15 +207,57 @@ export default {
// Slice is done because reverse() changes the original array, so we make a copy first
mapService.addLayers(baseMap.layers.slice().reverse(), null, null, null,);
},
activateGroup(basemapId) {
//* to activate a basemap, we need to set the active property to true et set the others to false
this.baseMaps = this.baseMaps.map((bm) => {
return { ...bm, active: bm.id === basemapId ? true : false };
});
//* add the basemap that was clicked to the map
this.addLayers(this.baseMaps.find((bm) => bm.id === basemapId));
//* to persist the settings, we set the localStorage mapOptions per project
this.setLocalstorageMapOptions({ 'current-basemap-index': basemapId });
},
onlayerMove() {
// Get the names of the current layers in order.
const currentLayersNamesInOrder = Array.from(
document.getElementsByClassName('layer-item transition visible')
).map((el) => parseInt(el.attributes['data-id'].value));
// Create an array to put the layers in order.
let movedLayers = [];
for (const layerName of currentLayersNamesInOrder) {
movedLayers.push(
this.activeBasemap.layers.find((el) => el.id === layerName)
);
}
// Remove existing layers undefined
movedLayers = movedLayers.filter(function (x) {
return x !== undefined;
});
const eventOrder = new CustomEvent('change-layers-order', {
detail: {
layers: movedLayers,
},
});
document.dispatchEvent(eventOrder);
// Save the basemaps options into the localstorage
this.setLocalstorageMapOptions({ basemaps: this.baseMaps });
},
setLocalstorageMapOptions(newOptionObj) {
let mapOptions = localStorage.getItem('geocontrib-map-options') || {};
mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {};
mapOptions[this.projectSlug] = {
...mapOptions[this.projectSlug],
...newOptionObj,
};
localStorage.setItem(
'geocontrib-map-options',
JSON.stringify(mapOptions)
);
},
},
};
</script>
<style>
.queryable-layers-dropdown {
margin-bottom: 1em;
}
.queryable-layers-dropdown > label {
font-weight: bold;
}
</style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment