@vcmap/ui 5.0.0-rc.29 → 5.0.0-rc.30

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.
Files changed (41) hide show
  1. package/config/dev.config.json +4 -0
  2. package/dist/assets/cesium.js +1 -1
  3. package/dist/assets/{core.74da2a.js → core.b16511.js} +2 -2
  4. package/dist/assets/core.js +1 -1
  5. package/dist/assets/index-c115e3a1.js +1 -0
  6. package/dist/assets/ol.js +1 -1
  7. package/dist/assets/{ui.d3054c.css → ui.ab815e.css} +2 -2
  8. package/dist/assets/{ui.d3054c.js → ui.ab815e.js} +4081 -3460
  9. package/dist/assets/ui.js +1 -1
  10. package/dist/assets/vue.js +2 -2
  11. package/dist/assets/{vuetify.946bd8.js → vuetify.ea3fa8.js} +1 -1
  12. package/dist/assets/vuetify.js +2 -2
  13. package/dist/index.html +1 -1
  14. package/index.js +6 -0
  15. package/package.json +1 -1
  16. package/plugins/@vcmap/search-nominatim/SearchNominatimEditor.vue +90 -0
  17. package/plugins/@vcmap/search-nominatim/index.js +37 -0
  18. package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +37 -1
  19. package/plugins/@vcmap-show-case/form-inputs-example/index.js +3 -0
  20. package/plugins/@vcmap-show-case/form-inputs-example/validation.js +11 -0
  21. package/plugins/@vcmap-show-case/style-input-example/styleExample.vue +0 -1
  22. package/plugins/@vcmap-show-case/vector-properties-example/index.js +40 -0
  23. package/plugins/@vcmap-show-case/vector-properties-example/package.json +5 -0
  24. package/plugins/@vcmap-show-case/vector-properties-example/vectorPropertiesExample.vue +109 -0
  25. package/src/components/form-inputs-controls/VcsChipArrayInput.vue +282 -0
  26. package/src/components/form-inputs-controls/VcsTextField.vue +9 -3
  27. package/src/components/plugins/AbstractConfigEditor.vue +84 -0
  28. package/src/components/style/VcsImageSelector.vue +6 -5
  29. package/src/components/style/VcsTextSelector.vue +1 -1
  30. package/src/components/vector-properties/VcsVectorPropertiesComponent.vue +737 -0
  31. package/src/components/vector-properties/composables.js +93 -0
  32. package/src/i18n/de.js +40 -9
  33. package/src/i18n/en.js +38 -7
  34. package/src/manager/collectionManager/collectionComponent.js +1 -1
  35. package/src/pluginHelper.js +57 -17
  36. package/src/vcsUiApp.js +17 -27
  37. package/dist/assets/index-cb070eff.js +0 -1
  38. /package/dist/assets/{cesium.16590b.js → cesium.eaf7cc.js} +0 -0
  39. /package/dist/assets/{ol.50a512.js → ol.4bbf0f.js} +0 -0
  40. /package/dist/assets/{vue.30740e.js → vue.67e80f.js} +0 -0
  41. /package/dist/assets/{vuetify.946bd8.css → vuetify.ea3fa8.css} +0 -0
@@ -0,0 +1,737 @@
1
+ <template>
2
+ <VcsFormSection
3
+ heading="components.vectorProperties.header"
4
+ :header-actions="[
5
+ {
6
+ name: 'reset',
7
+ title: 'components.style.reset',
8
+ icon: '$vcsReturn',
9
+ callback: () => {
10
+ reset();
11
+ },
12
+ },
13
+ ]"
14
+ >
15
+ <v-container class="px-1 py-0">
16
+ <v-row
17
+ v-if="visibleProperties.has('altitudeMode') && show3DProperties"
18
+ no-gutters
19
+ >
20
+ <v-col>
21
+ <VcsLabel html-for="vp-altitude-mode">{{
22
+ $t('components.vectorProperties.altitudeMode')
23
+ }}</VcsLabel>
24
+ </v-col>
25
+ <v-col>
26
+ <VcsSelect
27
+ id="vp-altitude-mode"
28
+ :items="[
29
+ {
30
+ value: 'clampToGround',
31
+ text: 'components.vectorProperties.clampToGround',
32
+ },
33
+ {
34
+ value: 'absolute',
35
+ text: 'components.vectorProperties.absolute',
36
+ },
37
+ {
38
+ value: 'relativeToGround',
39
+ text: 'components.vectorProperties.relativeToGround',
40
+ },
41
+ ]"
42
+ v-model="altitudeMode"
43
+ dense
44
+ />
45
+ </v-col>
46
+ </v-row>
47
+ <v-row
48
+ v-if="altitudeMode === 'relativeToGround' && show3DProperties"
49
+ no-gutters
50
+ >
51
+ <v-col>
52
+ <VcsLabel html-for="vp-height-above-ground">{{
53
+ $t('components.vectorProperties.heightAboveGround')
54
+ }}</VcsLabel>
55
+ </v-col>
56
+ <v-col>
57
+ <VcsTextField
58
+ id="vp-height-above-ground"
59
+ dense
60
+ v-model.number="heightAboveGround"
61
+ type="number"
62
+ unit="m"
63
+ :placeholder="'heightAboveGround' in value ? '0 m' : ''"
64
+ />
65
+ </v-col>
66
+ </v-row>
67
+ <v-row
68
+ v-if="visibleProperties.has('groundLevel') && show3DProperties"
69
+ no-gutters
70
+ >
71
+ <v-col>
72
+ <VcsLabel html-for="vp-ground-level">{{
73
+ $t('components.vectorProperties.groundLevel')
74
+ }}</VcsLabel>
75
+ </v-col>
76
+ <v-col>
77
+ <VcsTextField
78
+ id="vp-ground-level"
79
+ dense
80
+ v-model.number="groundLevel"
81
+ type="number"
82
+ unit="m"
83
+ :placeholder="'groundLevel' in value ? '0 m' : ''"
84
+ />
85
+ </v-col>
86
+ </v-row>
87
+ <v-row
88
+ v-if="visibleProperties.has('scaleByDistance') && show3DProperties"
89
+ no-gutters
90
+ >
91
+ <v-col>
92
+ <VcsCheckbox
93
+ label="components.vectorProperties.scaleByDistance"
94
+ v-model="hasScaleByDistance"
95
+ />
96
+ </v-col>
97
+ <v-col>
98
+ <v-row no-gutters>
99
+ <v-col v-for="(nearFar, index) in scaleByDistance" :key="index">
100
+ <VcsTextField
101
+ dense
102
+ v-model.number="nearFar.value"
103
+ type="number"
104
+ :unit="index % 2 === 0 ? 'm' : ''"
105
+ :disabled="!hasScaleByDistance"
106
+ :placeholder="
107
+ 'scaleByDistance' in value
108
+ ? index % 2 === 0
109
+ ? `${scaleByDistanceDefault[index]} m`
110
+ : `${scaleByDistanceDefault[index]}`
111
+ : ''
112
+ "
113
+ :rules="[(v) => !isNaN(v) || 'components.validation.required']"
114
+ />
115
+ </v-col>
116
+ </v-row>
117
+ </v-col>
118
+ </v-row>
119
+ <v-row
120
+ v-if="visibleProperties.has('eyeOffset') && show3DProperties"
121
+ no-gutters
122
+ >
123
+ <v-col>
124
+ <VcsCheckbox
125
+ label="components.vectorProperties.eyeOffset"
126
+ v-model="hasEyeOffset"
127
+ />
128
+ </v-col>
129
+ <v-col v-for="(distance, index) in eyeOffset" :key="index" cols="2">
130
+ <VcsTextField
131
+ dense
132
+ v-model.number="distance.value"
133
+ unit="m"
134
+ type="number"
135
+ :disabled="!hasEyeOffset"
136
+ :prefix="dimensionsUpperCase[index]"
137
+ :rules="[(v) => !isNaN(v) || 'components.validation.required']"
138
+ :placeholder="
139
+ 'eyeOffset' in value ? `${eyeOffsetDefault[index]} m` : ''
140
+ "
141
+ />
142
+ </v-col>
143
+ </v-row>
144
+ <v-row v-if="visibleProperties.has('allowPicking')" no-gutters>
145
+ <v-col>
146
+ <VcsCheckbox
147
+ label="components.vectorProperties.allowPicking"
148
+ v-model="allowPicking"
149
+ />
150
+ </v-col>
151
+ </v-row>
152
+ <v-row
153
+ v-if="visibleProperties.has('classificationType') && show3DProperties"
154
+ no-gutters
155
+ >
156
+ <v-col>
157
+ <VcsLabel html-for="vp-classification-type" :dense="true">
158
+ {{ $t('components.vectorProperties.classificationType') }}
159
+ </VcsLabel>
160
+ </v-col>
161
+ <v-col>
162
+ <VcsSelect
163
+ id="vp-classification-type"
164
+ :items="[
165
+ { value: 'none', text: 'components.vectorProperties.none' },
166
+ { value: 'both', text: 'components.vectorProperties.both' },
167
+ {
168
+ value: 'cesium3DTile',
169
+ text: 'components.vectorProperties.cesium3DTile',
170
+ },
171
+ { value: 'terrain', text: 'components.vectorProperties.terrain' },
172
+ ]"
173
+ v-model="classificationType"
174
+ dense
175
+ />
176
+ </v-col>
177
+ </v-row>
178
+ </v-container>
179
+ <v-divider
180
+ v-if="
181
+ [
182
+ 'extrudedHeight',
183
+ 'skirt',
184
+ 'storeysAboveGround',
185
+ 'storeysBelowGround',
186
+ 'storeyHeightsAboveGround',
187
+ 'storeyHeightsBelowGround',
188
+ ].some((prop) => visibleProperties.has(prop)) && show3DProperties
189
+ "
190
+ />
191
+ <v-container class="px-1 py-0" v-if="show3DProperties">
192
+ <v-row
193
+ v-if="
194
+ visibleProperties.has('extrudedHeight') ||
195
+ visibleProperties.has('storeysAboveGround') ||
196
+ visibleProperties.has('storeyHeightsAboveGround')
197
+ "
198
+ no-gutters
199
+ >
200
+ <v-col>
201
+ <VcsLabel>{{
202
+ $t('components.vectorProperties.aboveGround')
203
+ }}</VcsLabel>
204
+ </v-col>
205
+ </v-row>
206
+ <v-row v-if="visibleProperties.has('extrudedHeight')" no-gutters>
207
+ <v-col>
208
+ <VcsLabel html-for="vp-extruded-height" class="px-4">{{
209
+ $t('components.vectorProperties.extrudedHeight')
210
+ }}</VcsLabel>
211
+ </v-col>
212
+ <v-col>
213
+ <VcsTextField
214
+ id="vp-extruded-height"
215
+ dense
216
+ v-model.number="extrudedHeight"
217
+ type="number"
218
+ unit="m"
219
+ :placeholder="'extrudedHeight' in value ? '0 m' : ''"
220
+ :rules="[
221
+ (v) => v >= 0 || isNaN(v) || 'components.validation.notValid',
222
+ ]"
223
+ />
224
+ </v-col>
225
+ </v-row>
226
+ <v-row v-if="visibleProperties.has('storeysAboveGround')" no-gutters>
227
+ <v-col>
228
+ <VcsLabel html-for="vp-storeys-above" class="px-4">{{
229
+ $t('components.vectorProperties.storeys')
230
+ }}</VcsLabel>
231
+ </v-col>
232
+ <v-col>
233
+ <VcsTextField
234
+ id="vp-storeys-above"
235
+ dense
236
+ v-model.number="storeysAboveGround"
237
+ type="number"
238
+ :placeholder="'storeysAboveGround' in value ? '0' : ''"
239
+ :rules="[
240
+ (v) => v >= 0 || isNaN(v) || 'components.validation.notValid',
241
+ ]"
242
+ />
243
+ </v-col>
244
+ </v-row>
245
+ <v-row
246
+ v-if="visibleProperties.has('storeyHeightsAboveGround')"
247
+ no-gutters
248
+ >
249
+ <v-col>
250
+ <VcsLabel :html-for="'vp-storey-heights-above'" class="px-4">{{
251
+ $t('components.vectorProperties.storeyHeights')
252
+ }}</VcsLabel>
253
+ </v-col>
254
+ <v-col>
255
+ <VcsChipArrayInput
256
+ id="vp-storey-heights-above"
257
+ dense
258
+ column
259
+ type="number"
260
+ v-model="storeyHeights.storeyHeightsAboveGround.value"
261
+ placeholder="3"
262
+ />
263
+ </v-col>
264
+ </v-row>
265
+ <v-row
266
+ v-if="
267
+ visibleProperties.has('skirt') ||
268
+ visibleProperties.has('storeysBelowGround') ||
269
+ visibleProperties.has('storeyHeightsBelowGround')
270
+ "
271
+ no-gutters
272
+ >
273
+ <v-col>
274
+ <VcsLabel>{{
275
+ $t('components.vectorProperties.belowGround')
276
+ }}</VcsLabel>
277
+ </v-col>
278
+ </v-row>
279
+ <v-row v-if="visibleProperties.has('skirt')" no-gutters>
280
+ <v-col>
281
+ <VcsLabel html-for="vp-skirt" class="px-4">{{
282
+ $t('components.vectorProperties.skirt')
283
+ }}</VcsLabel>
284
+ </v-col>
285
+ <v-col>
286
+ <VcsTextField
287
+ id="vp-skirt"
288
+ dense
289
+ v-model.number="skirt"
290
+ type="number"
291
+ unit="m"
292
+ :placeholder="'skirt' in value ? '0 m' : ''"
293
+ :rules="[
294
+ (v) => v >= 0 || isNaN(v) || 'components.validation.notValid',
295
+ ]"
296
+ />
297
+ </v-col>
298
+ </v-row>
299
+ <v-row v-if="visibleProperties.has('storeysBelowGround')" no-gutters>
300
+ <v-col>
301
+ <VcsLabel html-for="vp-storeys-below" class="px-4">{{
302
+ $t('components.vectorProperties.storeys')
303
+ }}</VcsLabel>
304
+ </v-col>
305
+ <v-col>
306
+ <VcsTextField
307
+ id="vp-storeys-below"
308
+ dense
309
+ v-model.number="storeysBelowGround"
310
+ type="number"
311
+ :placeholder="'storeysBelowGround' in value ? '0' : ''"
312
+ :rules="[
313
+ (v) => v >= 0 || isNaN(v) || 'components.validation.notValid',
314
+ ]"
315
+ />
316
+ </v-col>
317
+ </v-row>
318
+ <v-row
319
+ v-if="visibleProperties.has('storeyHeightsBelowGround')"
320
+ no-gutters
321
+ >
322
+ <v-col>
323
+ <VcsLabel :html-for="'vp-storey-heights-below'" class="px-4">{{
324
+ $t('components.vectorProperties.storeyHeights')
325
+ }}</VcsLabel>
326
+ </v-col>
327
+ <v-col>
328
+ <VcsChipArrayInput
329
+ :id="'vp-storey-heights-below'"
330
+ dense
331
+ column
332
+ type="number"
333
+ v-model="storeyHeights.storeyHeightsBelowGround.value"
334
+ placeholder="3"
335
+ />
336
+ </v-col>
337
+ </v-row>
338
+ </v-container>
339
+ <v-divider
340
+ v-if="
341
+ [
342
+ 'modelUrl',
343
+ 'modelScaleX',
344
+ 'modelScaleY',
345
+ 'modelScaleZ',
346
+ 'modelHeading',
347
+ 'modelPitch',
348
+ 'modelRoll',
349
+ 'baseUrl',
350
+ ].some((prop) => visibleProperties.has(prop)) && show3DProperties
351
+ "
352
+ />
353
+ <v-container class="px-1 py-0" v-if="show3DProperties">
354
+ <v-row v-if="visibleProperties.has('modelUrl')" no-gutters>
355
+ <v-col>
356
+ <VcsLabel html-for="vp-model-url">
357
+ {{ $t('components.vectorProperties.modelUrl') }}
358
+ </VcsLabel>
359
+ </v-col>
360
+ <v-col>
361
+ <VcsTextField
362
+ id="vp-model-url"
363
+ dense
364
+ v-model="modelUrl"
365
+ clearable
366
+ :placeholder="'modelUrl' in value ? 'example.glb' : ''"
367
+ />
368
+ </v-col>
369
+ </v-row>
370
+ <v-row v-if="Object.keys(modelScale).length" no-gutters>
371
+ <v-col cols="6">
372
+ <VcsLabel>{{
373
+ $t('components.vectorProperties.modelScale')
374
+ }}</VcsLabel>
375
+ </v-col>
376
+ <v-col v-for="(dimension, key) in modelScale" :key="key">
377
+ <VcsTextField
378
+ dense
379
+ v-model.number="dimension.value"
380
+ type="number"
381
+ :placeholder="`modelScale${key}` in value ? '1' : ''"
382
+ :prefix="key"
383
+ :rules="[(v) => v > 0 || 'components.validation.notValid']"
384
+ />
385
+ </v-col>
386
+ </v-row>
387
+ <v-row v-if="visibleProperties.has('modelHeading')" no-gutters>
388
+ <v-col cols="6">
389
+ <VcsLabel>{{
390
+ $t('components.vectorProperties.modelHeading')
391
+ }}</VcsLabel>
392
+ </v-col>
393
+ <v-col>
394
+ <VcsTextField
395
+ dense
396
+ v-model.number="modelHeading"
397
+ type="number"
398
+ :placeholder="'modelHeading' in value ? '0 °' : ''"
399
+ unit="°"
400
+ />
401
+ </v-col>
402
+ </v-row>
403
+ <v-row v-if="visibleProperties.has('modelPitch')" no-gutters>
404
+ <v-col cols="6">
405
+ <VcsLabel>{{
406
+ $t('components.vectorProperties.modelPitch')
407
+ }}</VcsLabel>
408
+ </v-col>
409
+ <v-col>
410
+ <VcsTextField
411
+ dense
412
+ v-model.number="modelPitch"
413
+ type="number"
414
+ :placeholder="'modelPitch' in value ? '0 °' : ''"
415
+ unit="°"
416
+ />
417
+ </v-col>
418
+ </v-row>
419
+ <v-row v-if="visibleProperties.has('modelRoll')" no-gutters>
420
+ <v-col cols="6">
421
+ <VcsLabel>{{ $t('components.vectorProperties.modelRoll') }}</VcsLabel>
422
+ </v-col>
423
+ <v-col>
424
+ <VcsTextField
425
+ dense
426
+ v-model.number="modelRoll"
427
+ type="number"
428
+ :placeholder="'modelRoll' in value ? '0 °' : ''"
429
+ unit="°"
430
+ />
431
+ </v-col>
432
+ </v-row>
433
+ <v-row v-if="visibleProperties.has('baseUrl')" no-gutters>
434
+ <v-col>
435
+ <VcsLabel html-for="vp-base-url">{{
436
+ $t('components.vectorProperties.baseUrl')
437
+ }}</VcsLabel>
438
+ </v-col>
439
+ <v-col>
440
+ <VcsTextField
441
+ id="vp-base-url"
442
+ dense
443
+ clearable
444
+ v-model="baseUrl"
445
+ :placeholder="'baseUrl' in value ? 'path/to/files/' : ''"
446
+ />
447
+ </v-col>
448
+ </v-row>
449
+ </v-container>
450
+ </VcsFormSection>
451
+ </template>
452
+
453
+ <script>
454
+ import { computed } from 'vue';
455
+ import { VContainer, VRow, VCol, VDivider } from 'vuetify/lib';
456
+ import {
457
+ VcsFormSection,
458
+ VcsSelect,
459
+ VcsTextField,
460
+ VcsCheckbox,
461
+ VcsLabel,
462
+ } from '@vcmap/ui';
463
+ import {
464
+ usePrimitiveProperty,
465
+ useArrayProperty,
466
+ useHasProperty,
467
+ } from './composables.js';
468
+ import VcsChipArrayInput from '../form-inputs-controls/VcsChipArrayInput.vue';
469
+
470
+ export const vectorProperties = [
471
+ 'altitudeMode',
472
+ 'allowPicking',
473
+ 'classificationType',
474
+ 'scaleByDistance',
475
+ 'eyeOffset',
476
+ 'heightAboveGround',
477
+ 'skirt',
478
+ 'groundLevel',
479
+ 'extrudedHeight',
480
+ 'storeysAboveGround',
481
+ 'storeysBelowGround',
482
+ 'storeyHeightsAboveGround',
483
+ 'storeyHeightsBelowGround',
484
+ 'modelUrl',
485
+ 'modelScaleX',
486
+ 'modelScaleY',
487
+ 'modelScaleZ',
488
+ 'modelHeading',
489
+ 'modelPitch',
490
+ 'modelRoll',
491
+ 'baseUrl',
492
+ ];
493
+
494
+ export const scaleByDistanceDefault = [0, 1, 1, 1];
495
+ export const eyeOffsetDefault = [0, 0, 0];
496
+ export const dimensionsUpperCase = ['X', 'Y', 'Z'];
497
+
498
+ /**
499
+ * @description Allows to model VectorPropertiesOptions. If a key is not part of the options, the corresponding input field stays empty.
500
+ * @vue-prop {import("@vcmap/core").VectorPropertiesOptions} value - The options to be modelled.
501
+ * @vue-prop {import("@vcmap/core").VectorPropertiesOptions} valueDefault - The default VectorPropertiesOptions that are applied when clicking the "Reset" button.
502
+ * @vue-prop {Array<string>} properties - The keys of the VectorPropertiesOptions that should be editable. If a key is not within this array, the corresponding input field is not shown.
503
+ * @vue-prop {boolean} show3DProperties - Whether the 3D related properties should be shown or not.
504
+ * @vue-event {import("@vcmap/core").VectorPropertiesOptions} input - Emits the updated VectorPropertiesOptions each time a property is changed.
505
+ * @vue-event {import("@vcmap/core").VectorPropertiesOptions} propertyChange - Emits the updated VectorPropertiesOptions, containing only the keys that changed, each time a property is changed.
506
+ */
507
+ export default {
508
+ name: 'VcsVectorPropertiesComponent',
509
+ components: {
510
+ VcsFormSection,
511
+ VcsLabel,
512
+ VcsSelect,
513
+ VcsTextField,
514
+ VcsCheckbox,
515
+ VcsChipArrayInput,
516
+ VContainer,
517
+ VRow,
518
+ VCol,
519
+ VDivider,
520
+ },
521
+ props: {
522
+ value: {
523
+ type: Object,
524
+ default: () => {},
525
+ },
526
+ valueDefault: {
527
+ type: Object,
528
+ required: true,
529
+ },
530
+ properties: {
531
+ type: Array,
532
+ default: () => vectorProperties,
533
+ },
534
+ show3DProperties: {
535
+ type: Boolean,
536
+ default: true,
537
+ },
538
+ },
539
+ setup(props, { emit }) {
540
+ const visibleProperties = computed(() => {
541
+ return new Set(props.properties);
542
+ });
543
+
544
+ const altitudeMode = usePrimitiveProperty(
545
+ () => props.value,
546
+ 'altitudeMode',
547
+ emit,
548
+ );
549
+ const heightAboveGround = usePrimitiveProperty(
550
+ () => props.value,
551
+ 'heightAboveGround',
552
+ emit,
553
+ );
554
+ const allowPicking = computed({
555
+ get() {
556
+ return props.value.allowPicking;
557
+ },
558
+ set(value) {
559
+ if (props.value.allowPicking !== value) {
560
+ const newParams = structuredClone(props.value);
561
+ const changedParams = { allowPicking: value || false };
562
+ emit('input', Object.assign(newParams, changedParams));
563
+ emit('propertyChange', changedParams);
564
+ }
565
+ },
566
+ });
567
+ const classificationType = computed({
568
+ get() {
569
+ if ('classificationType' in props.value) {
570
+ return props.value.classificationType || 'none';
571
+ } else {
572
+ return undefined;
573
+ }
574
+ },
575
+ set(value) {
576
+ if (props.value.classificationType !== value) {
577
+ const newParams = structuredClone(props.value);
578
+ const changedParams = {
579
+ classificationType: value === 'none' ? undefined : value,
580
+ };
581
+ emit('input', Object.assign(newParams, changedParams));
582
+ emit('propertyChange', changedParams);
583
+ }
584
+ },
585
+ });
586
+ const scaleByDistance = useArrayProperty(
587
+ () => props.value,
588
+ 'scaleByDistance',
589
+ emit,
590
+ 4,
591
+ );
592
+ const hasScaleByDistance = useHasProperty(
593
+ () => props.value,
594
+ 'scaleByDistance',
595
+ emit,
596
+ scaleByDistanceDefault,
597
+ );
598
+
599
+ const eyeOffset = useArrayProperty(
600
+ () => props.value,
601
+ 'eyeOffset',
602
+ emit,
603
+ 3,
604
+ );
605
+ const hasEyeOffset = useHasProperty(
606
+ () => props.value,
607
+ 'eyeOffset',
608
+ emit,
609
+ eyeOffsetDefault,
610
+ );
611
+
612
+ const groundLevel = usePrimitiveProperty(
613
+ () => props.value,
614
+ 'groundLevel',
615
+ emit,
616
+ );
617
+ const extrudedHeight = usePrimitiveProperty(
618
+ () => props.value,
619
+ 'extrudedHeight',
620
+ emit,
621
+ );
622
+ const skirt = usePrimitiveProperty(() => props.value, 'skirt', emit);
623
+ const storeysAboveGround = usePrimitiveProperty(
624
+ () => props.value,
625
+ 'storeysAboveGround',
626
+ emit,
627
+ );
628
+ const storeysBelowGround = usePrimitiveProperty(
629
+ () => props.value,
630
+ 'storeysBelowGround',
631
+ emit,
632
+ );
633
+
634
+ const storeyHeights = computed(() => {
635
+ return ['storeyHeightsAboveGround', 'storeyHeightsBelowGround']
636
+ .filter((key) => visibleProperties.value.has(key))
637
+ .reduce((acc, key) => {
638
+ return {
639
+ ...acc,
640
+ [key]: computed({
641
+ get() {
642
+ if (Array.isArray(props.value?.[key])) {
643
+ return props.value?.[key];
644
+ } else {
645
+ return [props.value?.[key]];
646
+ }
647
+ },
648
+ set(value) {
649
+ const newParams = structuredClone(props.value);
650
+ const changedParams = {
651
+ [key]: value,
652
+ };
653
+ emit('input', Object.assign(newParams, changedParams));
654
+ emit('propertyChange', changedParams);
655
+ },
656
+ }),
657
+ };
658
+ }, {});
659
+ });
660
+
661
+ const modelUrl = usePrimitiveProperty(
662
+ () => props.value,
663
+ 'modelUrl',
664
+ emit,
665
+ );
666
+
667
+ const modelScale = computed(() => {
668
+ return dimensionsUpperCase
669
+ .filter((dimension) =>
670
+ visibleProperties.value.has(`modelScale${dimension}`),
671
+ )
672
+ .reduce((acc, dimension) => {
673
+ return {
674
+ ...acc,
675
+ [dimension]: usePrimitiveProperty(
676
+ () => props.value,
677
+ `modelScale${dimension}`,
678
+ emit,
679
+ ),
680
+ };
681
+ }, {});
682
+ });
683
+
684
+ const modelHeading = usePrimitiveProperty(
685
+ () => props.value,
686
+ 'modelHeading',
687
+ emit,
688
+ );
689
+ const modelPitch = usePrimitiveProperty(
690
+ () => props.value,
691
+ 'modelPitch',
692
+ emit,
693
+ );
694
+ const modelRoll = usePrimitiveProperty(
695
+ () => props.value,
696
+ 'modelRoll',
697
+ emit,
698
+ );
699
+ const baseUrl = usePrimitiveProperty(() => props.value, 'baseUrl', emit);
700
+
701
+ function reset() {
702
+ const newParams = structuredClone(props.valueDefault);
703
+
704
+ emit('input', newParams);
705
+ emit('propertyChange', newParams);
706
+ }
707
+
708
+ return {
709
+ visibleProperties,
710
+ altitudeMode,
711
+ heightAboveGround,
712
+ allowPicking,
713
+ classificationType,
714
+ scaleByDistance,
715
+ hasScaleByDistance,
716
+ scaleByDistanceDefault,
717
+ eyeOffset,
718
+ hasEyeOffset,
719
+ eyeOffsetDefault,
720
+ groundLevel,
721
+ extrudedHeight,
722
+ skirt,
723
+ storeysAboveGround,
724
+ storeysBelowGround,
725
+ storeyHeights,
726
+ modelUrl,
727
+ modelScale,
728
+ modelHeading,
729
+ modelPitch,
730
+ modelRoll,
731
+ baseUrl,
732
+ reset,
733
+ dimensionsUpperCase,
734
+ };
735
+ },
736
+ };
737
+ </script>