@geode/opengeodeweb-front 10.19.1-rc.1 → 10.20.0-rc.2
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/app/components/ViewToolbar.vue +1 -1
- package/app/components/Viewer/ContextMenu/CenterButton.vue +119 -0
- package/app/components/Viewer/ContextMenu/CircularItems.vue +86 -0
- package/app/components/Viewer/{ContextMenu.vue → ContextMenu/ContextMenu.vue} +67 -71
- package/app/components/Viewer/{ContextMenuItem.vue → ContextMenu/ContextMenuItem.vue} +104 -4
- package/app/components/Viewer/ContextMenu/InfoCard.vue +184 -0
- package/app/components/Viewer/EdgedCurve/SpecificEdgesOptions.vue +1 -1
- package/app/components/Viewer/Generic/Mesh/CellsOptions.vue +1 -1
- package/app/components/Viewer/Generic/Mesh/EdgesOptions.vue +1 -1
- package/app/components/Viewer/Generic/Mesh/PointsOptions.vue +1 -1
- package/app/components/Viewer/Generic/Mesh/PolygonsOptions.vue +1 -1
- package/app/components/Viewer/Generic/Mesh/PolyhedraOptions.vue +1 -1
- package/app/components/Viewer/Generic/Model/EdgesOptions.vue +1 -1
- package/app/components/Viewer/Generic/Model/ModelStyleOptions.vue +1 -1
- package/app/components/Viewer/Generic/Model/PointsOptions.vue +1 -1
- package/app/components/Viewer/OverlappingObjectsPicker.vue +96 -0
- package/app/components/Viewer/PointSet/SpecificPointsOptions.vue +1 -1
- package/app/components/Viewer/Solid/SpecificPolyhedraOptions.vue +1 -1
- package/app/components/Viewer/Surface/PolygonsOptions.vue +1 -1
- package/app/components/Viewer/Ui.vue +38 -24
- package/app/composables/project_manager.js +3 -3
- package/app/composables/use_adaptive_styles.js +50 -3
- package/app/composables/use_overlapping_picker.js +153 -0
- package/app/stores/data.js +5 -0
- package/app/stores/viewer.js +2 -2
- package/app/utils/name_cleaner.js +20 -0
- package/internal/stores/hybrid_viewer.js +31 -24
- package/package.json +1 -1
- package/tests/unit/composables/project_manager.nuxt.test.js +0 -1
|
@@ -135,7 +135,7 @@ const camera_options = computed(() => [
|
|
|
135
135
|
</script>
|
|
136
136
|
|
|
137
137
|
<template>
|
|
138
|
-
<v-container :class="[$style.floatToolbar, 'pa-0']" width="auto">
|
|
138
|
+
<v-container :class="[$style.floatToolbar, 'pa-0', 'view-toolbar']" width="auto">
|
|
139
139
|
<v-row v-for="camera_option in camera_options" :key="camera_option.icon" dense>
|
|
140
140
|
<v-col>
|
|
141
141
|
<v-menu v-if="camera_option.menu" location="start" :close-on-content-click="false">
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useAdaptiveStyles } from "@ogw_front/composables/use_adaptive_styles";
|
|
3
|
+
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
4
|
+
|
|
5
|
+
const { isOverTreeview, isOverToolbar } = defineProps({
|
|
6
|
+
isOverTreeview: { type: Boolean, required: true },
|
|
7
|
+
isOverToolbar: { type: Boolean, default: false },
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const emit = defineEmits(["drag", "click"]);
|
|
11
|
+
|
|
12
|
+
const ADAPTIVE_BLUR_VAL = "15px";
|
|
13
|
+
const ADAPTIVE_OPACITY_VAL = 0.85;
|
|
14
|
+
const ADAPTIVE_BRIGHTNESS_VAL = 1.15;
|
|
15
|
+
const dragThreshold = 3;
|
|
16
|
+
|
|
17
|
+
const menuStore = useMenuStore();
|
|
18
|
+
|
|
19
|
+
const centerButtonCoords = computed(() => {
|
|
20
|
+
const size = 52;
|
|
21
|
+
return {
|
|
22
|
+
x: menuStore.containerLeft + menuStore.menuX - size / 2,
|
|
23
|
+
y: menuStore.containerTop + menuStore.menuY - size / 2,
|
|
24
|
+
width: size,
|
|
25
|
+
height: size,
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const { adaptiveStyles } = useAdaptiveStyles(centerButtonCoords, {
|
|
30
|
+
minOpacity: 0.35,
|
|
31
|
+
maxOpacity: 1,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const computedItemStyles = computed(() => {
|
|
35
|
+
if (isOverTreeview || isOverToolbar) {
|
|
36
|
+
return {
|
|
37
|
+
"--adaptive-blur": ADAPTIVE_BLUR_VAL,
|
|
38
|
+
"--adaptive-opacity": ADAPTIVE_OPACITY_VAL,
|
|
39
|
+
"--adaptive-brightness": ADAPTIVE_BRIGHTNESS_VAL,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return adaptiveStyles.value;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
let dragMoved = false;
|
|
46
|
+
let dragStartClientX = 0;
|
|
47
|
+
let dragStartClientY = 0;
|
|
48
|
+
|
|
49
|
+
function onMouseDown(event) {
|
|
50
|
+
dragMoved = false;
|
|
51
|
+
dragStartClientX = event.clientX;
|
|
52
|
+
dragStartClientY = event.clientY;
|
|
53
|
+
emit("drag", event);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function onMouseUp(event) {
|
|
57
|
+
const deltaX = event.clientX - dragStartClientX;
|
|
58
|
+
const deltaY = event.clientY - dragStartClientY;
|
|
59
|
+
if (Math.hypot(deltaX, deltaY) > dragThreshold) {
|
|
60
|
+
dragMoved = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function onCenterClick(event) {
|
|
65
|
+
event.stopPropagation();
|
|
66
|
+
if (!dragMoved) {
|
|
67
|
+
emit("click", event);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<template>
|
|
73
|
+
<v-btn
|
|
74
|
+
icon
|
|
75
|
+
variant="outlined"
|
|
76
|
+
class="central-selector-btn elevation-6"
|
|
77
|
+
style="width: 52px; height: 52px; z-index: 5"
|
|
78
|
+
:style="computedItemStyles"
|
|
79
|
+
@mousedown="onMouseDown"
|
|
80
|
+
@mouseup="onMouseUp"
|
|
81
|
+
@click.stop="onCenterClick"
|
|
82
|
+
>
|
|
83
|
+
<v-icon icon="mdi-information-outline" size="28" color="primary" style="pointer-events: none" />
|
|
84
|
+
</v-btn>
|
|
85
|
+
</template>
|
|
86
|
+
|
|
87
|
+
<style scoped>
|
|
88
|
+
.central-selector-btn {
|
|
89
|
+
background: transparent !important;
|
|
90
|
+
border: 2px solid rgba(var(--v-theme-primary), 0.35) !important;
|
|
91
|
+
position: relative;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
transition: all 0.2s ease;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.central-selector-btn::before {
|
|
97
|
+
content: "";
|
|
98
|
+
position: absolute;
|
|
99
|
+
inset: 0;
|
|
100
|
+
background: rgba(255, 255, 255, var(--adaptive-opacity));
|
|
101
|
+
backdrop-filter: blur(var(--adaptive-blur)) brightness(var(--adaptive-brightness));
|
|
102
|
+
-webkit-backdrop-filter: blur(var(--adaptive-blur)) brightness(var(--adaptive-brightness));
|
|
103
|
+
z-index: 0;
|
|
104
|
+
pointer-events: none;
|
|
105
|
+
border-radius: inherit;
|
|
106
|
+
transition:
|
|
107
|
+
background-color 0.2s ease,
|
|
108
|
+
backdrop-filter 0.2s ease;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.central-selector-btn:hover {
|
|
112
|
+
transform: scale(1.08);
|
|
113
|
+
border-color: rgba(var(--v-theme-primary), 0.85) !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.central-selector-btn:hover::before {
|
|
117
|
+
background: rgba(255, 255, 255, calc(var(--adaptive-opacity, 0.15) + 0.15));
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
3
|
+
|
|
4
|
+
const { menuItems, id, metaData, menuItemCount } = defineProps({
|
|
5
|
+
menuItems: { type: Array, required: true },
|
|
6
|
+
id: { type: String, required: true },
|
|
7
|
+
metaData: { type: Object, required: true },
|
|
8
|
+
menuItemCount: { type: Number, required: true },
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const RADIUS = 80;
|
|
12
|
+
const Z_INDEX_ACTIVE_ITEM = 10;
|
|
13
|
+
const Z_INDEX_BASE_ITEM = 1;
|
|
14
|
+
const FULL_ANGLE = 360;
|
|
15
|
+
const ANGLE_45 = 45;
|
|
16
|
+
const ANGLE_135 = 135;
|
|
17
|
+
const ANGLE_225 = 225;
|
|
18
|
+
const ANGLE_315 = 315;
|
|
19
|
+
|
|
20
|
+
const menuStore = useMenuStore();
|
|
21
|
+
|
|
22
|
+
function getItemStyle(index) {
|
|
23
|
+
const angle = (index / menuItemCount) * 2 * Math.PI;
|
|
24
|
+
return {
|
|
25
|
+
transform: `translate(${Math.cos(angle) * RADIUS}px, ${Math.sin(angle) * RADIUS}px)`,
|
|
26
|
+
transition: "opacity 0.2s ease, transform 0.2s ease",
|
|
27
|
+
position: "absolute",
|
|
28
|
+
zIndex: menuStore.active_item_index === index ? Z_INDEX_ACTIVE_ITEM : Z_INDEX_BASE_ITEM,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getTooltipLocation(index) {
|
|
33
|
+
const angle = (index / menuItemCount) * FULL_ANGLE;
|
|
34
|
+
if (angle < ANGLE_45 || angle >= ANGLE_315) {
|
|
35
|
+
return "right";
|
|
36
|
+
}
|
|
37
|
+
if (angle >= ANGLE_45 && angle < ANGLE_135) {
|
|
38
|
+
return "top";
|
|
39
|
+
}
|
|
40
|
+
if (angle >= ANGLE_135 && angle < ANGLE_225) {
|
|
41
|
+
return "left";
|
|
42
|
+
}
|
|
43
|
+
return "bottom";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getTooltipOrigin(index) {
|
|
47
|
+
const angle = (index / menuItemCount) * FULL_ANGLE;
|
|
48
|
+
if (angle < ANGLE_45 || angle >= ANGLE_315) {
|
|
49
|
+
return "left";
|
|
50
|
+
}
|
|
51
|
+
if (angle >= ANGLE_45 && angle < ANGLE_135) {
|
|
52
|
+
return "bottom";
|
|
53
|
+
}
|
|
54
|
+
if (angle >= ANGLE_135 && angle < ANGLE_225) {
|
|
55
|
+
return "right";
|
|
56
|
+
}
|
|
57
|
+
return "top";
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<component
|
|
63
|
+
v-for="(item, index) in menuItems"
|
|
64
|
+
:is="item"
|
|
65
|
+
:key="index"
|
|
66
|
+
:index="index"
|
|
67
|
+
:itemProps="{
|
|
68
|
+
id: id,
|
|
69
|
+
meta_data: metaData,
|
|
70
|
+
tooltip_location: getTooltipLocation(index),
|
|
71
|
+
tooltip_origin: getTooltipOrigin(index),
|
|
72
|
+
totalItems: menuItemCount,
|
|
73
|
+
}"
|
|
74
|
+
class="menu-item-wrapper"
|
|
75
|
+
:style="getItemStyle(index)"
|
|
76
|
+
@mousedown.stop
|
|
77
|
+
/>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<style scoped>
|
|
81
|
+
.menu-item-wrapper {
|
|
82
|
+
position: absolute;
|
|
83
|
+
transform-origin: center;
|
|
84
|
+
will-change: transform, opacity;
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import CenterButton from "@ogw_front/components/Viewer/ContextMenu/CenterButton";
|
|
3
|
+
import CircularItems from "@ogw_front/components/Viewer/ContextMenu/CircularItems";
|
|
4
|
+
import InfoCard from "@ogw_front/components/Viewer/ContextMenu/InfoCard";
|
|
2
5
|
import { useEventListener } from "@vueuse/core";
|
|
3
6
|
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
4
|
-
|
|
5
|
-
const RADIUS = 80;
|
|
6
|
-
const MARGIN_OFFSET = 40;
|
|
7
|
-
const Z_INDEX_ACTIVE_ITEM = 10;
|
|
8
|
-
const Z_INDEX_BASE_ITEM = 1;
|
|
9
|
-
const FULL_ANGLE = 360;
|
|
10
|
-
const ANGLE_45 = 45;
|
|
11
|
-
const ANGLE_135 = 135;
|
|
12
|
-
const ANGLE_225 = 225;
|
|
13
|
-
const ANGLE_315 = 315;
|
|
14
|
-
const CLOSE_DELAY = 100;
|
|
15
|
-
|
|
16
|
-
const menuStore = useMenuStore();
|
|
7
|
+
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
17
8
|
|
|
18
9
|
const { id, x, y, containerWidth, containerHeight } = defineProps({
|
|
19
10
|
id: { type: String, required: true },
|
|
@@ -23,9 +14,22 @@ const { id, x, y, containerWidth, containerHeight } = defineProps({
|
|
|
23
14
|
containerHeight: { type: Number, required: true },
|
|
24
15
|
});
|
|
25
16
|
|
|
17
|
+
const RADIUS = 80;
|
|
18
|
+
const MARGIN_OFFSET = 40;
|
|
19
|
+
const CLOSE_DELAY = 100;
|
|
20
|
+
const TREEVIEW_MARGIN_LEFT = 10;
|
|
21
|
+
const TREEVIEW_ICON_WIDTH = 48;
|
|
22
|
+
const TREEVIEW_MARGIN_RIGHT = 20;
|
|
23
|
+
const CENTER_BUTTON_SIZE = 52;
|
|
24
|
+
const CENTER_BUTTON_HALF_SIZE = 26;
|
|
25
|
+
|
|
26
|
+
const menuStore = useMenuStore();
|
|
27
|
+
const treeviewStore = useTreeviewStore();
|
|
28
|
+
|
|
26
29
|
const meta_data = computed(() => menuStore.current_meta_data || {});
|
|
27
30
|
|
|
28
31
|
const show_menu = ref(true);
|
|
32
|
+
const showName = ref(false);
|
|
29
33
|
const isDragging = ref(false);
|
|
30
34
|
const dragStartX = ref(0);
|
|
31
35
|
const dragStartY = ref(0);
|
|
@@ -73,11 +77,42 @@ watch(
|
|
|
73
77
|
|
|
74
78
|
const menuItemCount = computed(() => menu_items.value.length);
|
|
75
79
|
|
|
80
|
+
const isOverTreeview = computed(() => {
|
|
81
|
+
const hasAdditional = treeviewStore.opened_views.some((view) => view.id !== "main");
|
|
82
|
+
const hasMain = treeviewStore.opened_views.some((view) => view.id === "main");
|
|
83
|
+
const firstColWidth = hasMain ? treeviewStore.panelWidth : 0;
|
|
84
|
+
const secondColWidth = hasAdditional ? treeviewStore.additionalPanelWidth : 0;
|
|
85
|
+
const treeviewWidth =
|
|
86
|
+
TREEVIEW_MARGIN_LEFT +
|
|
87
|
+
TREEVIEW_ICON_WIDTH +
|
|
88
|
+
firstColWidth +
|
|
89
|
+
secondColWidth +
|
|
90
|
+
TREEVIEW_MARGIN_RIGHT;
|
|
91
|
+
return menuX.value < treeviewWidth;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const isOverToolbar = computed(() => {
|
|
95
|
+
const toolbarEl = document.querySelector(".view-toolbar");
|
|
96
|
+
if (!toolbarEl) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const rect = toolbarEl.getBoundingClientRect();
|
|
100
|
+
const btnX = menuStore.containerLeft + menuX.value - CENTER_BUTTON_HALF_SIZE;
|
|
101
|
+
const btnY = menuStore.containerTop + menuY.value - CENTER_BUTTON_HALF_SIZE;
|
|
102
|
+
const btnWidth = CENTER_BUTTON_SIZE;
|
|
103
|
+
const btnHeight = CENTER_BUTTON_SIZE;
|
|
104
|
+
return (
|
|
105
|
+
btnX < rect.right &&
|
|
106
|
+
btnX + btnWidth > rect.left &&
|
|
107
|
+
btnY < rect.bottom &&
|
|
108
|
+
btnY + btnHeight > rect.top
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
76
112
|
function startDrag(event) {
|
|
77
113
|
isDragging.value = true;
|
|
78
114
|
dragStartX.value = event.clientX - menuX.value;
|
|
79
115
|
dragStartY.value = event.clientY - menuY.value;
|
|
80
|
-
event.preventDefault();
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
function clampPosition(posX, posY) {
|
|
@@ -112,42 +147,8 @@ function getMenuStyle() {
|
|
|
112
147
|
};
|
|
113
148
|
}
|
|
114
149
|
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
if (angle < ANGLE_45 || angle >= ANGLE_315) {
|
|
118
|
-
return "right";
|
|
119
|
-
}
|
|
120
|
-
if (angle >= ANGLE_45 && angle < ANGLE_135) {
|
|
121
|
-
return "top";
|
|
122
|
-
}
|
|
123
|
-
if (angle >= ANGLE_135 && angle < ANGLE_225) {
|
|
124
|
-
return "left";
|
|
125
|
-
}
|
|
126
|
-
return "bottom";
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getTooltipOrigin(index) {
|
|
130
|
-
const angle = (index / menuItemCount.value) * FULL_ANGLE;
|
|
131
|
-
if (angle < ANGLE_45 || angle >= ANGLE_315) {
|
|
132
|
-
return "left";
|
|
133
|
-
}
|
|
134
|
-
if (angle >= ANGLE_45 && angle < ANGLE_135) {
|
|
135
|
-
return "bottom";
|
|
136
|
-
}
|
|
137
|
-
if (angle >= ANGLE_135 && angle < ANGLE_225) {
|
|
138
|
-
return "right";
|
|
139
|
-
}
|
|
140
|
-
return "top";
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function getItemStyle(index) {
|
|
144
|
-
const angle = (index / menuItemCount.value) * 2 * Math.PI;
|
|
145
|
-
return {
|
|
146
|
-
transform: `translate(${Math.cos(angle) * RADIUS}px, ${Math.sin(angle) * RADIUS}px)`,
|
|
147
|
-
transition: "opacity 0.2s ease, transform 0.2s ease",
|
|
148
|
-
position: "absolute",
|
|
149
|
-
zIndex: menuStore.active_item_index === index ? Z_INDEX_ACTIVE_ITEM : Z_INDEX_BASE_ITEM,
|
|
150
|
-
};
|
|
150
|
+
function toggleShowName() {
|
|
151
|
+
showName.value = !showName.value;
|
|
151
152
|
}
|
|
152
153
|
</script>
|
|
153
154
|
|
|
@@ -165,22 +166,21 @@ function getItemStyle(index) {
|
|
|
165
166
|
class="circular-menu-items"
|
|
166
167
|
:style="{ width: `${RADIUS * 2}px`, height: `${RADIUS * 2}px` }"
|
|
167
168
|
>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
:
|
|
171
|
-
:
|
|
172
|
-
:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class="menu-item-wrapper"
|
|
181
|
-
:style="getItemStyle(index)"
|
|
182
|
-
@mousedown.stop
|
|
169
|
+
<CircularItems
|
|
170
|
+
:menu-items="menu_items"
|
|
171
|
+
:id="id"
|
|
172
|
+
:meta-data="meta_data"
|
|
173
|
+
:menu-item-count="menuItemCount"
|
|
174
|
+
/>
|
|
175
|
+
|
|
176
|
+
<CenterButton
|
|
177
|
+
:is-over-treeview="isOverTreeview"
|
|
178
|
+
:is-over-toolbar="isOverToolbar"
|
|
179
|
+
@drag="startDrag"
|
|
180
|
+
@click="toggleShowName"
|
|
183
181
|
/>
|
|
182
|
+
|
|
183
|
+
<InfoCard v-model:show="showName" :meta-data="meta_data" />
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
186
186
|
</v-menu>
|
|
@@ -200,6 +200,8 @@ function getItemStyle(index) {
|
|
|
200
200
|
height: 100%;
|
|
201
201
|
border-radius: 50%;
|
|
202
202
|
cursor: grab;
|
|
203
|
+
user-select: none;
|
|
204
|
+
-webkit-user-select: none;
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
.circular-menu-drag-handle:active {
|
|
@@ -215,10 +217,4 @@ function getItemStyle(index) {
|
|
|
215
217
|
background-color: transparent;
|
|
216
218
|
border: none;
|
|
217
219
|
}
|
|
218
|
-
|
|
219
|
-
.menu-item-wrapper {
|
|
220
|
-
position: absolute;
|
|
221
|
-
transform-origin: center;
|
|
222
|
-
will-change: transform, opacity;
|
|
223
|
-
}
|
|
224
220
|
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import GlassCard from "@ogw_front/components/GlassCard";
|
|
3
|
+
import { useAdaptiveStyles } from "@ogw_front/composables/use_adaptive_styles";
|
|
3
4
|
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
4
5
|
import { useTheme } from "vuetify";
|
|
6
|
+
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
5
7
|
|
|
6
8
|
const CARD_WIDTH = 320;
|
|
7
9
|
const CARD_HEIGHT = 500;
|
|
@@ -12,6 +14,7 @@ const OFFSET = 40;
|
|
|
12
14
|
const menuStore = useMenuStore();
|
|
13
15
|
const theme = useTheme();
|
|
14
16
|
const primaryColor = computed(() => theme.current.value.colors.primary);
|
|
17
|
+
|
|
15
18
|
const { index, itemProps, tooltip, btn_image } = defineProps({
|
|
16
19
|
index: { type: Number, required: true },
|
|
17
20
|
itemProps: { type: Object, required: true },
|
|
@@ -19,6 +22,69 @@ const { index, itemProps, tooltip, btn_image } = defineProps({
|
|
|
19
22
|
btn_image: { type: String, required: true },
|
|
20
23
|
});
|
|
21
24
|
|
|
25
|
+
const buttonCoords = computed(() => {
|
|
26
|
+
const angle = (index / itemProps.totalItems) * 2 * Math.PI;
|
|
27
|
+
const deltaX = Math.cos(angle) * RADIUS;
|
|
28
|
+
const deltaY = Math.sin(angle) * RADIUS;
|
|
29
|
+
const size = 40;
|
|
30
|
+
return {
|
|
31
|
+
x: menuStore.containerLeft + menuStore.menuX + deltaX - size / 2,
|
|
32
|
+
y: menuStore.containerTop + menuStore.menuY + deltaY - size / 2,
|
|
33
|
+
width: size,
|
|
34
|
+
height: size,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const { adaptiveStyles } = useAdaptiveStyles(buttonCoords, {
|
|
39
|
+
minOpacity: 0.35,
|
|
40
|
+
maxOpacity: 1,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const TREEVIEW_MARGIN_LEFT = 10;
|
|
44
|
+
const TREEVIEW_MARGIN_RIGHT = 20;
|
|
45
|
+
const TREEVIEW_ICON_WIDTH = 48;
|
|
46
|
+
|
|
47
|
+
const treeviewStore = useTreeviewStore();
|
|
48
|
+
const isOverTreeview = computed(() => {
|
|
49
|
+
const hasAdditional = treeviewStore.opened_views.some((view) => view.id !== "main");
|
|
50
|
+
const hasMain = treeviewStore.opened_views.some((view) => view.id === "main");
|
|
51
|
+
const firstColWidth = hasMain ? treeviewStore.panelWidth : 0;
|
|
52
|
+
const secondColWidth = hasAdditional ? treeviewStore.additionalPanelWidth : 0;
|
|
53
|
+
const treeviewWidth =
|
|
54
|
+
TREEVIEW_MARGIN_LEFT +
|
|
55
|
+
TREEVIEW_ICON_WIDTH +
|
|
56
|
+
firstColWidth +
|
|
57
|
+
secondColWidth +
|
|
58
|
+
TREEVIEW_MARGIN_RIGHT;
|
|
59
|
+
return buttonCoords.value.x < treeviewWidth;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const isOverToolbar = computed(() => {
|
|
63
|
+
const toolbarEl = document.querySelector(".view-toolbar");
|
|
64
|
+
if (!toolbarEl) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const rect = toolbarEl.getBoundingClientRect();
|
|
68
|
+
const btn = buttonCoords.value;
|
|
69
|
+
return (
|
|
70
|
+
btn.x < rect.right &&
|
|
71
|
+
btn.x + btn.width > rect.left &&
|
|
72
|
+
btn.y < rect.bottom &&
|
|
73
|
+
btn.y + btn.height > rect.top
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const computedItemStyles = computed(() => {
|
|
78
|
+
if (isOverTreeview.value || isOverToolbar.value) {
|
|
79
|
+
return {
|
|
80
|
+
"--adaptive-blur": "15px",
|
|
81
|
+
"--adaptive-opacity": 0.85,
|
|
82
|
+
"--adaptive-brightness": 1.15,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return adaptiveStyles.value;
|
|
86
|
+
});
|
|
87
|
+
|
|
22
88
|
const is_active = computed(() => menuStore.active_item_index === index);
|
|
23
89
|
const optionsRef = ref(undefined);
|
|
24
90
|
const { height: optionsHeight } = useElementSize(optionsRef);
|
|
@@ -66,13 +132,20 @@ function toggleOptions() {
|
|
|
66
132
|
<template v-slot:activator="{ props: tooltipProps }">
|
|
67
133
|
<v-btn
|
|
68
134
|
icon
|
|
135
|
+
variant="outlined"
|
|
69
136
|
:active="is_active"
|
|
70
137
|
@click.stop="toggleOptions"
|
|
71
138
|
v-bind="tooltipProps"
|
|
72
|
-
class="menu-btn
|
|
139
|
+
class="menu-btn"
|
|
73
140
|
elevation="2"
|
|
141
|
+
:style="computedItemStyles"
|
|
74
142
|
>
|
|
75
|
-
<v-img
|
|
143
|
+
<v-img
|
|
144
|
+
:src="btn_image"
|
|
145
|
+
height="28"
|
|
146
|
+
width="28"
|
|
147
|
+
style="pointer-events: none; object-fit: contain"
|
|
148
|
+
/>
|
|
76
149
|
</v-btn>
|
|
77
150
|
</template>
|
|
78
151
|
<span>{{ tooltip }}</span>
|
|
@@ -120,13 +193,34 @@ function toggleOptions() {
|
|
|
120
193
|
}
|
|
121
194
|
|
|
122
195
|
.menu-btn {
|
|
196
|
+
background: transparent !important;
|
|
197
|
+
border: 1px solid rgba(255, 255, 255, 0.2) !important;
|
|
198
|
+
position: relative;
|
|
199
|
+
overflow: hidden;
|
|
123
200
|
transition: all 0.2s ease;
|
|
124
|
-
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.menu-btn::before {
|
|
204
|
+
content: "";
|
|
205
|
+
position: absolute;
|
|
206
|
+
inset: 0;
|
|
207
|
+
background: rgba(255, 255, 255, var(--adaptive-opacity));
|
|
208
|
+
backdrop-filter: blur(var(--adaptive-blur)) brightness(var(--adaptive-brightness));
|
|
209
|
+
-webkit-backdrop-filter: blur(var(--adaptive-blur)) brightness(var(--adaptive-brightness));
|
|
210
|
+
z-index: 0;
|
|
211
|
+
pointer-events: none;
|
|
212
|
+
border-radius: inherit;
|
|
213
|
+
transition:
|
|
214
|
+
background-color 0.2s ease,
|
|
215
|
+
backdrop-filter 0.2s ease;
|
|
125
216
|
}
|
|
126
217
|
|
|
127
218
|
.menu-btn:hover {
|
|
128
219
|
transform: scale(1.1);
|
|
129
|
-
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.menu-btn:hover::before {
|
|
223
|
+
background: rgba(255, 255, 255, calc(var(--adaptive-opacity, 0.15) + 0.15));
|
|
130
224
|
}
|
|
131
225
|
|
|
132
226
|
.menu-btn.v-btn--active {
|
|
@@ -134,6 +228,12 @@ function toggleOptions() {
|
|
|
134
228
|
color: white !important;
|
|
135
229
|
}
|
|
136
230
|
|
|
231
|
+
.menu-btn.v-btn--active::before {
|
|
232
|
+
background: transparent !important;
|
|
233
|
+
backdrop-filter: none !important;
|
|
234
|
+
-webkit-backdrop-filter: none !important;
|
|
235
|
+
}
|
|
236
|
+
|
|
137
237
|
.menu-btn.v-btn--active ::v-deep(.v-img__img) {
|
|
138
238
|
filter: invert(100%);
|
|
139
239
|
}
|