Skip to content

Commit b16ca51

Browse files
committed
fix(ContextMenu): The contextmenu is now draggable
1 parent 497c563 commit b16ca51

File tree

1 file changed

+85
-31
lines changed

1 file changed

+85
-31
lines changed

components/Viewer/ContextMenu.vue

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,28 @@
33
v-model="show_menu"
44
content-class="circular-menu"
55
:style="getMenuStyle()"
6+
:close-on-content-click="false"
7+
:close-delay="100"
68
>
7-
<div
8-
class="circular-menu-items"
9-
:style="{ width: `${radius * 2}px`, height: `${radius * 2}px` }"
10-
>
11-
<component
12-
v-for="(item, index) in menu_items"
13-
:is="item"
14-
:key="index"
15-
:itemProps="{
16-
id: props.id,
17-
tooltip_location: getTooltipLocation(index),
18-
tooltip_origin: getTooltipOrigin(index),
19-
}"
20-
class="menu-item-wrapper"
21-
:style="getItemStyle(index)"
22-
/>
9+
<div class="circular-menu-drag-handle" @mousedown.stop="startDrag">
10+
<div
11+
class="circular-menu-items"
12+
:style="{ width: `${radius * 2}px`, height: `${radius * 2}px` }"
13+
>
14+
<component
15+
v-for="(item, index) in menu_items"
16+
:is="item"
17+
:key="index"
18+
:itemProps="{
19+
id: props.id,
20+
tooltip_location: getTooltipLocation(index),
21+
tooltip_origin: getTooltipOrigin(index),
22+
}"
23+
class="menu-item-wrapper"
24+
:style="getItemStyle(index)"
25+
@mousedown.stop
26+
/>
27+
</div>
2328
</div>
2429
</v-menu>
2530
</template>
@@ -40,12 +45,20 @@
4045
const itemId = props.id || menuStore.current_id
4146
return itemId ? dataBaseStore.itemMetaDatas(itemId) : {}
4247
})
48+
4349
const radius = 80
4450
const show_menu = ref(true)
51+
const isDragging = ref(false)
52+
const dragStartX = ref(0)
53+
const dragStartY = ref(0)
54+
const menuX = ref(props.x || menuStore.menuX)
55+
const menuY = ref(props.y || menuStore.menuY)
4556
46-
watch(show_menu, (value) => {
47-
if (!value) {
48-
menuStore.closeMenu()
57+
watch(show_menu, (newVal) => {
58+
if (!newVal && isDragging.value) {
59+
setTimeout(() => {
60+
show_menu.value = true
61+
}, 10)
4962
}
5063
})
5164
@@ -58,18 +71,42 @@
5871
5972
const menuItemCount = computed(() => menu_items.value.length)
6073
61-
function getMenuStyle() {
62-
const x = props.x || menuStore.menuX
63-
const y = props.y || menuStore.menuY
64-
const width = props.containerWidth || menuStore.containerWidth
65-
const height = props.containerHeight || menuStore.containerHeight
74+
function startDrag(e) {
75+
isDragging.value = true
76+
dragStartX.value = e.clientX - menuX.value
77+
dragStartY.value = e.clientY - menuY.value
78+
document.addEventListener("mousemove", handleDrag)
79+
document.addEventListener("mouseup", stopDrag)
80+
e.preventDefault()
81+
}
82+
83+
function handleDrag(e) {
84+
if (!isDragging.value) return
85+
menuX.value = e.clientX - dragStartX.value
86+
menuY.value = e.clientY - dragStartY.value
6687
67-
const adjustedX = Math.min(Math.max(x, radius), width - radius)
68-
const adjustedY = Math.min(Math.max(y, radius), height - radius)
88+
menuX.value = Math.min(
89+
Math.max(menuX.value, radius),
90+
props.containerWidth - radius,
91+
)
92+
menuY.value = Math.min(
93+
Math.max(menuY.value, radius),
94+
props.containerHeight - radius,
95+
)
96+
}
97+
98+
function stopDrag(e) {
99+
isDragging.value = false
100+
document.removeEventListener("mousemove", handleDrag)
101+
document.removeEventListener("mouseup", stopDrag)
102+
e.stopPropagation()
103+
menuStore.setMenuPosition(menuX.value, menuY.value)
104+
}
69105
106+
function getMenuStyle() {
70107
return {
71-
left: `${adjustedX - radius}px`,
72-
top: `${adjustedY - radius}px`,
108+
left: `${menuX.value - radius}px`,
109+
top: `${menuY.value - radius}px`,
73110
}
74111
}
75112
@@ -92,20 +129,37 @@
92129
function getItemStyle(index) {
93130
const angle = (index / menuItemCount.value) * 2 * Math.PI
94131
return {
95-
transform: `translate(${Math.cos(angle) * radius}px, ${
96-
Math.sin(angle) * radius
97-
}px)`,
132+
transform: `translate(${Math.cos(angle) * radius}px, ${Math.sin(angle) * radius}px)`,
98133
transition: "opacity 0.1s ease, transform 0.1s ease",
99134
position: "absolute",
100135
}
101136
}
137+
138+
onUnmounted(() => {
139+
document.removeEventListener("mousemove", handleDrag)
140+
document.removeEventListener("mouseup", stopDrag)
141+
})
102142
</script>
103143

104144
<style scoped>
105145
.circular-menu {
106146
position: absolute;
107147
border-radius: 50%;
108148
background-color: rgba(0, 0, 0, 0.8);
149+
user-select: none;
150+
cursor: grab;
151+
z-index: 1000;
152+
}
153+
154+
.circular-menu-drag-handle {
155+
width: 100%;
156+
height: 100%;
157+
border-radius: 50%;
158+
cursor: grab;
159+
}
160+
161+
.circular-menu-drag-handle:active {
162+
cursor: grabbing;
109163
}
110164
111165
.circular-menu-items {

0 commit comments

Comments
 (0)