graph babay

This commit is contained in:
2025-12-01 16:32:21 +01:00
parent 992e01bb7b
commit 97b69149ca
2 changed files with 63 additions and 59 deletions

View File

@@ -1,40 +1,62 @@
<script setup lang="ts"> <script setup lang="ts">
import {motion, type MotionValue} from "motion-v"; import {motion, frame} from "motion-v";
function getRandomArbitrary(min: number, max: number): number {
return Math.random() * (max - min) + min;
}
const { const {
x,
y,
name, name,
img = undefined, img = undefined,
color = 'bg-white', color = 'bg-white',
hOffset = undefined, textTop = false,
vOffset = undefined, moveFactor = undefined
} = defineProps<{ } = defineProps<{
x: MotionValue<number>,
y: MotionValue<number>,
name: string, name: string,
img?: string, img?: string,
color?: string, color?: string,
hOffset?: string, textTop?: boolean,
vOffset?: string, moveFactor?: number
}>() }>()
const isHoveringParent = ref(false) const isHoveringParent = ref(false)
const roundedDivClass = `rounded-full w-full h-full absolute ${color}` const roundedDivClass = `rounded-full w-full h-full absolute ${color}`
const hOffsetValue = hOffset === undefined ? '' : hOffset const moveFactorValue = moveFactor ? moveFactor : getRandomArbitrary(8.0, 30.0)
const vOffsetValue = vOffset === undefined ? '' : vOffset
const computedClass = `w-20 h-20 absolute avatar ${hOffsetValue} ${vOffsetValue}` const spring = {damping: 5, stiffness: 50, restDelta: 0.001}
const elementRef = useTemplateRef('elementRef')
const xPoint = useMotionValue(0)
const yPoint = useMotionValue(0)
const x = useSpring(xPoint, spring)
const y = useSpring(yPoint, spring)
const handlePointerMove = ({clientX, clientY}: { clientX: number; clientY: number }) => {
const element = elementRef.value?.$el
if (!element) return
frame.read(() => {
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2)/moveFactorValue)
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2)/moveFactorValue)
})
}
onMounted(() => {
window.addEventListener("pointermove", handlePointerMove)
})
onUnmounted(() => {
window.removeEventListener("pointermove", handlePointerMove)
})
</script> </script>
<template> <template>
<motion.div <motion.div
ref="elementRef" ref="elementRef"
:class="computedClass" class="w-30 h-30 avatar absolute"
:style="{ x, y }" :style="{ x, y }"
:while-hover="{ scale: 3 }" :while-hover="{ scale: 2 }"
@hover-start="event => {isHoveringParent=true}" @hover-start="event => {isHoveringParent=true}"
@hover-end="event => {isHoveringParent=false}"> @hover-end="event => {isHoveringParent=false}">
@@ -44,6 +66,7 @@ const computedClass = `w-20 h-20 absolute avatar ${hOffsetValue} ${vOffsetValue}
<div v-else :class="roundedDivClass"/> <div v-else :class="roundedDivClass"/>
<motion.p <motion.p
v-if="textTop"
v-show="isHoveringParent" v-show="isHoveringParent"
class="-top-8 absolute text-xs" class="-top-8 absolute text-xs"
:initial="{ opacity: 0 }" :initial="{ opacity: 0 }"
@@ -51,6 +74,16 @@ const computedClass = `w-20 h-20 absolute avatar ${hOffsetValue} ${vOffsetValue}
:exit="{ opacity: 0 }"> :exit="{ opacity: 0 }">
{{ name }} {{ name }}
</motion.p> </motion.p>
<motion.p
v-else
v-show="isHoveringParent"
class="-bottom-8 absolute text-xs"
:initial="{ opacity: 0 }"
:animate="{ opacity: 1 }"
:exit="{ opacity: 0 }">
{{ name }}
</motion.p>
</motion.div> </motion.div>
</template> </template>

View File

@@ -1,76 +1,47 @@
<script setup lang="ts"> <script setup lang="ts">
import {frame} from "motion-v";
import GraphNode from "~/components/GraphNode.vue";
const spring = {damping: 5, stiffness: 50, restDelta: 0.001}
const elementRef = useTemplateRef('elementRef')
const xPoint = useMotionValue(0)
const yPoint = useMotionValue(0)
const x = useSpring(xPoint, spring)
const y = useSpring(yPoint, spring)
const handlePointerMove = ({clientX, clientY}: { clientX: number; clientY: number }) => {
const element = elementRef.value?.$el
if (!element) return
frame.read(() => {
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2) / 10)
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2) / 10)
})
}
onMounted(() => {
window.addEventListener("pointermove", handlePointerMove)
})
onUnmounted(() => {
window.removeEventListener("pointermove", handlePointerMove)
})
const nodes = [ const nodes = [
{ {
name: "DevOps engineer", name: "DevOps engineer",
color: "bg-blue-100", color: "bg-blue-100",
hOffset: 'left-20', hOffset: 'left-30',
vOffset: 'top-20', vOffset: 'top-30',
}, },
{ {
name: "Game developer", name: "Game developer",
color: "bg-blue-200", color: "bg-blue-200",
hOffset: 'right-20', hOffset: 'right-30',
vOffset: 'top-20', vOffset: 'top-30',
}, },
{ {
name: "Fullstack developer", name: "Fullstack developer",
color: "bg-blue-300", color: "bg-blue-300",
hOffset: 'left-20', hOffset: 'left-30',
vOffset: 'bottom-20', vOffset: 'bottom-30',
textTop: true
}, },
{ {
name: "Tools programmer", name: "Tools programmer",
color: "bg-blue-400", color: "bg-blue-400",
hOffset: 'right-20', hOffset: 'right-30',
vOffset: 'bottom-20', vOffset: 'bottom-30',
textTop: true
}, },
] ]
</script> </script>
<template> <template>
<div class="hero bg-base-200 min-h-screen"> <div class="hero bg-base-200 min-h-screen">
<div class="hero-content overflow-hidden bg-"> <div class="overflow-hidden">
<GraphNode ref="elementRef" :x="x" :y="y" img="/face.jpg" name="Hi, I'm Alex" /> <GraphNode img="/face.jpg" name="Hi, I'm Alex" :text-top="true" :move-factor="6"/>
<ul v-for="(node, index) in nodes" :key="index"> <ul v-for="(node, index) in nodes" :key="index">
<li> <li>
<GraphNode <GraphNode
:x="x"
:y="y"
:name="node.name" :name="node.name"
:color="node.color" :color="node.color"
:hOffset="node.hOffset" :class="`${node.hOffset} ${node.vOffset}`"
:vOffset="node.vOffset"/> :text-top="node.textTop"/>
</li> </li>
</ul> </ul>
</div> </div>