@vcmap/ui 5.0.0-rc.26 → 5.0.0-rc.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/buildCesium.js +7 -0
- package/config/dev.config.json +4 -0
- package/dist/assets/cesium/ThirdParty/Workers/basis_transcoder.js +21 -0
- package/dist/assets/cesium/ThirdParty/Workers/draco_decoder_nodejs.js +117 -0
- package/dist/assets/cesium/ThirdParty/Workers/package.json +1 -0
- package/dist/assets/cesium/ThirdParty/Workers/pako_deflate.min.js +2 -0
- package/dist/assets/cesium/ThirdParty/Workers/pako_inflate.min.js +2 -0
- package/dist/assets/cesium/ThirdParty/Workers/z-worker-pako.js +1 -0
- package/dist/assets/cesium/ThirdParty/basis_transcoder.wasm +0 -0
- package/dist/assets/cesium/ThirdParty/draco_decoder.wasm +0 -0
- package/dist/assets/cesium/ThirdParty/google-earth-dbroot-parser.js +8337 -0
- package/dist/assets/{cesium.305b7c.js → cesium.82fdbe.js} +4 -4
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core.f3d6d4.js → core.df069a.js} +2 -2
- package/dist/assets/core.js +1 -1
- package/dist/assets/index-1cff371d.js +1 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/style/icon-marker-blue.534e37.png +0 -0
- package/dist/assets/style/icon-marker-green.0b6a92.png +0 -0
- package/dist/assets/style/icon-marker-o-blue.7b6d62.png +0 -0
- package/dist/assets/style/icon-marker-o-green.c863c0.png +0 -0
- package/dist/assets/style/icon-marker-o-red.93ff58.png +0 -0
- package/dist/assets/style/icon-marker-o.036477.png +0 -0
- package/dist/assets/style/icon-marker-red.313d03.png +0 -0
- package/dist/assets/style/icon-marker.70960f.png +0 -0
- package/dist/assets/style/icon-pin-blue.7be369.png +0 -0
- package/dist/assets/style/icon-pin-green.cbb935.png +0 -0
- package/dist/assets/style/icon-pin-red.3f25b2.png +0 -0
- package/dist/assets/style/icon-pin.b7ce77.png +0 -0
- package/dist/assets/{ui.74022f.css → ui.3ed7ff.css} +2 -2
- package/dist/assets/ui.3ed7ff.js +14763 -0
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +2 -2
- package/dist/assets/{vuetify.30486f.js → vuetify.614278.js} +1 -1
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -1
- package/index.js +17 -1
- package/package.json +1 -1
- package/plugins/@vcmap/create-link/index.js +8 -8
- package/plugins/@vcmap-show-case/collection-manager-example/index.js +6 -1
- package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +36 -8
- package/plugins/@vcmap-show-case/form-inputs-example/exampleActions.js +0 -19
- package/plugins/@vcmap-show-case/form-inputs-example/index.js +1 -2
- package/plugins/@vcmap-show-case/style-input-example/README.md +4 -0
- package/plugins/@vcmap-show-case/style-input-example/index.js +42 -0
- package/plugins/@vcmap-show-case/style-input-example/package.json +5 -0
- package/plugins/@vcmap-show-case/style-input-example/styleExample.vue +191 -0
- package/plugins/@vcmap-show-case/window-tester/WindowExample.vue +12 -13
- package/plugins/@vcmap-show-case/window-tester/windowExampleToggleChild.vue +44 -0
- package/public/assets/style/icon-marker-blue.png +0 -0
- package/public/assets/style/icon-marker-green.png +0 -0
- package/public/assets/style/icon-marker-o-blue.png +0 -0
- package/public/assets/style/icon-marker-o-green.png +0 -0
- package/public/assets/style/icon-marker-o-red.png +0 -0
- package/public/assets/style/icon-marker-o.png +0 -0
- package/public/assets/style/icon-marker-red.png +0 -0
- package/public/assets/style/icon-marker.png +0 -0
- package/public/assets/style/icon-pin-blue.png +0 -0
- package/public/assets/style/icon-pin-green.png +0 -0
- package/public/assets/style/icon-pin-red.png +0 -0
- package/public/assets/style/icon-pin.png +0 -0
- package/src/actions/actionHelper.js +1 -0
- package/src/application/VcsApp.vue +7 -1
- package/src/components/buttons/VcsActionButtonList.vue +1 -0
- package/src/components/form-inputs-controls/VcsCheckbox.vue +3 -2
- package/src/components/form-inputs-controls/VcsFormSection.vue +59 -9
- package/src/components/form-inputs-controls/VcsLabel.vue +10 -0
- package/src/components/form-inputs-controls/VcsRadioGrid.vue +175 -0
- package/src/components/form-inputs-controls/VcsSelect.vue +3 -0
- package/src/components/form-inputs-controls/VcsTextField.vue +12 -0
- package/src/components/icons/+all.js +4 -0
- package/src/components/icons/EditVerticesIcon.vue +39 -0
- package/src/components/lists/VcsActionList.vue +2 -0
- package/src/components/style/MenuWrapper.vue +138 -0
- package/src/components/style/VcsFillMenu.vue +61 -0
- package/src/components/style/VcsFillSelector.vue +45 -0
- package/src/components/style/VcsImageMenu.vue +84 -0
- package/src/components/style/VcsImageSelector.vue +609 -0
- package/src/components/style/VcsStrokeMenu.vue +73 -0
- package/src/components/style/VcsStrokeSelector.vue +87 -0
- package/src/components/style/VcsTextMenu.vue +81 -0
- package/src/components/style/VcsTextSelector.vue +271 -0
- package/src/components/style/VcsVectorStyleComponent.vue +119 -0
- package/src/components/style/composables.js +84 -0
- package/src/contentTree/contentTreeCollection.js +1 -0
- package/src/i18n/de.js +51 -17
- package/src/i18n/en.js +56 -22
- package/src/legend/vcsLegend.vue +7 -5
- package/src/manager/collectionManager/CollectionComponent.vue +9 -17
- package/src/manager/collectionManager/CollectionComponentList.vue +22 -9
- package/src/manager/collectionManager/CollectionManager.vue +20 -1
- package/src/manager/collectionManager/collectionComponent.js +11 -0
- package/src/manager/window/WindowComponent.vue +2 -1
- package/src/manager/window/WindowManager.vue +23 -9
- package/src/manager/window/windowHelper.js +76 -4
- package/src/manager/window/windowManager.js +38 -6
- package/src/vcsUiApp.js +1 -0
- package/dist/assets/index-f94d5be3.js +0 -1
- package/dist/assets/ui.74022f.js +0 -13466
- /package/dist/assets/{ol.39cc05.js → ol.90a5d0.js} +0 -0
- /package/dist/assets/{vue.9b8c6e.js → vue.537ff3.js} +0 -0
- /package/dist/assets/{vuetify.30486f.css → vuetify.614278.css} +0 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
<template>
|
2
|
+
<v-sheet>
|
3
|
+
<v-container class="px-1 py-0">
|
4
|
+
<v-row no-gutters>
|
5
|
+
<v-col>
|
6
|
+
<VcsLabel html-for="draw-stroke-width">
|
7
|
+
{{ $t('components.style.lineWidth') }}
|
8
|
+
</VcsLabel>
|
9
|
+
</v-col>
|
10
|
+
<v-col cols="3">
|
11
|
+
<VcsTextField
|
12
|
+
id="draw-stroke-width"
|
13
|
+
v-model.number="width"
|
14
|
+
type="number"
|
15
|
+
unit="px"
|
16
|
+
:disabled="!value"
|
17
|
+
/>
|
18
|
+
</v-col>
|
19
|
+
</v-row>
|
20
|
+
</v-container>
|
21
|
+
<v-color-picker
|
22
|
+
:value="rgbaObject"
|
23
|
+
@input="updateColor"
|
24
|
+
mode="rgba"
|
25
|
+
:hide-mode-switch="true"
|
26
|
+
:disabled="!value"
|
27
|
+
/>
|
28
|
+
</v-sheet>
|
29
|
+
</template>
|
30
|
+
|
31
|
+
<script>
|
32
|
+
import { computed } from 'vue';
|
33
|
+
import { VSheet, VColorPicker, VContainer, VRow, VCol } from 'vuetify/lib';
|
34
|
+
import { VcsLabel, VcsTextField } from '@vcmap/ui';
|
35
|
+
import { useColorObject } from './composables.js';
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @description Allows to model a JSON representation of ol/Stroke vector style with a vuetify VColorPicker.
|
39
|
+
* @vue-prop {import("ol/style/Stroke").Options} value - The Stroke Options
|
40
|
+
*/
|
41
|
+
export default {
|
42
|
+
name: 'VcsFillSelector',
|
43
|
+
components: {
|
44
|
+
VSheet,
|
45
|
+
VColorPicker,
|
46
|
+
VContainer,
|
47
|
+
VRow,
|
48
|
+
VCol,
|
49
|
+
VcsLabel,
|
50
|
+
VcsTextField,
|
51
|
+
},
|
52
|
+
props: {
|
53
|
+
value: {
|
54
|
+
type: Object,
|
55
|
+
default: undefined,
|
56
|
+
},
|
57
|
+
},
|
58
|
+
setup(props, { emit }) {
|
59
|
+
return {
|
60
|
+
rgbaObject: useColorObject(() => props.value?.color),
|
61
|
+
width: computed({
|
62
|
+
get() {
|
63
|
+
return props.value?.width;
|
64
|
+
},
|
65
|
+
set(value) {
|
66
|
+
if (value > 0 && value !== props.value?.width) {
|
67
|
+
const stroke = {
|
68
|
+
width: value,
|
69
|
+
};
|
70
|
+
if (props.value?.color) {
|
71
|
+
stroke.color = [...props.value.color];
|
72
|
+
}
|
73
|
+
emit('input', stroke);
|
74
|
+
}
|
75
|
+
},
|
76
|
+
}),
|
77
|
+
updateColor(rgba) {
|
78
|
+
const stroke = {
|
79
|
+
color: [rgba.r, rgba.g, rgba.b, rgba.a],
|
80
|
+
width: props.value?.width,
|
81
|
+
};
|
82
|
+
emit('input', stroke);
|
83
|
+
},
|
84
|
+
};
|
85
|
+
},
|
86
|
+
};
|
87
|
+
</script>
|
@@ -0,0 +1,81 @@
|
|
1
|
+
<template>
|
2
|
+
<MenuWrapper
|
3
|
+
v-bind="{ value, valueDefault }"
|
4
|
+
:value-fallback="fallbackStyle"
|
5
|
+
v-on="$listeners"
|
6
|
+
name="components.style.text"
|
7
|
+
>
|
8
|
+
<template #preview>
|
9
|
+
<div v-if="value" class="d-flex justify-center align-center">
|
10
|
+
<span id="text-preview">T</span>
|
11
|
+
</div>
|
12
|
+
</template>
|
13
|
+
<template #content>
|
14
|
+
<VcsTextSelector v-bind="{ value, valueDefault }" v-on="$listeners" />
|
15
|
+
</template>
|
16
|
+
</MenuWrapper>
|
17
|
+
</template>
|
18
|
+
|
19
|
+
<script>
|
20
|
+
import { computed } from 'vue';
|
21
|
+
import { VcsTextSelector } from '@vcmap/ui';
|
22
|
+
import MenuWrapper from './MenuWrapper.vue';
|
23
|
+
import { rgbaObjectToString, useColorObject } from './composables.js';
|
24
|
+
|
25
|
+
export const fallbackStyle = {
|
26
|
+
font: '10px Arial, Helvetica, sans-serif',
|
27
|
+
fill: { color: [0, 0, 0, 1] },
|
28
|
+
stroke: { color: [255, 255, 255, 1], width: 2 },
|
29
|
+
offsetX: 0,
|
30
|
+
offsetY: 0,
|
31
|
+
};
|
32
|
+
|
33
|
+
/**
|
34
|
+
* @description A wrapper for the VcsTextSelector, that has a small shape/icon preview and a menu that pops up when clicking the preview, containing the text style selector.
|
35
|
+
* @vue-prop {import("ol/style/Text").Options} value - The ol Text style options
|
36
|
+
* @vue-prop {import("ol/style/Text").Options} valueDefault - The default ol Text style options
|
37
|
+
*/
|
38
|
+
export default {
|
39
|
+
name: 'VcsTextMenu',
|
40
|
+
components: {
|
41
|
+
MenuWrapper,
|
42
|
+
VcsTextSelector,
|
43
|
+
},
|
44
|
+
props: {
|
45
|
+
value: {
|
46
|
+
type: Object,
|
47
|
+
default: undefined,
|
48
|
+
},
|
49
|
+
valueDefault: {
|
50
|
+
type: Object,
|
51
|
+
default: undefined,
|
52
|
+
},
|
53
|
+
},
|
54
|
+
setup(props) {
|
55
|
+
const fillColorObject = useColorObject(() => props.value?.fill?.color);
|
56
|
+
const strokeColorObject = useColorObject(
|
57
|
+
() => props.value?.stroke?.color,
|
58
|
+
);
|
59
|
+
|
60
|
+
return {
|
61
|
+
strokeColor: computed(() =>
|
62
|
+
rgbaObjectToString(strokeColorObject.value),
|
63
|
+
),
|
64
|
+
fillColor: computed(() => rgbaObjectToString(fillColorObject.value)),
|
65
|
+
fontStyle: computed(() => props.value?.font),
|
66
|
+
fallbackStyle,
|
67
|
+
};
|
68
|
+
},
|
69
|
+
};
|
70
|
+
</script>
|
71
|
+
|
72
|
+
<style>
|
73
|
+
#text-preview {
|
74
|
+
font: v-bind(fontStyle) !important;
|
75
|
+
font-size: 20px !important;
|
76
|
+
-webkit-text-stroke-color: v-bind(strokeColor);
|
77
|
+
-webkit-text-stroke-width: 1px;
|
78
|
+
-webkit-text-fill-color: v-bind(fillColor);
|
79
|
+
line-height: 1;
|
80
|
+
}
|
81
|
+
</style>
|
@@ -0,0 +1,271 @@
|
|
1
|
+
<template>
|
2
|
+
<v-sheet>
|
3
|
+
<v-container class="px-1 py-0">
|
4
|
+
<v-row no-gutters>
|
5
|
+
<v-col>
|
6
|
+
<VcsTextField
|
7
|
+
v-model="selectedText"
|
8
|
+
:placeholder="$t('components.style.enterText')"
|
9
|
+
/>
|
10
|
+
</v-col>
|
11
|
+
</v-row>
|
12
|
+
<v-row no-gutters>
|
13
|
+
<v-col>
|
14
|
+
<VcsSelect
|
15
|
+
:items="
|
16
|
+
Object.keys(fonts).map((font) => ({
|
17
|
+
text: font,
|
18
|
+
value: fonts[font],
|
19
|
+
}))
|
20
|
+
"
|
21
|
+
v-model="fontFamily"
|
22
|
+
>
|
23
|
+
<template #item="{ item }">
|
24
|
+
<span :style="`font-family: ${item.value} !important`">{{
|
25
|
+
item.text
|
26
|
+
}}</span>
|
27
|
+
</template>
|
28
|
+
</VcsSelect>
|
29
|
+
</v-col>
|
30
|
+
<v-col cols="2">
|
31
|
+
<VcsTextField
|
32
|
+
type="number"
|
33
|
+
unit="px"
|
34
|
+
v-model="fontSize"
|
35
|
+
:rules="[(v) => (!!v && v > 0) || 'components.style.notValid']"
|
36
|
+
/>
|
37
|
+
</v-col>
|
38
|
+
</v-row>
|
39
|
+
<div class="px-1 py-3">
|
40
|
+
<VcsButton
|
41
|
+
:active="isBold"
|
42
|
+
@click="isBold = !isBold"
|
43
|
+
class="pr-1"
|
44
|
+
tooltip="components.style.bold"
|
45
|
+
>
|
46
|
+
{{ $t('components.style.bold') }}
|
47
|
+
</VcsButton>
|
48
|
+
<VcsButton
|
49
|
+
:active="isItalic"
|
50
|
+
@click="isItalic = !isItalic"
|
51
|
+
class="px-2"
|
52
|
+
tooltip="components.style.italic"
|
53
|
+
>
|
54
|
+
{{ $t('components.style.italic') }}
|
55
|
+
</VcsButton>
|
56
|
+
</div>
|
57
|
+
<VcsStrokeMenu
|
58
|
+
v-model="selectedStroke"
|
59
|
+
:value-default="valueDefault.stroke"
|
60
|
+
:disabled="!value"
|
61
|
+
/>
|
62
|
+
<VcsFillMenu
|
63
|
+
v-model="selectedFill"
|
64
|
+
:value-default="valueDefault.fill"
|
65
|
+
:disabled="!value"
|
66
|
+
/>
|
67
|
+
<v-row no-gutters>
|
68
|
+
<v-col cols="6">
|
69
|
+
<VcsLabel>{{ $t('components.style.offset') }}</VcsLabel>
|
70
|
+
</v-col>
|
71
|
+
<v-col cols="3">
|
72
|
+
<VcsTextField
|
73
|
+
type="number"
|
74
|
+
v-model.number="selectedOffsetX"
|
75
|
+
tooltip-position="top"
|
76
|
+
prefix="X"
|
77
|
+
unit="px"
|
78
|
+
tooltip="components.style.offsetX"
|
79
|
+
/>
|
80
|
+
</v-col>
|
81
|
+
<v-col cols="3">
|
82
|
+
<VcsTextField
|
83
|
+
type="number"
|
84
|
+
v-model.number="selectedOffsetY"
|
85
|
+
tooltip-position="top"
|
86
|
+
prefix="Y"
|
87
|
+
unit="px"
|
88
|
+
tooltip="components.style.offsetY"
|
89
|
+
/>
|
90
|
+
</v-col>
|
91
|
+
</v-row>
|
92
|
+
</v-container>
|
93
|
+
</v-sheet>
|
94
|
+
</template>
|
95
|
+
|
96
|
+
<script>
|
97
|
+
import { computed } from 'vue';
|
98
|
+
import { VSheet, VContainer, VRow, VCol } from 'vuetify/lib';
|
99
|
+
import {
|
100
|
+
VcsSelect,
|
101
|
+
VcsTextField,
|
102
|
+
VcsButton,
|
103
|
+
VcsStrokeMenu,
|
104
|
+
VcsFillMenu,
|
105
|
+
VcsLabel,
|
106
|
+
} from '@vcmap/ui';
|
107
|
+
import { useSelectedKey } from './composables.js';
|
108
|
+
|
109
|
+
export const fonts = {
|
110
|
+
Georgia: 'Georgia, serif',
|
111
|
+
Palatino: '"Palatino Linotype", "Book Antiqua", Palatino, serif',
|
112
|
+
'Times New Roman': '"Times New Roman", Times, serif',
|
113
|
+
Arial: 'Arial, Helvetica, sans-serif',
|
114
|
+
Impact: 'Impact, Charcoal, sans-serif',
|
115
|
+
'Comic Sans': '"Comic Sans MS", cursive, sans-serif',
|
116
|
+
Trebuchet: '"Trebuchet MS", Helvetica, sans-serif',
|
117
|
+
Verdana: 'Verdana, Geneva, sans-serif',
|
118
|
+
Courier: '"Courier New", Courier, monospace',
|
119
|
+
Lucida: '"Lucida Console", Monaco, monospace',
|
120
|
+
};
|
121
|
+
|
122
|
+
/**
|
123
|
+
* @description Allows to model a JSON representation of ol/style/Text style. It makes use of VcsStrokeMenu and VcsFillMenu.
|
124
|
+
* @vue-prop {import("ol/style/Text").Options} value - The ol Text style options
|
125
|
+
* @vue-prop {import("ol/style/Text").Options} valueDefault - The default ol Text style options
|
126
|
+
*/
|
127
|
+
export default {
|
128
|
+
name: 'VcsTextSelector',
|
129
|
+
components: {
|
130
|
+
VSheet,
|
131
|
+
VContainer,
|
132
|
+
VRow,
|
133
|
+
VCol,
|
134
|
+
VcsSelect,
|
135
|
+
VcsTextField,
|
136
|
+
VcsButton,
|
137
|
+
VcsStrokeMenu,
|
138
|
+
VcsFillMenu,
|
139
|
+
VcsLabel,
|
140
|
+
},
|
141
|
+
props: {
|
142
|
+
value: {
|
143
|
+
type: Object,
|
144
|
+
default: undefined,
|
145
|
+
},
|
146
|
+
valueDefault: {
|
147
|
+
type: Object,
|
148
|
+
required: true,
|
149
|
+
},
|
150
|
+
},
|
151
|
+
setup(props, { emit }) {
|
152
|
+
const font = computed({
|
153
|
+
get() {
|
154
|
+
let fontStyle = {
|
155
|
+
// fontStyle: 'normal',
|
156
|
+
// fontWeight: 'normal',
|
157
|
+
};
|
158
|
+
if (props.value) {
|
159
|
+
const el = document.createElement('span');
|
160
|
+
el.setAttribute('style', `font: ${props.value.font}`);
|
161
|
+
fontStyle = el.style;
|
162
|
+
el.remove();
|
163
|
+
}
|
164
|
+
return fontStyle;
|
165
|
+
},
|
166
|
+
});
|
167
|
+
|
168
|
+
function emitNewFont(key, value) {
|
169
|
+
font.value[key] = value;
|
170
|
+
const newModelObject = JSON.parse(JSON.stringify(props.value));
|
171
|
+
const fontPropertyArray = [
|
172
|
+
font.value.fontStyle,
|
173
|
+
font.value.fontWeight,
|
174
|
+
font.value.fontSize,
|
175
|
+
font.value.fontFamily,
|
176
|
+
];
|
177
|
+
emit(
|
178
|
+
'input',
|
179
|
+
Object.assign(newModelObject, {
|
180
|
+
font: fontPropertyArray
|
181
|
+
.filter((prop) => prop && prop !== 'normal')
|
182
|
+
.join(' '),
|
183
|
+
}),
|
184
|
+
);
|
185
|
+
}
|
186
|
+
|
187
|
+
const fontFamily = computed({
|
188
|
+
get() {
|
189
|
+
return font.value.fontFamily;
|
190
|
+
},
|
191
|
+
set(newFamily) {
|
192
|
+
emitNewFont('fontFamily', newFamily);
|
193
|
+
},
|
194
|
+
});
|
195
|
+
|
196
|
+
const fontSize = computed({
|
197
|
+
get() {
|
198
|
+
return parseInt(font.value.fontSize, 10);
|
199
|
+
},
|
200
|
+
set(newSize) {
|
201
|
+
if (!newSize || newSize < 1) {
|
202
|
+
return;
|
203
|
+
}
|
204
|
+
emitNewFont('fontSize', `${newSize}px`);
|
205
|
+
},
|
206
|
+
});
|
207
|
+
|
208
|
+
const isBold = computed({
|
209
|
+
get() {
|
210
|
+
return font.value.fontWeight === 'bold';
|
211
|
+
},
|
212
|
+
set(newValue) {
|
213
|
+
emitNewFont('fontWeight', newValue ? 'bold' : 'normal');
|
214
|
+
},
|
215
|
+
});
|
216
|
+
const isItalic = computed({
|
217
|
+
get() {
|
218
|
+
return font.value.fontStyle === 'italic';
|
219
|
+
},
|
220
|
+
set(newValue) {
|
221
|
+
emitNewFont('fontStyle', newValue ? 'italic' : 'normal');
|
222
|
+
},
|
223
|
+
});
|
224
|
+
|
225
|
+
const selectedFill = useSelectedKey(
|
226
|
+
() => props.value,
|
227
|
+
'fill',
|
228
|
+
props.valueDefault.fill,
|
229
|
+
emit,
|
230
|
+
);
|
231
|
+
const selectedStroke = useSelectedKey(
|
232
|
+
() => props.value,
|
233
|
+
'stroke',
|
234
|
+
props.valueDefault.stroke,
|
235
|
+
emit,
|
236
|
+
);
|
237
|
+
const selectedOffsetX = useSelectedKey(
|
238
|
+
() => props.value,
|
239
|
+
'offsetX',
|
240
|
+
props.valueDefault.offsetX,
|
241
|
+
emit,
|
242
|
+
);
|
243
|
+
const selectedOffsetY = useSelectedKey(
|
244
|
+
() => props.value,
|
245
|
+
'offsetY',
|
246
|
+
props.valueDefault.offsetY,
|
247
|
+
emit,
|
248
|
+
);
|
249
|
+
const selectedText = useSelectedKey(
|
250
|
+
() => props.value,
|
251
|
+
'text',
|
252
|
+
props.valueDefault.text,
|
253
|
+
emit,
|
254
|
+
);
|
255
|
+
return {
|
256
|
+
fonts,
|
257
|
+
font,
|
258
|
+
fontFamily,
|
259
|
+
fontSize,
|
260
|
+
selectedFill,
|
261
|
+
selectedStroke,
|
262
|
+
emitNewFont,
|
263
|
+
isBold,
|
264
|
+
isItalic,
|
265
|
+
selectedOffsetX,
|
266
|
+
selectedOffsetY,
|
267
|
+
selectedText,
|
268
|
+
};
|
269
|
+
},
|
270
|
+
};
|
271
|
+
</script>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
<template>
|
2
|
+
<v-sheet>
|
3
|
+
<component
|
4
|
+
v-for="key in styleComponents"
|
5
|
+
:key="key"
|
6
|
+
:is="componentMap[key]"
|
7
|
+
:value-default="valueDefault[key]"
|
8
|
+
v-model="selectedKeys[key].value"
|
9
|
+
@input="(value) => $emit(`update:${key}`, value)"
|
10
|
+
v-bind="specificProps[key]"
|
11
|
+
/>
|
12
|
+
</v-sheet>
|
13
|
+
</template>
|
14
|
+
|
15
|
+
<script>
|
16
|
+
import { computed } from 'vue';
|
17
|
+
import {
|
18
|
+
VcsFillMenu,
|
19
|
+
VcsImageMenu,
|
20
|
+
VcsStrokeMenu,
|
21
|
+
VcsTextMenu,
|
22
|
+
} from '@vcmap/ui';
|
23
|
+
import { VSheet } from 'vuetify/lib';
|
24
|
+
import { useSelectedKey } from './composables.js';
|
25
|
+
|
26
|
+
/**
|
27
|
+
* @enum {string}
|
28
|
+
* @property {string} FILL
|
29
|
+
* @property {string} STROKE
|
30
|
+
* @property {string} IMAGE
|
31
|
+
* @property {string} TEXT
|
32
|
+
*/
|
33
|
+
export const VectorStyleMenus = {
|
34
|
+
FILL: 'fill',
|
35
|
+
STROKE: 'stroke',
|
36
|
+
IMAGE: 'image',
|
37
|
+
TEXT: 'text',
|
38
|
+
};
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @enum{string}
|
42
|
+
*/
|
43
|
+
const componentMap = {
|
44
|
+
fill: 'VcsFillMenu',
|
45
|
+
stroke: 'VcsStrokeMenu',
|
46
|
+
image: 'VcsImageMenu',
|
47
|
+
text: 'VcsTextMenu',
|
48
|
+
};
|
49
|
+
|
50
|
+
/**
|
51
|
+
* @description Wraps the style component into a single component so whole @vcmap/core/VectorStyleItemOptions can be modelled.
|
52
|
+
* @vue-prop {import("@vcmap/core").VectorStyleItemOptions} value - The VectorStyleItemOptions that should be modelled.
|
53
|
+
* @vue-prop {import("@vcmap/core").VectorStyleItemOptions} valueDefault - The default VectorStyleItemOptions.
|
54
|
+
* @vue-prop {VectorStyleMenus[]} styleComponents - The style component that should be rendered.
|
55
|
+
* @vue-prop {boolean} [extendedShapeSettings=false] - If true, there are all the input fields needed to create arbitrary ol RegularShapes.
|
56
|
+
* @vue-prop {Array<import("ol/style/Icon").Options>} [iconOptions] - The icon options in the image component too choose from. Scale and opacity are ignored. The defaults are 3 different icon types with 4 different colors.
|
57
|
+
*/
|
58
|
+
export default {
|
59
|
+
name: 'VcsVectorStyleComponent',
|
60
|
+
components: {
|
61
|
+
VcsFillMenu,
|
62
|
+
VcsImageMenu,
|
63
|
+
VcsStrokeMenu,
|
64
|
+
VcsTextMenu,
|
65
|
+
VSheet,
|
66
|
+
},
|
67
|
+
props: {
|
68
|
+
value: {
|
69
|
+
type: Object,
|
70
|
+
default: undefined,
|
71
|
+
},
|
72
|
+
valueDefault: {
|
73
|
+
type: Object,
|
74
|
+
default: undefined,
|
75
|
+
},
|
76
|
+
styleComponents: {
|
77
|
+
type: Array,
|
78
|
+
default: () => Object.values(VectorStyleMenus),
|
79
|
+
validator: (array) =>
|
80
|
+
array.every((component) =>
|
81
|
+
Object.values(VectorStyleMenus).includes(component),
|
82
|
+
),
|
83
|
+
},
|
84
|
+
extendedShapeSettings: {
|
85
|
+
type: Boolean,
|
86
|
+
default: false,
|
87
|
+
},
|
88
|
+
iconOptions: {
|
89
|
+
type: Array,
|
90
|
+
default: undefined,
|
91
|
+
},
|
92
|
+
},
|
93
|
+
setup(props, { emit }) {
|
94
|
+
const selectedKeys = computed(() =>
|
95
|
+
// convert to Object with style prop names as keys and computed props as value to allow v-model.
|
96
|
+
props.styleComponents.reduce((acc, key) => {
|
97
|
+
acc[key] = useSelectedKey(
|
98
|
+
() => props.value,
|
99
|
+
key,
|
100
|
+
props.valueDefault[key],
|
101
|
+
emit,
|
102
|
+
);
|
103
|
+
return acc;
|
104
|
+
}, {}),
|
105
|
+
);
|
106
|
+
const specificProps = computed(() => ({
|
107
|
+
[VectorStyleMenus.IMAGE]: {
|
108
|
+
extendedShapeSettings: props.extendedShapeSettings,
|
109
|
+
iconOptions: props.iconOptions,
|
110
|
+
},
|
111
|
+
}));
|
112
|
+
return {
|
113
|
+
selectedKeys,
|
114
|
+
specificProps,
|
115
|
+
componentMap,
|
116
|
+
};
|
117
|
+
},
|
118
|
+
};
|
119
|
+
</script>
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { computed } from 'vue';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Computes a color object from a color array.
|
5
|
+
* @param {function():Array<number>} colorGetter Getter that returns an array containing rgba values.
|
6
|
+
* @returns {{r: number, g: number, b: number, a: number}} An object with rgba keys.
|
7
|
+
*/
|
8
|
+
export function useColorObject(colorGetter) {
|
9
|
+
return computed(() => {
|
10
|
+
const rgbaArray = colorGetter();
|
11
|
+
if (rgbaArray) {
|
12
|
+
return {
|
13
|
+
r: rgbaArray[0],
|
14
|
+
g: rgbaArray[1],
|
15
|
+
b: rgbaArray[2],
|
16
|
+
a: rgbaArray[3],
|
17
|
+
};
|
18
|
+
} else {
|
19
|
+
return { r: 255, g: 255, b: 255, a: 0 };
|
20
|
+
}
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Checks if a value is in a value range.
|
26
|
+
* @param {number} value Value checked to see if it is in the allowed range.
|
27
|
+
* @param {number[]} range Min and max value
|
28
|
+
* @returns {boolean} If value is between min and max.
|
29
|
+
*/
|
30
|
+
export function between(value, range) {
|
31
|
+
return value >= range[0] && value <= range[1];
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Creates a computed property with a getter and a setter for a specific object property/key of the value prop. If the value prop is an object, this composable allows to pass this computed to an v-model of a sub component. The getter returns the value of the key or, if it is undefined, a default value. The setter merges the passed value with the other object properties of the value prop and emits the whole object as a input event.
|
36
|
+
* @param {function():Object} modelObject Getter for the property that is modelled by the component and should be updated with input event, usually this is the 'value' prop.
|
37
|
+
* @param {string} key The key of the modelObject that should be return on get and updated on set.
|
38
|
+
* @param {*} defaultValue Default value for the key of the modelObject.
|
39
|
+
* @param {function(event: string, ...args: any[]):void} emit The emit function of the component context that is using this composable.
|
40
|
+
* @param {Array<number>} [range] The allowed range of numbers.
|
41
|
+
* @param {Array<number>} [isRequired] If value is required.
|
42
|
+
* @returns {*} The value to the key param if the getter is called.
|
43
|
+
*/
|
44
|
+
export function useSelectedKey(
|
45
|
+
modelObject,
|
46
|
+
key,
|
47
|
+
defaultValue,
|
48
|
+
emit,
|
49
|
+
range,
|
50
|
+
isRequired,
|
51
|
+
) {
|
52
|
+
return computed({
|
53
|
+
get() {
|
54
|
+
if (modelObject()?.[key] === undefined && isRequired) {
|
55
|
+
return defaultValue;
|
56
|
+
}
|
57
|
+
return modelObject()?.[key];
|
58
|
+
},
|
59
|
+
set(value) {
|
60
|
+
if (
|
61
|
+
((value === null || value === undefined) && isRequired) ||
|
62
|
+
(value !== null &&
|
63
|
+
value !== undefined &&
|
64
|
+
range &&
|
65
|
+
!between(value, range))
|
66
|
+
) {
|
67
|
+
return;
|
68
|
+
}
|
69
|
+
const newModelObject = JSON.parse(JSON.stringify(modelObject()));
|
70
|
+
// is needed to get e.g. from square shape to x by setting radius2 from 0 to undefined
|
71
|
+
const newValue = value === '' ? undefined : value;
|
72
|
+
emit('input', Object.assign(newModelObject, { [key]: newValue }));
|
73
|
+
},
|
74
|
+
});
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Creates a string from a color object.
|
79
|
+
* @param {{r: number, g: number, b: number, a: number}} rgbaObject An object with rgba keys.
|
80
|
+
* @returns {string} A string looking like this: rgba(0,0,0,0).
|
81
|
+
*/
|
82
|
+
export function rgbaObjectToString(rgbaObject) {
|
83
|
+
return `rgba(${Object.values(rgbaObject).toString()})`;
|
84
|
+
}
|