vue-hover-effect
Version:
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
221 lines (213 loc) • 7.03 kB
JavaScript
import { defineComponent as q, ref as B, onMounted as N, onUnmounted as j, openBlock as $, createElementBlock as J, Fragment as K, createElementVNode as Q, normalizeClass as X, renderSlot as Y } from "vue";
import * as n from "three";
import V from "gsap";
function Z(t) {
console.log(
"%c Hover effect (Single) by Robin Delaporte – https://github.com/robin-dela/hover-effect",
"color: #bada55; font-size: 0.8rem"
);
function i(...o) {
return o.find((r) => r !== void 0);
}
const e = t.parent, d = t.displacementImage, p = t.image1, h = t.image2;
if (!e) {
console.warn("SingleHoverEffect: no parent element provided.");
return;
}
if (!d || !p || !h) {
console.warn("SingleHoverEffect: displacementImage/image1/image2 missing.");
return;
}
const u = i(t.imagesRatio, 1), x = i(t.intensity1, t.intensity, 1), F = i(t.intensity2, t.intensity, 1), v = i(t.angle, Math.PI / 4), W = i(t.angle1, v), M = i(t.angle2, -v * 3), D = i(t.speedIn, t.speed, 1.6), T = i(t.speedOut, t.speed, 1.2), U = i(t.hover, !0), S = i(t.easing, "expo.out"), C = i(t.video, !1), O = new n.Scene(), H = new n.OrthographicCamera(
e.offsetWidth / -2,
e.offsetWidth / 2,
e.offsetHeight / 2,
e.offsetHeight / -2,
1,
1e3
);
H.position.z = 1;
const f = new n.WebGLRenderer({ alpha: !0, antialias: !1 });
f.setPixelRatio(window.devicePixelRatio), f.setClearColor(16777215, 0), f.setSize(e.offsetWidth, e.offsetHeight), e.appendChild(f.domElement);
function c() {
f.render(O, H);
}
const A = `
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`, k = `
varying vec2 vUv;
uniform float dispFactor;
uniform sampler2D disp;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float angle1;
uniform float angle2;
uniform float intensity1;
uniform float intensity2;
uniform vec4 res;
mat2 getRotM(float angle){
float s = sin(angle);
float c = cos(angle);
return mat2(c, -s, s, c);
}
void main(){
// displacement
vec4 dispTex = texture2D(disp, vUv);
vec2 dispVec = dispTex.rg;
// Simple approach
vec2 uv = vUv;
vec2 distortedPos1 = uv + getRotM(angle1) * dispVec * intensity1 * dispFactor;
vec2 distortedPos2 = uv + getRotM(angle2) * dispVec * intensity2 * (1.0 - dispFactor);
vec4 _texture1 = texture2D(texture1, distortedPos1);
vec4 _texture2 = texture2D(texture2, distortedPos2);
gl_FragColor = mix(_texture1, _texture2, dispFactor);
}
`, w = new n.TextureLoader();
w.crossOrigin = "";
const b = w.load(d, c);
b.magFilter = b.minFilter = n.LinearFilter;
let a, s;
if (C) {
const o = document.createElement("video");
o.autoplay = !0, o.loop = !0, o.muted = !0, o.src = p, o.load();
const r = document.createElement("video");
r.autoplay = !0, r.loop = !0, r.muted = !0, r.src = h, r.load(), a = new n.VideoTexture(o), s = new n.VideoTexture(r), a.magFilter = a.minFilter = n.LinearFilter, s.magFilter = s.minFilter = n.LinearFilter, o.addEventListener("loadeddata", () => {
o.play(), a = new n.VideoTexture(o), a.magFilter = a.minFilter = n.LinearFilter, g.uniforms.texture1.value = a;
}), r.addEventListener("loadeddata", () => {
r.play(), s = new n.VideoTexture(r), s.magFilter = s.minFilter = n.LinearFilter, g.uniforms.texture2.value = s;
}), requestAnimationFrame(function l() {
requestAnimationFrame(l), f.render(O, H);
});
} else
a = w.load(p, c), s = w.load(h, c), a.magFilter = a.minFilter = n.LinearFilter, s.magFilter = s.minFilter = n.LinearFilter;
let y = 1, E = 1;
function R(o, r) {
const l = o || e.offsetWidth, m = r || e.offsetHeight;
m / l < u ? (y = 1, E = m / l / u) : (y = l / m * u, E = 1);
}
R();
const g = new n.ShaderMaterial({
uniforms: {
dispFactor: { value: 0 },
disp: { value: b },
texture1: { value: a },
texture2: { value: s },
angle1: { value: W },
angle2: { value: M },
intensity1: { value: x },
intensity2: { value: F },
res: {
value: new n.Vector4(
e.offsetWidth,
e.offsetHeight,
y,
E
)
}
},
vertexShader: A,
fragmentShader: k,
transparent: !0,
opacity: 1
}), G = new n.PlaneGeometry(e.offsetWidth, e.offsetHeight, 1), z = new n.Mesh(G, g);
O.add(z);
function L() {
V.to(g.uniforms.dispFactor, {
duration: D,
value: 1,
ease: S,
onUpdate: c,
onComplete: c
});
}
function I() {
V.to(g.uniforms.dispFactor, {
duration: T,
value: 0,
ease: S,
onUpdate: c,
onComplete: c
});
}
U && (e.addEventListener("mouseenter", L), e.addEventListener("mouseleave", I), e.addEventListener("touchstart", L), e.addEventListener("touchend", I));
function P(o, r) {
const l = o || e.offsetWidth, m = r || e.offsetHeight;
f.setSize(l, m), R(l, m), g.uniforms.res.value.set(
l,
m,
y,
E
), z.geometry = new n.PlaneGeometry(
l,
m,
1
), c();
}
return window.addEventListener("resize", () => P()), {
next: L,
// image1 → image2
previous: I,
// image2 → image1
resize: P
};
}
const te = /* @__PURE__ */ q({
__name: "SingleHoverEffect",
props: {
hoverOptions: { default: () => ({
image1: "/lib-images/images/Img22.webp",
image2: "/lib-images/images/Img21.webp",
displacementImage: "/lib-images/displacements/3.webp",
hover: !0,
speedIn: 0.8,
speedOut: 0.8
}) },
distortionClass: { default: "" }
},
setup(t) {
const i = B(null);
let e, d;
N(() => {
i.value && (e = Z({
...t.hoverOptions,
parent: i.value,
image1: t.hoverOptions.image1,
image2: t.hoverOptions.image2,
displacementImage: t.hoverOptions.displacementImage,
hover: t.hoverOptions.hover,
speedIn: t.hoverOptions.speedIn,
speedOut: t.hoverOptions.speedOut
}), window.ResizeObserver && (d = new ResizeObserver((u) => {
var x, F;
for (const v of u)
v.target === i.value && (e == null || e.resize((x = v.target) == null ? void 0 : x.clientWidth, (F = v.target) == null ? void 0 : F.clientHeight));
}), d.observe(i.value)));
});
function p() {
e == null || e.next();
}
function h() {
e == null || e.previous();
}
return j(() => {
e = void 0, d && i.value && (d.unobserve(i.value), d.disconnect());
}), (u, x) => ($(), J(K, null, [
Q("div", {
ref_key: "container",
ref: i,
class: X(["distortion-container", u.distortionClass])
}, null, 2),
Y(u.$slots, "controllers", {
funcs: { goNext: p, goPrev: h }
})
], 64));
}
});
export {
te as SingleHoverEffect,
Z as createSingleHoverEffect
};