text customization
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {motion, frame} from "motion-v";
|
import {motion, frame} from "motion-v";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
img = undefined,
|
img = undefined,
|
||||||
@@ -9,6 +10,8 @@ const {
|
|||||||
scaleFactor = 2,
|
scaleFactor = 2,
|
||||||
initialWidth = undefined,
|
initialWidth = undefined,
|
||||||
initialHeight = undefined,
|
initialHeight = undefined,
|
||||||
|
topTextOffset = undefined,
|
||||||
|
bottomTextOffset = undefined,
|
||||||
} = defineProps<{
|
} = defineProps<{
|
||||||
name: string,
|
name: string,
|
||||||
img?: string,
|
img?: string,
|
||||||
@@ -18,12 +21,18 @@ const {
|
|||||||
scaleFactor?: number,
|
scaleFactor?: number,
|
||||||
initialWidth?: string,
|
initialWidth?: string,
|
||||||
initialHeight?: string,
|
initialHeight?: string,
|
||||||
|
topTextOffset?: string,
|
||||||
|
bottomTextOffset?: string,
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['positionChanged'])
|
const emit = defineEmits(['positionChanged'])
|
||||||
|
|
||||||
const isHoveringParent = ref(false)
|
const isHoveringParent = ref(false)
|
||||||
const roundedDivClass = `rounded-full w-full h-full absolute ${color}`
|
|
||||||
|
const imageMaskClass = `avatar mask mask-squircle ${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'}`
|
||||||
|
const roundedDivClass = `rounded-full absolute ${color} ${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'}`
|
||||||
|
const topTextClass = `absolute w-full text-center ${topTextOffset ? topTextOffset : '-top-30'}`
|
||||||
|
const bottomTextClass = `absolute w-full text-center ${bottomTextOffset ? bottomTextOffset : '-bottom-30'}`
|
||||||
|
|
||||||
function getRandomArbitrary(min: number, max: number): number {
|
function getRandomArbitrary(min: number, max: number): number {
|
||||||
return Math.random() * (max - min) + min;
|
return Math.random() * (max - min) + min;
|
||||||
@@ -42,8 +51,8 @@ const handlePointerMove = ({clientX, clientY}: { clientX: number; clientY: numbe
|
|||||||
const element = elementRef.value?.$el
|
const element = elementRef.value?.$el
|
||||||
if (!element) return
|
if (!element) return
|
||||||
frame.read(() => {
|
frame.read(() => {
|
||||||
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2)/moveFactorValue)
|
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2) / moveFactorValue)
|
||||||
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2)/moveFactorValue)
|
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2) / moveFactorValue)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +62,8 @@ useRafFn(() => {
|
|||||||
return
|
return
|
||||||
emit(
|
emit(
|
||||||
'positionChanged',
|
'positionChanged',
|
||||||
x.get() + element.offsetLeft + element.offsetWidth/2,
|
x.get() + element.offsetLeft + element.offsetWidth / 2,
|
||||||
y.get() + element.offsetTop + element.offsetHeight/2,)
|
y.get() + element.offsetTop + element.offsetHeight / 2,)
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -65,43 +74,50 @@ onUnmounted(() => {
|
|||||||
window.removeEventListener("pointermove", handlePointerMove)
|
window.removeEventListener("pointermove", handlePointerMove)
|
||||||
})
|
})
|
||||||
|
|
||||||
const baseElementClass = ref(`${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'} avatar absolute`)
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<motion.div
|
<motion.div
|
||||||
ref="elementRef"
|
ref="elementRef"
|
||||||
:class="baseElementClass"
|
class="w-60 h-24 absolute flex items-center justify-center"
|
||||||
:style="{ x, y }"
|
:style="{ x, y }">
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
v-if="img !== undefined"
|
||||||
|
:class="imageMaskClass"
|
||||||
:while-hover="{ scale: scaleFactor }"
|
:while-hover="{ scale: scaleFactor }"
|
||||||
@hover-start="event => {isHoveringParent=true}"
|
@hover-start="event => {isHoveringParent=true}"
|
||||||
@hover-end="event => {isHoveringParent=false}">
|
@hover-end="event => {isHoveringParent=false}">
|
||||||
|
|
||||||
<div v-if="img !== undefined" class="mask mask-squircle w-full">
|
|
||||||
<NuxtImg :src="img"/>
|
<NuxtImg :src="img"/>
|
||||||
</div>
|
</motion.div>
|
||||||
<div v-else :class="roundedDivClass"/>
|
<motion.div
|
||||||
|
v-else
|
||||||
|
:class="roundedDivClass"
|
||||||
|
:while-hover="{ scale: scaleFactor }"
|
||||||
|
@hover-start="event => {isHoveringParent=true}"
|
||||||
|
@hover-end="event => {isHoveringParent=false}"/>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
<motion.p
|
<motion.p
|
||||||
v-if="textTop"
|
v-if="textTop"
|
||||||
v-show="isHoveringParent"
|
v-show="isHoveringParent"
|
||||||
class="-top-8 absolute text-xs"
|
:class="topTextClass"
|
||||||
:initial="{ opacity: 0 }"
|
:initial="{ opacity: 0, scale: 0 }"
|
||||||
:animate="{ opacity: 1 }"
|
:animate="{ opacity: 1, scale: 1 }"
|
||||||
:exit="{ opacity: 0 }">
|
:exit="{ opacity: 0, scale: 0 }">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</motion.p>
|
</motion.p>
|
||||||
|
|
||||||
<motion.p
|
<motion.p
|
||||||
v-else
|
v-else
|
||||||
v-show="isHoveringParent"
|
v-show="isHoveringParent"
|
||||||
class="-bottom-8 absolute text-xs"
|
:class="bottomTextClass"
|
||||||
:initial="{ opacity: 0 }"
|
:initial="{ opacity: 0, scale: 0 }"
|
||||||
:animate="{ opacity: 1 }"
|
:animate="{ opacity: 1, scale: 1 }"
|
||||||
:exit="{ opacity: 0 }">
|
:exit="{ opacity: 0, scale: 0 }">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</motion.p>
|
</motion.p>
|
||||||
|
</AnimatePresence>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ const nodes = [
|
|||||||
img: "/face.jpg",
|
img: "/face.jpg",
|
||||||
textTop: true,
|
textTop: true,
|
||||||
moveFactor: 6,
|
moveFactor: 6,
|
||||||
|
initialWidth: 'w-50',
|
||||||
|
initialHeight: 'h-50',
|
||||||
|
scaleFactor: 2,
|
||||||
hOffset: 'left-1/3',
|
hOffset: 'left-1/3',
|
||||||
vOffset: 'top-1/3',
|
vOffset: 'top-1/3',
|
||||||
|
topTextOffset: '-top-50',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DevOps engineer",
|
name: "DevOps engineer",
|
||||||
@@ -17,6 +21,7 @@ const nodes = [
|
|||||||
initialWidth: 'w-2',
|
initialWidth: 'w-2',
|
||||||
initialHeight: 'h-2',
|
initialHeight: 'h-2',
|
||||||
scaleFactor: 10,
|
scaleFactor: 10,
|
||||||
|
bottomTextOffset: '-bottom-10'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Game developer",
|
name: "Game developer",
|
||||||
@@ -98,6 +103,8 @@ useRafFn(() => {
|
|||||||
:scale-factor="node.scaleFactor"
|
:scale-factor="node.scaleFactor"
|
||||||
:initial-width="node.initialWidth"
|
:initial-width="node.initialWidth"
|
||||||
:initial-height="node.initialHeight"
|
:initial-height="node.initialHeight"
|
||||||
|
:top-text-offset="node.topTextOffset"
|
||||||
|
:bottom-text-offset="node.bottomTextOffset"
|
||||||
@position-changed="(x, y) => { nodeMoved(index, x, y) }"/>
|
@position-changed="(x, y) => { nodeMoved(index, x, y) }"/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Reference in New Issue
Block a user