Skip to content

Commit 6ae067b

Browse files
committed
wip: create a style manager (#1072)
1 parent 58e6233 commit 6ae067b

File tree

5 files changed

+144
-40
lines changed

5 files changed

+144
-40
lines changed

map/client/components/styles/KStyleEditor.vue

+12-6
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
<KStyleProperty v-model="style.point.color" :name="$t('KStyleEditor.COLOR')" type="color" />
2626
<KStyleProperty v-model="style.point.size" :name="$t('KStyleEditor.SIZE')" type="size" />
2727
<KStyleProperty v-model="style.point.shape" :name="$t('KStyleEditor.SHAPE')" type="shape" />
28-
<KStyleProperty v-model="style.point.icon.classes" :name="$t('KStyleEditor.ICON')" type="icon" />
29-
<KStyleProperty v-model="style.point.icon.size" :name="$t('KStyleEditor.ICON_SIZE')" type="size" :min="12" :max="24" />
28+
<KStyleProperty v-if="!is3D" v-model="style.point.icon.classes" :name="$t('KStyleEditor.ICON')" type="icon" />
29+
<KStyleProperty v-if="!is3D" v-model="style.point.icon.size" :name="$t('KStyleEditor.ICON_SIZE')" type="size" :min="12" :max="24" />
3030
</q-list>
3131
</q-expansion-item>
3232

@@ -82,14 +82,15 @@
8282
</template>
8383

8484
<script setup>
85-
8685
import { ref, computed } from 'vue'
86+
import _ from 'lodash'
8787
import KStyleProperty from './KStyleProperty.vue'
8888
import KStylePreview from './KStylePreview.vue'
89-
import { DefaultStyle } from '../../utils/index.js'
90-
import _ from 'lodash'
9189
import KPanel from '../../../../core/client/components/KPanel.vue'
90+
import { DefaultStyle } from '../../utils/index.js'
91+
import { useCurrentActivity } from '../../composables/activity.js'
9292
93+
// Props
9394
const props = defineProps({
9495
title: {
9596
type: String,
@@ -109,13 +110,17 @@ const props = defineProps({
109110
}
110111
})
111112
113+
// Emits
112114
const emit = defineEmits([
113115
'cancel',
114116
'apply'
115117
])
116118
119+
// Data
117120
const style = ref(_.assign({}, _.pick(DefaultStyle, ['point', 'line', 'polygon']), { name: '' }, props.style))
121+
const { CurrentActivity } = useCurrentActivity()
118122
123+
// Computed
119124
const buttons = computed(() => {
120125
if (props.buttons !== null) return props.buttons
121126
return [
@@ -139,9 +144,10 @@ const buttons = computed(() => {
139144
]
140145
})
141146
const is3D = computed(() => {
142-
return this.kActivity.is3D()
147+
return CurrentActivity.value.is3D()
143148
})
144149
150+
// Functions
145151
function getStyle () {
146152
return style.value
147153
}
+115-34
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,61 @@
11
<template>
2-
<div class="column">
3-
<div class="row justify-center">
4-
5-
<q-tab-panels v-model="viewMode" animated style="width: 100%">
2+
<div>
3+
<div id="style-manager-header" class="q-px-md q-mt-md" v-if="title || (toolbar && toolbar.length)">
4+
<div v-if="title" class="ellipsis text-h6">
5+
{{ $tie(title) }}
6+
</div>
7+
<KPanel
8+
id="style-manager-toolbar"
9+
:content="toolbar"
10+
v-bind:class="{ 'q-gutter-x-sm' : $q.screen.gt.xs, 'q-gutter-x-xs': $q.screen.lt.sm }"
11+
/>
12+
<QSeparator inset />
13+
</div>
14+
<div id="style-manager-content">
15+
<q-tab-panels v-model="viewMode" animated>
616
<q-tab-panel name="list">
717
<KGrid
8-
service="styles"
9-
:append-items="true"
10-
:base-query="baseQuery"
11-
:filter-query="filterQuery"
12-
class="fit"
13-
:renderer="{
14-
component: 'collection/KItem',
15-
actions: [
16-
{
17-
id: 'edit-style',
18-
icon: 'las la-edit',
19-
tooltip: 'KStyleManager.EDIT',
20-
scope: 'header',
21-
handler: editStyle
22-
},
23-
{
24-
id: 'delete-style',
25-
icon: 'las la-trash',
26-
tooltip: 'KStyleManager.DELETE',
27-
scope: 'footer',
28-
handler: { name: 'removeItem', params: ['confirm'] }
29-
},
30-
],
31-
class: 'col-12'
32-
}"
18+
service="styles"
19+
:append-items="true"
20+
:base-query="baseQuery"
21+
:filter-query="filterQuery"
22+
class="fit"
23+
:renderer="{
24+
component: 'styles/KStylePreviewItem',
25+
options: {
26+
avatar: false
27+
},
28+
actions: [
29+
{
30+
id: 'apply-to-selection',
31+
icon: 'las la-object-ungroup',
32+
tooltip: 'KStyleManager.APPLY_TO_SELECTION',
33+
scope: 'header',
34+
handler: applyToSelection
35+
},
36+
{
37+
id: 'edit-style',
38+
icon: 'las la-edit',
39+
tooltip: 'KStyleManager.EDIT',
40+
scope: 'header',
41+
handler: editStyle
42+
},
43+
{
44+
id: 'delete-style',
45+
icon: 'las la-trash',
46+
tooltip: 'KStyleManager.DELETE',
47+
scope: 'footer',
48+
handler: { name: 'removeItem', params: ['confirm'] }
49+
},
50+
],
51+
class: 'col-12'
52+
}"
3353
/>
3454
</q-tab-panel>
3555
<q-tab-panel name="edit">
36-
<k-style-editor/>
56+
<KStyleEditor ref="styleEditor" :style="style" @cancel="onCancel" @apply="onApply" />
3757
</q-tab-panel>
3858
</q-tab-panels>
39-
4059
</div>
4160
</div>
4261
</template>
@@ -45,12 +64,26 @@
4564
import { computed, ref } from 'vue'
4665
import _ from 'lodash'
4766
import { KGrid } from '../../../../core/client/components'
48-
import { Store } from '@kalisio/kdk/core.client'
67+
import { Store, api } from '@kalisio/kdk/core.client'
4968
import KStyleEditor from './KStyleEditor.vue'
69+
import { useCurrentActivity } from '../../composables/activity.js'
70+
import { isLayerStyleEditable } from '../../utils/utils.layers.js'
71+
import { editFeaturesStyle } from '../../utils/utils.features.js'
72+
73+
// Props
74+
defineProps({
75+
title: {
76+
type: String,
77+
default: ''
78+
}
79+
})
5080
5181
// Data
5282
const filter = Store.get('filter')
83+
const styleEditor = ref(null)
84+
const style = ref(null)
5385
const viewMode = ref('list')
86+
const { getSelectedFeaturesByLayer } = useCurrentActivity()
5487
5588
// Computed
5689
const baseQuery = computed(() => {
@@ -63,10 +96,58 @@ const filterQuery = computed(() => {
6396
// Filter the objects against the group
6497
return query
6598
})
99+
const toolbar = computed(() => {
100+
if (viewMode.value === 'edit') return []
101+
return [
102+
{
103+
component: 'collection/KSorter',
104+
id: 'style-manager-sorter-options',
105+
tooltip: 'KStyleManager.SORT',
106+
options: [
107+
{ icon: 'las la-sort-alpha-down', value: { field: 'name', order: 1 }, default: true },
108+
{ icon: 'las la-sort-alpha-up', value: { field: 'name', order: -1 } },
109+
{ icon: 'kdk:clockwise.png', value: { field: 'updatedAt', order: 1 } },
110+
{ icon: 'kdk:anticlockwise.png', value: { field: 'updatedAt', order: -1 } }
111+
]
112+
},
113+
{ component: 'collection/KFilter', style: 'max-width: 200px;' },
114+
{ component: 'QSpace' },
115+
{
116+
id: 'add-layer-category',
117+
icon: 'las la-plus-circle',
118+
tooltip: 'KStyleManager.CREATE_STYLE',
119+
size: '1rem',
120+
handler: () => { editStyle() }
121+
}
122+
]
123+
})
66124
67-
function editStyle (style) {
68-
console.log(style)
125+
// Functions
126+
function applyToSelection (styleToApply) {
127+
const type = { Point: 'point', LineString: 'line', Polygon: 'polygon' }
128+
_.forEach(getSelectedFeaturesByLayer(), layer => {
129+
if (isLayerStyleEditable(layer.layer)) {
130+
_.forEach(layer.features, f => { f.style = _.get(styleToApply, ['item', _.get(type, f.geometry.type, 'point')], null) })
131+
editFeaturesStyle({ type: 'FeatureCollection', features: layer.features }, layer.layer)
132+
}
133+
})
134+
}
135+
function editStyle (styleToEdit) {
69136
viewMode.value = 'edit'
137+
style.value = _.get(styleToEdit, 'item', null)
138+
}
139+
function onApply (style) {
140+
const service = api.getService('styles')
141+
if (style._id) {
142+
service.patch(style._id, style)
143+
} else {
144+
service.create(style)
145+
}
146+
viewMode.value = 'list'
147+
}
148+
149+
function onCancel () {
150+
viewMode.value = 'list'
70151
}
71152
72153
</script>

map/client/i18n/map_en.json

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"DISPLAY_POSITION": "Display the coordinates",
8181
"DISPLAY_LEGEND": "Display legend",
8282
"DISPLAY_SELECTION": "Display selection",
83+
"DISPLAY_STYLE_MANAGER": "Display style manager",
8384
"HIDE_LEGEND": "Hide legend",
8485
"SEARCH_LOCATION": "Search a location",
8586
"ADD_VIEW": "Add view",
@@ -748,6 +749,7 @@
748749
},
749750
"KStyleManager": {
750751
"TITLE": "Style manager",
752+
"APPLY_TO_SELECTION": "Apply style to selection",
751753
"EDIT": "Edit style",
752754
"DELETE": "Delete style",
753755
"SORT": "Sort styles",

map/client/i18n/map_fr.json

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"DISPLAY_POSITION": "Afficher les coordonnées",
8181
"DISPLAY_LEGEND": "Afficher la légende",
8282
"DISPLAY_SELECTION": "Afficher la sélection",
83+
"DISPLAY_STYLE_MANAGER": "Afficher le gestionnaire de style",
8384
"HIDE_LEGEND": "Masquer la légende",
8485
"SEARCH_LOCATION": "Rechercher un lieu",
8586
"ADD_VIEW": "Ajouter une vue",
@@ -752,6 +753,7 @@
752753
},
753754
"KStyleManager": {
754755
"TITLE": "Gestionnaire de styles",
756+
"APPLY_TO_SELECTION": "Appliquer le style à la sélection",
755757
"EDIT": "Modifier le style",
756758
"DELETE": "Supprimer le style",
757759
"SORT": "Trier les styles",

map/client/utils/utils.features.js

+13
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,19 @@ export async function editFeaturesProperties(geoJson, layer) {
483483
return (geoJson.type === 'FeatureCollection' ? Object.assign(geoJson, { features: updatedFeatures }) : updatedFeatures)
484484
}
485485

486+
export async function editFeaturesStyle(geoJson, layer) {
487+
const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
488+
const updatedFeatures = []
489+
for (let i = 0; i < features.length; i++) {
490+
const feature = features[i]
491+
if (feature._id) {
492+
const updatedFeature = await api.getService(layer.service).patch(feature._id, _.pick(feature, ['style']))
493+
updatedFeatures.push(updatedFeature)
494+
}
495+
}
496+
return (geoJson.type === 'FeatureCollection' ? Object.assign(geoJson, { features: updatedFeatures }) : updatedFeatures)
497+
}
498+
486499
export async function removeFeatures(geoJson, layer) {
487500
// Remove all features of a given layer
488501
if (!geoJson) {

0 commit comments

Comments
 (0)