在任意网页中加载鼠标波浪特效的油猴脚本
网上冲浪🏄🏻看到 狂奔滴小马的博客里的一个特效,他博客源码里是一个TS写的插件,我通过AI把它转成了js的版本如下:
class Wave {
constructor({ phase = 0, offset = 0, frequency = 0.001, amplitude = 1 } = {}) {
this.phase = phase;
this.offset = offset;
this.frequency = frequency;
this.amplitude = amplitude;
}
update() {
this.phase += this.frequency;
return this.offset + Math.sin(this.phase) * this.amplitude;
}
}
class Node {
constructor() {
this.x = 0;
this.y = 0;
this.vy = 0;
this.vx = 0;
}
}
class Line {
constructor({ spring }, pos) {
this.spring = spring + 0.1 * Math.random() - 0.05;
this.friction = E.friction + 0.01 * Math.random() - 0.005;
this.nodes = [];
this.pos = pos;
for (let i = 0; i < E.size; i++) {
const node = new Node();
node.x = this.pos.x;
node.y = this.pos.y;
this.nodes.push(node);
}
}
update() {
let spring = this.spring;
let node = this.nodes[0];
node.vx += (this.pos.x - node.x) * spring;
node.vy += (this.pos.y - node.y) * spring;
for (let i = 0; i < this.nodes.length; i++) {
node = this.nodes[i];
if (i > 0) {
const prevNode = this.nodes[i - 1];
node.vx += (prevNode.x - node.x) * spring;
node.vy += (prevNode.y - node.y) * spring;
node.vx += prevNode.vx * E.dampening;
node.vy += prevNode.vy * E.dampening;
}
node.vx *= this.friction;
node.vy *= this.friction;
node.x += node.vx;
node.y += node.vy;
spring *= E.tension;
}
}
draw(ctx) {
let currNode, nextNode;
let x = this.nodes[0].x;
let y = this.nodes[0].y;
ctx.beginPath();
ctx.moveTo(x, y);
for (let i = 1; i < this.nodes.length - 2; i++) {
currNode = this.nodes[i];
nextNode = this.nodes[i + 1];
x = 0.5 * (currNode.x + nextNode.x);
y = 0.5 * (currNode.y + nextNode.y);
ctx.quadraticCurveTo(currNode.x, currNode.y, x, y);
}
currNode = this.nodes[this.nodes.length - 2];
nextNode = this.nodes[this.nodes.length - 1];
ctx.quadraticCurveTo(currNode.x, currNode.y, nextNode.x, nextNode.y);
ctx.stroke();
ctx.closePath();
}
}
const E = {
friction: 0.5,
trails: 20,
size: 50,
dampening: 0.25,
tension: 0.98,
};
function renderCanvas() {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let lines = [];
const pos = { x: 0, y: 0 };
const wave = new Wave({
phase: Math.random() * 2 * Math.PI,
amplitude: 85,
frequency: 0.0015,
offset: 285,
});
let running = true;
let frame = 1;
function resizeCanvas() {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
}
resizeCanvas();
function animate() {
if (running) {
ctx.globalCompositeOperation = "source-over";
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = "lighter";
ctx.strokeStyle = `hsla(${Math.round(wave.update())},90%,50%,0.25)`;
ctx.lineWidth = 1;
for (let i = 0; i < E.trails; i++) {
const line = lines[i];
line.update();
line.draw(ctx);
}
frame++;
window.requestAnimationFrame(animate);
}
}
function bindMouseMove(event) {
function drawLine() {
lines = [];
for (let i = 0; i < E.trails; i++) {
lines.push(new Line({ spring: 0.45 + (i / E.trails) * 0.025 }, pos));
}
}
function move(e) {
if (e.touches) {
pos.x = e.touches[0].pageX;
pos.y = e.touches[0].pageY;
} else {
pos.x = e.clientX;
pos.y = e.clientY;
}
e.preventDefault();
}
function start(e) {
if (e.touches.length === 1) {
pos.x = e.touches[0].pageX;
pos.y = e.touches[0].pageY;
}
}
document.removeEventListener("mousemove", bindMouseMove);
document.removeEventListener("touchstart", bindMouseMove);
document.addEventListener("mousemove", move);
document.addEventListener("touchmove", move);
document.addEventListener("touchstart", start);
move(event);
drawLine();
animate();
}
document.addEventListener("mousemove", bindMouseMove);
document.addEventListener("touchstart", bindMouseMove);
window.addEventListener("resize", resizeCanvas);
}
// Call this function in your HTML file
// Example usage:
// <canvas id="canvas"></canvas>
// <script src="wave-effect.js"></script>
// <script>renderCanvas();</script>
油猴脚本如下:
需要动态的创建一个canvas的dom节点浮在最上层,但不能影响交互
// ==UserScript==
// @name Wave Effect
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 在任意网页上添加鼠标波浪特效
// @author me
// @match *://*/*
// @grant none
// ==/UserScript==
(function () {
"use strict";
// 创建 Canvas 元素并添加到页面
const canvas = document.createElement("canvas");
canvas.id = "wave-effect-canvas";
canvas.style.position = "fixed";
canvas.style.top = "0";
canvas.style.left = "0";
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.pointerEvents = "none"; // 确保不会影响页面交互
canvas.style.zIndex = "9999"; // 覆盖其他内容
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
// 调整 Canvas 尺寸
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener("resize", resizeCanvas);
// 波浪特效逻辑
class Wave {
constructor({ phase = 0, offset = 0, frequency = 0.001, amplitude = 1 } = {}) {
this.phase = phase;
this.offset = offset;
this.frequency = frequency;
this.amplitude = amplitude;
}
update() {
this.phase += this.frequency;
return this.offset + Math.sin(this.phase) * this.amplitude;
}
}
class Node {
constructor() {
this.x = 0;
this.y = 0;
this.vy = 0;
this.vx = 0;
}
}
class Line {
constructor({ spring }, pos) {
this.spring = spring + 0.1 * Math.random() - 0.05;
this.friction = E.friction + 0.01 * Math.random() - 0.005;
this.nodes = [];
this.pos = pos;
for (let i = 0; i < E.size; i++) {
const node = new Node();
node.x = this.pos.x;
node.y = this.pos.y;
this.nodes.push(node);
}
}
update() {
let spring = this.spring;
let node = this.nodes[0];
node.vx += (this.pos.x - node.x) * spring;
node.vy += (this.pos.y - node.y) * spring;
for (let i = 0; i < this.nodes.length; i++) {
node = this.nodes[i];
if (i > 0) {
const prevNode = this.nodes[i - 1];
node.vx += (prevNode.x - node.x) * spring;
node.vy += (prevNode.y - node.y) * spring;
node.vx += prevNode.vx * E.dampening;
node.vy += prevNode.vy * E.dampening;
}
node.vx *= this.friction;
node.vy *= this.friction;
node.x += node.vx;
node.y += node.vy;
spring *= E.tension;
}
}
draw(ctx) {
let currNode, nextNode;
let x = this.nodes[0].x;
let y = this.nodes[0].y;
ctx.beginPath();
ctx.moveTo(x, y);
for (let i = 1; i < this.nodes.length - 2; i++) {
currNode = this.nodes[i];
nextNode = this.nodes[i + 1];
x = 0.5 * (currNode.x + nextNode.x);
y = 0.5 * (currNode.y + nextNode.y);
ctx.quadraticCurveTo(currNode.x, currNode.y, x, y);
}
currNode = this.nodes[this.nodes.length - 2];
nextNode = this.nodes[this.nodes.length - 1];
ctx.quadraticCurveTo(currNode.x, currNode.y, nextNode.x, nextNode.y);
ctx.stroke();
ctx.closePath();
}
}
const E = {
friction: 0.5,
trails: 20,
size: 50,
dampening: 0.25,
tension: 0.98,
};
let lines = [];
const pos = { x: 0, y: 0 };
const wave = new Wave({
phase: Math.random() * 2 * Math.PI,
amplitude: 85,
frequency: 0.0015,
offset: 285,
});
let running = true;
function animate() {
if (running) {
ctx.globalCompositeOperation = "source-over";
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "lighter";
ctx.strokeStyle = `hsla(${Math.round(wave.update())},90%,50%,0.25)`;
ctx.lineWidth = 1;
for (let i = 0; i < E.trails; i++) {
const line = lines[i];
line.update();
line.draw(ctx);
}
requestAnimationFrame(animate);
}
}
function initializeLines() {
lines = [];
for (let i = 0; i < E.trails; i++) {
lines.push(new Line({ spring: 0.45 + (i / E.trails) * 0.025 }, pos));
}
}
document.addEventListener("mousemove", (e) => {
pos.x = e.clientX;
pos.y = e.clientY;
if (lines.length === 0) {
initializeLines();
animate();
}
});
document.addEventListener("touchmove", (e) => {
if (e.touches && e.touches.length === 1) {
pos.x = e.touches[0].pageX;
pos.y = e.touches[0].pageY;
if (lines.length === 0) {
initializeLines();
animate();
}
}
});
})();
尽管花里胡哨就完事儿了~
未经作者授权,禁止转载
本文来自博客园,作者:CoderWGB,转载请注明原文链接:https://www.cnblogs.com/wgb1234/p/18856752
THE END

浙公网安备 33010602011771号