Skip to content

Commit 2e5eb2a

Browse files
committed
feat: Provide a selection manager component - edit feature style action (closes #1098)
1 parent 75afe1d commit 2e5eb2a

File tree

3 files changed

+89
-46
lines changed

3 files changed

+89
-46
lines changed

map/client/components/selection/KSelectedLayerFeatures.vue

+87-46
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,58 @@
11
<template>
2-
<q-tree
3-
:nodes="[root]"
4-
node-key="_id"
5-
label-key="label"
6-
children-key="children"
7-
v-model:expanded="expandedNodes"
8-
dense
9-
>
10-
<template v-slot:default-header="prop">
11-
<!-- Layer rendering -->
12-
<q-icon v-if="prop.node.icon" :name="prop.node.icon"/>
13-
<KLayerItem v-if="isLayerNode(prop.node)"
14-
v-bind="$props"
15-
:togglable="false"
16-
:layer="root"
17-
/>
18-
<!-- Features rendering -->
19-
<div v-else-if="prop.node.label" class="row fit items-center q-pl-md q-pr-sm no-wrap">
20-
<div :class="{
21-
'text-primary': root.isVisible,
22-
'text-grey-6': root.isDisabled || !root.isVisible
23-
}"
24-
>
25-
<span v-html="prop.node.label" />
2+
<div>
3+
<q-tree
4+
:nodes="[root]"
5+
node-key="_id"
6+
label-key="label"
7+
children-key="children"
8+
v-model:expanded="expandedNodes"
9+
dense
10+
>
11+
<template v-slot:default-header="prop">
12+
<!-- Layer rendering -->
13+
<q-icon v-if="prop.node.icon" :name="prop.node.icon"/>
14+
<KLayerItem v-if="isLayerNode(prop.node)"
15+
v-bind="$props"
16+
:togglable="false"
17+
:layer="root"
18+
/>
19+
<!-- Features rendering -->
20+
<div v-else-if="prop.node.label" class="row fit items-center q-pl-md q-pr-sm no-wrap">
21+
<div :class="{
22+
'text-primary': root.isVisible,
23+
'text-grey-6': root.isDisabled || !root.isVisible
24+
}"
25+
>
26+
<span v-html="prop.node.label" />
27+
</div>
28+
<q-space v-if="isFeatureNode(prop.node)"/>
29+
<!-- Features actions -->
30+
<KPanel v-if="isFeatureNode(prop.node)"
31+
:id="`${prop.node.label}-feature-actions`"
32+
:content="featureActions"
33+
:context="prop.node"
34+
/>
2635
</div>
27-
<q-space v-if="isFeatureNode(prop.node)"/>
28-
<!-- Features actions -->
29-
<KPanel v-if="isFeatureNode(prop.node)"
30-
:id="`${prop.node.label}-feature-actions`"
31-
:content="featureActions"
32-
:context="prop.node"
36+
</template>
37+
<!-- Feature properties rendering -->
38+
<template v-slot:default-body="prop">
39+
<KView v-if="isFeaturePropertiesNode(prop.node)"
40+
class="q-pa-md full-width"
41+
:values="prop.node"
42+
:schema="schema"
43+
:separators="true"
3344
/>
34-
</div>
35-
</template>
36-
<!-- Feature properties rendering -->
37-
<template v-slot:default-body="prop">
38-
<KView v-if="isFeaturePropertiesNode(prop.node)"
39-
class="q-pa-md full-width"
40-
:values="prop.node"
41-
:schema="schema"
42-
:separators="true"
43-
/>
44-
</template>
45-
</q-tree>
45+
</template>
46+
</q-tree>
47+
<KModal
48+
id="style-editor-modal"
49+
:title="styleEditorTitle"
50+
:buttons="[]"
51+
v-model="isFeatureStyleEdited"
52+
>
53+
<KStyleEditor :edit-name="false" :allowed-styles="[editedFeatureType]" :style="editedFeatureStyle" @cancel="onCancelFeatureStyle" @apply="onApplyFeatureStyle" />
54+
</KModal>
55+
</div>
4656
</template>
4757

4858
<script setup>
@@ -54,9 +64,11 @@ import bbox from '@turf/bbox'
5464
import { Store, i18n } from '../../../../core/client'
5565
import { KView } from '../../../../core/client/components'
5666
import KLayerItem from '../catalog/KLayerItem.vue'
67+
import KStyleEditor from '../styles/KStyleEditor.vue'
5768
import { useCurrentActivity } from '../../composables/activity.js'
5869
import { getFeatureId, getFeatureLabel } from '../../utils/utils.js'
5970
import { isLayerDataEditable } from '../../utils/utils.layers.js'
71+
import { getFeatureStyleType } from '../../utils/utils.features.js'
6072
import { generatePropertiesSchema } from '../../utils/utils.schema.js'
6173
6274
// Props
@@ -73,8 +85,17 @@ const router = useRouter()
7385
const { CurrentActivity } = useCurrentActivity()
7486
const expandedNodes = ref([props.item.layer._id])
7587
const editedFeatures = ref([])
88+
const editedFeature = ref(null)
89+
const editedFeatureType = ref(null)
90+
const editedFeatureStyle = ref(null)
7691
7792
// Computed
93+
const isFeatureStyleEdited = computed(() => {
94+
return !_.isNil(editedFeatureStyle.value)
95+
})
96+
const styleEditorTitle = computed(() => {
97+
return (editedFeature.value ? getFeatureLabel(editedFeature.value, props.item.layer) : '')
98+
})
7899
const layerActions = computed(() => {
79100
return [{
80101
id: 'layer-actions',
@@ -134,6 +155,12 @@ const featureActions = computed(() => {
134155
icon: 'las la-address-card',
135156
handler: editSelectedFeatureProperties,
136157
visible: isLayerDataEditable(props.item.layer) && _.get(props.item.layer, 'schema.content')
158+
}, {
159+
id: 'edit-style-selected-feature',
160+
label: 'KSelectedLayerFeatures.EDIT_FEATURE_STYLE_LABEL',
161+
icon: 'las la-paint-brush',
162+
handler: editSelectedFeatureStyle,
163+
visible: isLayerDataEditable(props.item.layer)
137164
}, {
138165
id: 'reset-style-selected-feature',
139166
label: 'KSelectedLayerFeatures.RESET_FEATURE_STYLE_LABEL',
@@ -259,11 +286,25 @@ function editSelectedFeatureProperties (feature) {
259286
})
260287
})
261288
}
262-
function resetSelectedFeaturesStyle () {
263-
CurrentActivity.value.editFeaturesStyle({ type: 'FeatureCollection', features: props.item.features.map(feature => Object.assign(feature, { style: {} })) }, props.item.layer)
289+
function editSelectedFeatureStyle (feature) {
290+
editedFeature.value = feature
291+
editedFeatureType.value = getFeatureStyleType(feature)
292+
editedFeatureStyle.value = { [editedFeatureType.value]: _.get(feature, 'style', {}) }
293+
}
294+
function onCancelFeatureStyle () {
295+
editedFeature.value = null
296+
editedFeatureType.value = null
297+
editedFeatureStyle.value = null
298+
}
299+
async function onApplyFeatureStyle (style) {
300+
await CurrentActivity.value.editFeaturesStyle(Object.assign(editedFeature.value, { style: style[editedFeatureType.value] }), props.item.layer)
301+
onCancelFeatureStyle()
302+
}
303+
async function resetSelectedFeaturesStyle () {
304+
await CurrentActivity.value.editFeaturesStyle({ type: 'FeatureCollection', features: props.item.features.map(feature => Object.assign(feature, { style: {} })) }, props.item.layer)
264305
}
265-
function resetSelectedFeatureStyle (feature) {
266-
CurrentActivity.value.editFeaturesStyle(Object.assign(feature, { style: {} }), props.item.layer)
306+
async function resetSelectedFeatureStyle (feature) {
307+
await CurrentActivity.value.editFeaturesStyle(Object.assign(feature, { style: {} }), props.item.layer)
267308
}
268309
function removeSelectedFeatures () {
269310
Dialog.create({

map/client/i18n/map_en.json

+1
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@
531531
"ZOOM_TO_FEATURE_LABEL": "Zoom to feature",
532532
"EDIT_FEATURE_LABEL": "Edit feature",
533533
"EDIT_FEATURE_PROPERTIES_LABEL": "Edit feature properties",
534+
"EDIT_FEATURE_STYLE_LABEL": "Edit feature style",
534535
"RESET_FEATURE_STYLE_LABEL": "Reset feature style",
535536
"REMOVE_FEATURE_LABEL": "Remove feature",
536537
"REMOVE_FEATURE_DIALOG_TITLE": "Remove this feature ?",

map/client/i18n/map_fr.json

+1
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@
530530
"ZOOM_TO_FEATURE_LABEL": "Zoomer sur l'élément",
531531
"EDIT_FEATURE_LABEL": "Editer l'élément",
532532
"EDIT_FEATURE_PROPERTIES_LABEL": "Editer les propriétés de l'élément",
533+
"EDIT_FEATURE_STYLE_LABEL": "Editer le style",
533534
"RESET_FEATURE_STYLE_LABEL": "Réinitialiser le style",
534535
"REMOVE_FEATURE_LABEL": "Supprimer l'élément",
535536
"REMOVE_FEATURE_DIALOG_TITLE": "Supprimer l'élément ?",

0 commit comments

Comments
 (0)