feat: remake machanicalbutton
This commit is contained in:
parent
5ea541ef4b
commit
4465091db3
src/components/equipments
|
@ -1,37 +1,52 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :width="props.width" :height="props.height" viewBox="0 0 1600 1600">
|
||||
<def>
|
||||
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="20" result="blur" />
|
||||
<feColorMatrix result="bluralpha" type="matrix" :values="colorMatrix" />
|
||||
<feOffset in="bluralpha" dx="20" dy="20" result="offsetBlur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="offsetBlur" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</def>
|
||||
<g>
|
||||
<div class="relative" :style="{width: `${props.width}px`, height: `${props.height}px`}">
|
||||
<!-- 简化的SVG按钮 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :width="props.width" :height="props.height" viewBox="0 0 1600 1600">
|
||||
<defs>
|
||||
<filter id="btn-shadow">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="20" result="blur" />
|
||||
<feColorMatrix result="bluralpha" type="matrix" :values="colorMatrix" />
|
||||
<feOffset in="bluralpha" dx="20" dy="20" result="offsetBlur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="offsetBlur" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<linearGradient id="normal" gradientTransform="rotate(45 0 0)">
|
||||
<stop stop-color="#4b4b4b" offset="0" />
|
||||
<stop stop-color="#171717" offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="pressed" gradientTransform="rotate(45 0 0)">
|
||||
<stop stop-color="#171717" offset="0" />
|
||||
<stop stop-color="#4b4b4b" offset="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- 按钮底座 -->
|
||||
<rect width="800" height="800" x="400" y="400" fill="#464646" rx="20" />
|
||||
<rect width="700" height="700" x="450" y="450" fill="#eaeaea" rx="20" />
|
||||
|
||||
<!-- 装饰螺丝 -->
|
||||
<circle r="20" cx="1075" cy="1075" fill="#171717" />
|
||||
<circle r="20" cx="1075" cy="525" fill="#171717" />
|
||||
<circle r="20" cx="525" cy="525" fill="#171717" />
|
||||
<circle r="20" cx="525" cy="1075" fill="#171717" />
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="normal" gradientTransform="rotate(45 0 0)">
|
||||
<stop stop-color="#4b4b4b" offset="0" />
|
||||
<stop stop-color="#171717" offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="pressed" gradientTransform="rotate(45 0 0)">
|
||||
<stop stop-color="#171717" offset="0" />
|
||||
<stop stop-color="#4b4b4b" offset="1" />
|
||||
</linearGradient>
|
||||
<circle class="shadow" r="220" cx="800" cy="800" fill="black" />
|
||||
<circle class="light" @mousedown="toggleButtonState(true)" @mouseup="toggleButtonState(false)"
|
||||
@contextmenu.prevent="openContextMenu($event)" :r="btnHeight" cx="800" cy="800"
|
||||
fill-opacity="0.9" style="pointer-events: auto;"/>
|
||||
|
||||
<!-- 按钮主体 -->
|
||||
<circle r="220" cx="800" cy="800" fill="black" filter="url(#btn-shadow)" />
|
||||
<circle
|
||||
:r="btnHeight"
|
||||
cx="800"
|
||||
cy="800"
|
||||
:fill="isKeyPressed ? 'url(#pressed)' : 'url(#normal)'"
|
||||
fill-opacity="0.9"
|
||||
@mousedown="toggleButtonState(true)"
|
||||
@mouseup="toggleButtonState(false)"
|
||||
@contextmenu.prevent="openContextMenu($event)"
|
||||
style="pointer-events: auto; transition: all 20ms ease-in-out;"
|
||||
/>
|
||||
|
||||
<!-- 按键文字 -->
|
||||
<text
|
||||
v-if="bindKey"
|
||||
x="800"
|
||||
|
@ -40,20 +55,23 @@
|
|||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
fill="#ccc"
|
||||
style="font-family: Arial; filter: url(#shadow); user-select: none; pointer-events: none; mix-blend-mode: overlay;"
|
||||
style="font-family: Arial; filter: url(#btn-shadow); user-select: none; pointer-events: none; mix-blend-mode: overlay;"
|
||||
>
|
||||
{{ bindKey.toUpperCase() }}
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
<div v-if="showContextMenu"
|
||||
:style="{ top: contextMenuY + 'px', left: contextMenuX + 'px' }"
|
||||
@click.stop
|
||||
class="fixed z-50 border border-base-300 bg-base-100 rounded-md shadow-lg">
|
||||
<div class="px-4 py-2 cursor-pointer whitespace-nowrap text-base-content hover:bg-base-200"
|
||||
@click="startBinding">
|
||||
<span v-if="isBinding">请输入</span>
|
||||
<span v-else>绑定按键: {{ bindKey ? bindKey.toUpperCase() : '未绑定' }}</span>
|
||||
</svg>
|
||||
|
||||
<!-- 使用DaisyUI的卡片组件实现上下文菜单 -->
|
||||
<div v-if="showContextMenu"
|
||||
class="card card-compact fixed z-50 shadow-lg bg-base-100 border border-base-300"
|
||||
:style="{ top: contextMenuY + 'px', left: contextMenuX + 'px' }"
|
||||
@click.stop>
|
||||
<div class="card-body p-0">
|
||||
<button class="btn btn-ghost justify-start normal-case w-full h-full" @click="startBinding">
|
||||
<span v-if="isBinding">请输入</span>
|
||||
<span v-else>绑定按键: {{ bindKey ? bindKey.toUpperCase() : '未绑定' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -65,29 +83,28 @@ interface Props {
|
|||
width?: string | number
|
||||
height?: string | number
|
||||
}
|
||||
const bindKey = ref('');
|
||||
let isKeyPressed = false;
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
width: 160,
|
||||
height: 160,
|
||||
})
|
||||
|
||||
const btnHeight = ref(200)
|
||||
|
||||
const colorMatrix = ref("1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0")
|
||||
|
||||
function toggleButtonState(isPressed: boolean) {
|
||||
btnHeight.value = isPressed ? 210 : 200;
|
||||
colorMatrix.value = isPressed
|
||||
? "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.7 0"
|
||||
: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0";
|
||||
}
|
||||
|
||||
const bindKey = ref('');
|
||||
let isKeyPressed = false;
|
||||
const btnHeight = ref(200);
|
||||
const colorMatrix = ref("1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0");
|
||||
const isBinding = ref(false);
|
||||
const showContextMenu = ref(false);
|
||||
const contextMenuX = ref(0);
|
||||
const contextMenuY = ref(0);
|
||||
|
||||
function toggleButtonState(isPressed: boolean) {
|
||||
btnHeight.value = isPressed ? 210 : 200;
|
||||
colorMatrix.value = isPressed
|
||||
? "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.7 0"
|
||||
: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0";
|
||||
}
|
||||
|
||||
function openContextMenu(e: MouseEvent) {
|
||||
contextMenuX.value = e.clientX;
|
||||
contextMenuY.value = e.clientY;
|
||||
|
@ -135,21 +152,3 @@ onUnmounted(() => {
|
|||
window.removeEventListener('click', closeContextMenu);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
circle {
|
||||
transition: all 20ms ease-in-out;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
filter: url(#shadow);
|
||||
}
|
||||
|
||||
.light:active {
|
||||
fill: url(#pressed);
|
||||
}
|
||||
|
||||
.light {
|
||||
fill: url(#normal);
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue