-
Notifications
You must be signed in to change notification settings - Fork 0
/
FollowMouse.svelte
56 lines (50 loc) · 1.73 KB
/
FollowMouse.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!--
@component
the children of this component will follow the user pointer
@slot `default` - the main content of the component
-->
<script lang="ts" context="module">
function computeOpacity(full: number | undefined, current: number | undefined): number {
return Math.abs(1 - Math.abs((full ?? 0) / 2 - (current ?? 0)) / (((full ?? 1) * 1) / 2))
}
</script>
<script lang="ts">
import _ from 'lodash'
import { canHover$ } from './helpers/media-queries'
import { useWobble } from './helpers/wobble-svelte'
/** @default true */
export let fadeOutAtEdge = true
let viewportHeight: number = 0
let viewportWidth: number = 0
let mousePosition: { x: number; y: number } = { x: 0, y: 0 }
// $: mousePosition = { x: viewportWidth / 2, y: viewportHeight / 2 }
let [x, setX] = useWobble({ damping: 2.5, stiffness: 3, fromValue: mousePosition.x })
let [y, setY] = useWobble({ damping: 2.5, stiffness: 3, fromValue: mousePosition.y })
$: {
setX(mousePosition.x)
setY(mousePosition.y)
}
let opacity = 1
$: fadeOutAtEdge &&
(opacity = Math.min(computeOpacity(viewportHeight, $y), computeOpacity(viewportWidth, $x)))
let height = 0
let width = 0
</script>
<svelte:window
bind:innerHeight={viewportHeight}
bind:innerWidth={viewportWidth}
on:pointermove={_.throttle(e => (mousePosition = { x: e.clientX, y: e.clientY }), 50, {
leading: true,
trailing: true,
})} />
{#if $canHover$}
<div
data-name="follow-mouse"
bind:clientHeight={height}
bind:clientWidth={width}
style="opacity: {opacity}; transform: translate({$x - width / 2}px, {$y -
height / 2}px); will-change: transform, opacity;"
class="fixed z-10 top-0 left-0 pointer-events-none select-none">
<slot />
</div>
{/if}