Skip to content

Commit 09cdaa6

Browse files
authored
Merge pull request #692 from arshaan-abh/main
The LiquidEther component must overlay other elements for its pointer effect to work, despite being a background
2 parents 22ef46b + 98cb58e commit 09cdaa6

File tree

4 files changed

+222
-134
lines changed

4 files changed

+222
-134
lines changed

src/content/Backgrounds/LiquidEther/LiquidEther.jsx

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,8 @@ export default function LiquidEther({
121121
this.diff = new THREE.Vector2();
122122
this.timer = null;
123123
this.container = null;
124-
this._onMouseMove = this.onDocumentMouseMove.bind(this);
125-
this._onTouchStart = this.onDocumentTouchStart.bind(this);
126-
this._onTouchMove = this.onDocumentTouchMove.bind(this);
127-
this._onMouseEnter = this.onMouseEnter.bind(this);
128-
this._onMouseLeave = this.onMouseLeave.bind(this);
129-
this._onTouchEnd = this.onTouchEnd.bind(this);
124+
this.docTarget = null;
125+
this.listenerTarget = null;
130126
this.isHoverInside = false;
131127
this.hasUserControl = false;
132128
this.isAutoActive = false;
@@ -137,34 +133,61 @@ export default function LiquidEther({
137133
this.takeoverFrom = new THREE.Vector2();
138134
this.takeoverTo = new THREE.Vector2();
139135
this.onInteract = null;
136+
this._onMouseMove = this.onDocumentMouseMove.bind(this);
137+
this._onTouchStart = this.onDocumentTouchStart.bind(this);
138+
this._onTouchMove = this.onDocumentTouchMove.bind(this);
139+
this._onTouchEnd = this.onTouchEnd.bind(this);
140+
this._onDocumentLeave = this.onDocumentLeave.bind(this);
140141
}
141142
init(container) {
142143
this.container = container;
143-
container.addEventListener('mousemove', this._onMouseMove, false);
144-
container.addEventListener('touchstart', this._onTouchStart, false);
145-
container.addEventListener('touchmove', this._onTouchMove, false);
146-
container.addEventListener('mouseenter', this._onMouseEnter, false);
147-
container.addEventListener('mouseleave', this._onMouseLeave, false);
148-
container.addEventListener('touchend', this._onTouchEnd, false);
144+
this.docTarget = container.ownerDocument || null;
145+
const defaultView =
146+
(this.docTarget && this.docTarget.defaultView) || (typeof window !== 'undefined' ? window : null);
147+
if (!defaultView) return;
148+
this.listenerTarget = defaultView;
149+
this.listenerTarget.addEventListener('mousemove', this._onMouseMove);
150+
this.listenerTarget.addEventListener('touchstart', this._onTouchStart, { passive: true });
151+
this.listenerTarget.addEventListener('touchmove', this._onTouchMove, { passive: true });
152+
this.listenerTarget.addEventListener('touchend', this._onTouchEnd);
153+
if (this.docTarget) {
154+
this.docTarget.addEventListener('mouseleave', this._onDocumentLeave);
155+
}
149156
}
150157
dispose() {
151-
if (!this.container) return;
152-
this.container.removeEventListener('mousemove', this._onMouseMove, false);
153-
this.container.removeEventListener('touchstart', this._onTouchStart, false);
154-
this.container.removeEventListener('touchmove', this._onTouchMove, false);
155-
this.container.removeEventListener('mouseenter', this._onMouseEnter, false);
156-
this.container.removeEventListener('mouseleave', this._onMouseLeave, false);
157-
this.container.removeEventListener('touchend', this._onTouchEnd, false);
158+
if (this.listenerTarget) {
159+
this.listenerTarget.removeEventListener('mousemove', this._onMouseMove);
160+
this.listenerTarget.removeEventListener('touchstart', this._onTouchStart);
161+
this.listenerTarget.removeEventListener('touchmove', this._onTouchMove);
162+
this.listenerTarget.removeEventListener('touchend', this._onTouchEnd);
163+
}
164+
if (this.docTarget) {
165+
this.docTarget.removeEventListener('mouseleave', this._onDocumentLeave);
166+
}
167+
this.listenerTarget = null;
168+
this.docTarget = null;
169+
this.container = null;
170+
}
171+
isPointInside(clientX, clientY) {
172+
if (!this.container) return false;
173+
const rect = this.container.getBoundingClientRect();
174+
if (rect.width === 0 || rect.height === 0) return false;
175+
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
176+
}
177+
updateHoverState(clientX, clientY) {
178+
this.isHoverInside = this.isPointInside(clientX, clientY);
179+
return this.isHoverInside;
158180
}
159181
setCoords(x, y) {
160182
if (!this.container) return;
161-
if (this.timer) clearTimeout(this.timer);
183+
if (this.timer) window.clearTimeout(this.timer);
162184
const rect = this.container.getBoundingClientRect();
185+
if (rect.width === 0 || rect.height === 0) return;
163186
const nx = (x - rect.left) / rect.width;
164187
const ny = (y - rect.top) / rect.height;
165188
this.coords.set(nx * 2 - 1, -(ny * 2 - 1));
166189
this.mouseMoved = true;
167-
this.timer = setTimeout(() => {
190+
this.timer = window.setTimeout(() => {
168191
this.mouseMoved = false;
169192
}, 100);
170193
}
@@ -173,9 +196,12 @@ export default function LiquidEther({
173196
this.mouseMoved = true;
174197
}
175198
onDocumentMouseMove(event) {
199+
if (!this.updateHoverState(event.clientX, event.clientY)) return;
176200
if (this.onInteract) this.onInteract();
177201
if (this.isAutoActive && !this.hasUserControl && !this.takeoverActive) {
202+
if (!this.container) return;
178203
const rect = this.container.getBoundingClientRect();
204+
if (rect.width === 0 || rect.height === 0) return;
179205
const nx = (event.clientX - rect.left) / rect.width;
180206
const ny = (event.clientY - rect.top) / rect.height;
181207
this.takeoverFrom.copy(this.coords);
@@ -190,27 +216,24 @@ export default function LiquidEther({
190216
this.hasUserControl = true;
191217
}
192218
onDocumentTouchStart(event) {
193-
if (event.touches.length === 1) {
194-
const t = event.touches[0];
195-
if (this.onInteract) this.onInteract();
196-
this.setCoords(t.pageX, t.pageY);
197-
this.hasUserControl = true;
198-
}
219+
if (event.touches.length !== 1) return;
220+
const t = event.touches[0];
221+
if (!this.updateHoverState(t.clientX, t.clientY)) return;
222+
if (this.onInteract) this.onInteract();
223+
this.setCoords(t.clientX, t.clientY);
224+
this.hasUserControl = true;
199225
}
200226
onDocumentTouchMove(event) {
201-
if (event.touches.length === 1) {
202-
const t = event.touches[0];
203-
if (this.onInteract) this.onInteract();
204-
this.setCoords(t.pageX, t.pageY);
205-
}
227+
if (event.touches.length !== 1) return;
228+
const t = event.touches[0];
229+
if (!this.updateHoverState(t.clientX, t.clientY)) return;
230+
if (this.onInteract) this.onInteract();
231+
this.setCoords(t.clientX, t.clientY);
206232
}
207233
onTouchEnd() {
208234
this.isHoverInside = false;
209235
}
210-
onMouseEnter() {
211-
this.isHoverInside = true;
212-
}
213-
onMouseLeave() {
236+
onDocumentLeave() {
214237
this.isHoverInside = false;
215238
}
216239
update() {

src/tailwind/Backgrounds/LiquidEther/LiquidEther.jsx

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,8 @@ export default function LiquidEther({
120120
this.diff = new THREE.Vector2();
121121
this.timer = null;
122122
this.container = null;
123-
this._onMouseMove = this.onDocumentMouseMove.bind(this);
124-
this._onTouchStart = this.onDocumentTouchStart.bind(this);
125-
this._onTouchMove = this.onDocumentTouchMove.bind(this);
126-
this._onMouseEnter = this.onMouseEnter.bind(this);
127-
this._onMouseLeave = this.onMouseLeave.bind(this);
128-
this._onTouchEnd = this.onTouchEnd.bind(this);
123+
this.docTarget = null;
124+
this.listenerTarget = null;
129125
this.isHoverInside = false;
130126
this.hasUserControl = false;
131127
this.isAutoActive = false;
@@ -136,34 +132,61 @@ export default function LiquidEther({
136132
this.takeoverFrom = new THREE.Vector2();
137133
this.takeoverTo = new THREE.Vector2();
138134
this.onInteract = null;
135+
this._onMouseMove = this.onDocumentMouseMove.bind(this);
136+
this._onTouchStart = this.onDocumentTouchStart.bind(this);
137+
this._onTouchMove = this.onDocumentTouchMove.bind(this);
138+
this._onTouchEnd = this.onTouchEnd.bind(this);
139+
this._onDocumentLeave = this.onDocumentLeave.bind(this);
139140
}
140141
init(container) {
141142
this.container = container;
142-
container.addEventListener('mousemove', this._onMouseMove, false);
143-
container.addEventListener('touchstart', this._onTouchStart, false);
144-
container.addEventListener('touchmove', this._onTouchMove, false);
145-
container.addEventListener('mouseenter', this._onMouseEnter, false);
146-
container.addEventListener('mouseleave', this._onMouseLeave, false);
147-
container.addEventListener('touchend', this._onTouchEnd, false);
143+
this.docTarget = container.ownerDocument || null;
144+
const defaultView =
145+
(this.docTarget && this.docTarget.defaultView) || (typeof window !== 'undefined' ? window : null);
146+
if (!defaultView) return;
147+
this.listenerTarget = defaultView;
148+
this.listenerTarget.addEventListener('mousemove', this._onMouseMove);
149+
this.listenerTarget.addEventListener('touchstart', this._onTouchStart, { passive: true });
150+
this.listenerTarget.addEventListener('touchmove', this._onTouchMove, { passive: true });
151+
this.listenerTarget.addEventListener('touchend', this._onTouchEnd);
152+
if (this.docTarget) {
153+
this.docTarget.addEventListener('mouseleave', this._onDocumentLeave);
154+
}
148155
}
149156
dispose() {
150-
if (!this.container) return;
151-
this.container.removeEventListener('mousemove', this._onMouseMove, false);
152-
this.container.removeEventListener('touchstart', this._onTouchStart, false);
153-
this.container.removeEventListener('touchmove', this._onTouchMove, false);
154-
this.container.removeEventListener('mouseenter', this._onMouseEnter, false);
155-
this.container.removeEventListener('mouseleave', this._onMouseLeave, false);
156-
this.container.removeEventListener('touchend', this._onTouchEnd, false);
157+
if (this.listenerTarget) {
158+
this.listenerTarget.removeEventListener('mousemove', this._onMouseMove);
159+
this.listenerTarget.removeEventListener('touchstart', this._onTouchStart);
160+
this.listenerTarget.removeEventListener('touchmove', this._onTouchMove);
161+
this.listenerTarget.removeEventListener('touchend', this._onTouchEnd);
162+
}
163+
if (this.docTarget) {
164+
this.docTarget.removeEventListener('mouseleave', this._onDocumentLeave);
165+
}
166+
this.listenerTarget = null;
167+
this.docTarget = null;
168+
this.container = null;
169+
}
170+
isPointInside(clientX, clientY) {
171+
if (!this.container) return false;
172+
const rect = this.container.getBoundingClientRect();
173+
if (rect.width === 0 || rect.height === 0) return false;
174+
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
175+
}
176+
updateHoverState(clientX, clientY) {
177+
this.isHoverInside = this.isPointInside(clientX, clientY);
178+
return this.isHoverInside;
157179
}
158180
setCoords(x, y) {
159181
if (!this.container) return;
160-
if (this.timer) clearTimeout(this.timer);
182+
if (this.timer) window.clearTimeout(this.timer);
161183
const rect = this.container.getBoundingClientRect();
184+
if (rect.width === 0 || rect.height === 0) return;
162185
const nx = (x - rect.left) / rect.width;
163186
const ny = (y - rect.top) / rect.height;
164187
this.coords.set(nx * 2 - 1, -(ny * 2 - 1));
165188
this.mouseMoved = true;
166-
this.timer = setTimeout(() => {
189+
this.timer = window.setTimeout(() => {
167190
this.mouseMoved = false;
168191
}, 100);
169192
}
@@ -172,9 +195,12 @@ export default function LiquidEther({
172195
this.mouseMoved = true;
173196
}
174197
onDocumentMouseMove(event) {
198+
if (!this.updateHoverState(event.clientX, event.clientY)) return;
175199
if (this.onInteract) this.onInteract();
176200
if (this.isAutoActive && !this.hasUserControl && !this.takeoverActive) {
201+
if (!this.container) return;
177202
const rect = this.container.getBoundingClientRect();
203+
if (rect.width === 0 || rect.height === 0) return;
178204
const nx = (event.clientX - rect.left) / rect.width;
179205
const ny = (event.clientY - rect.top) / rect.height;
180206
this.takeoverFrom.copy(this.coords);
@@ -189,27 +215,24 @@ export default function LiquidEther({
189215
this.hasUserControl = true;
190216
}
191217
onDocumentTouchStart(event) {
192-
if (event.touches.length === 1) {
193-
const t = event.touches[0];
194-
if (this.onInteract) this.onInteract();
195-
this.setCoords(t.pageX, t.pageY);
196-
this.hasUserControl = true;
197-
}
218+
if (event.touches.length !== 1) return;
219+
const t = event.touches[0];
220+
if (!this.updateHoverState(t.clientX, t.clientY)) return;
221+
if (this.onInteract) this.onInteract();
222+
this.setCoords(t.clientX, t.clientY);
223+
this.hasUserControl = true;
198224
}
199225
onDocumentTouchMove(event) {
200-
if (event.touches.length === 1) {
201-
const t = event.touches[0];
202-
if (this.onInteract) this.onInteract();
203-
this.setCoords(t.pageX, t.pageY);
204-
}
226+
if (event.touches.length !== 1) return;
227+
const t = event.touches[0];
228+
if (!this.updateHoverState(t.clientX, t.clientY)) return;
229+
if (this.onInteract) this.onInteract();
230+
this.setCoords(t.clientX, t.clientY);
205231
}
206232
onTouchEnd() {
207233
this.isHoverInside = false;
208234
}
209-
onMouseEnter() {
210-
this.isHoverInside = true;
211-
}
212-
onMouseLeave() {
235+
onDocumentLeave() {
213236
this.isHoverInside = false;
214237
}
215238
update() {

0 commit comments

Comments
 (0)