graph babay
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user