写点什么

酷炫一款动态背景 + 鼠标点击效果(HTML +js canvas)

作者:Five
  • 2022 年 8 月 05 日
  • 本文字数:8802 字

    阅读完需:约 29 分钟

酷炫一款动态背景+鼠标点击效果(HTML +js canvas)

前言

之前用于装饰个人的 Hexo 博客背景和点击事件,于是动手弄弄顺便学习学习,现在分享出来给有需要的人。

废话不多说 ,分享一款酷炫的页面动态背景 效果见(https://fivecc.cn)

动态背景

1. 效果图:


背景效果


实例效果:


博客实例效果

2. 源码:


<!--背景css--><style>* {  margin: 0;  padding: 0;}#canvasBg {  position: fixed;  background: #ccc;  overflow: auto;  z-index: -1;}</style>
<!--背景html--><canvas id="canvasBg"></canvas>
<!--背景js--><script>window.requestAnimationFrame = (function () { return ( window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 2); } );})();var myCanvas = document.getElementById("canvasBg");var ctx = myCanvas.getContext("2d"); //getContext 设置画笔var num;var w, h;var duixiang = [];var move = {};function widthheight() { w = myCanvas.width = window.innerWidth; h = myCanvas.height = window.innerHeight; num = Math.floor(w * h * 0.00028); //点的数量。根据屏幕大小确定 for (var i = 0; i < num; i++) { duixiang[i] = { x: Math.random() * w, y: Math.random() * h, cX: Math.random() * 0.6 - 0.3, cY: Math.random() * 0.6 - 0.3, R: Math.floor(Math.random() * 5) + 2, //CC:Math.floor(Math.random()*3)+2, r: Math.floor(Math.random() * 254), g: Math.floor(Math.random() * 254), b: Math.floor(Math.random() * 254), }; // console.log(duixiang[i]) Cricle( duixiang[i].x, duixiang[i].y, duixiang[i].R, duixiang[i].r, duixiang[i].g, duixiang[i].b ); //Cricle(duixiang[i].x,duixiang[i].y,duixiang[i].R,duixiang[i].CC); }}widthheight(); //获取浏览器的等宽度等高
function Cricle(x, y, R, r, g, b) { ctx.save(); //保存路径 if (Math.random() > 0.991) { ctx.globalAlpha = 0.9; } //ctx.fillStyle = "#CCC";}//填充的背景颜色 else { ctx.globalAlpha = 0.47; }
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")"; ctx.beginPath(); //开始绘画 ctx.arc(x, y, R, Math.PI * 2, 0); //绘画圆 x y 半径(大小) 角度 一个PI 是180 * 2 = 360 真假 0/1 true/false ctx.closePath(); //结束绘画 ctx.fill(); //填充背景颜色 ctx.restore(); //回复路径}Cricle();
!(function draw() { ctx.clearRect(0, 0, w, h); //先清除画布上的点 for (var i = 0; i < num; i++) { duixiang[i].x += duixiang[i].cX; duixiang[i].y += duixiang[i].cY; if (duixiang[i].x > w || duixiang[i].x < 0) { duixiang[i].cX = -duixiang[i].cX; } if (duixiang[i].y > h || duixiang[i].y < 0) { duixiang[i].cY = -duixiang[i].cY; } Cricle( duixiang[i].x, duixiang[i].y, duixiang[i].R, duixiang[i].r, duixiang[i].g, duixiang[i].b ); //勾股定理判断两点是否连线 for (var j = i + 1; j < num; j++) { if ( (duixiang[i].x - duixiang[j].x) * (duixiang[i].x - duixiang[j].x) + (duixiang[i].y - duixiang[j].y) * (duixiang[i].y - duixiang[j].y) <= 55 * 55 ) { line( duixiang[i].x, duixiang[i].y, duixiang[j].x, duixiang[j].y, 0, i, j ); } if (move.x) { if ( (duixiang[i].x - move.x) * (duixiang[i].x - move.x) + (duixiang[i].y - move.y) * (duixiang[i].y - move.y) <= 100 * 100 ) { line(duixiang[i].x, duixiang[i].y, move.x, move.y, 1, i, 1); } } } } window.requestAnimationFrame(draw);})();
//绘制线条function line(x1, y1, x2, y2, flag, i, j) { if (flag) { var color = ctx.createLinearGradient(x1, y1, x2, y2); ctx.globalAlpha = 0.5; color.addColorStop( 0, "rgb(" + duixiang[i].r + "," + duixiang[i].g + "," + duixiang[i].b + ")" ); color.addColorStop(0.8, "#019ee5"); } else { var color = ctx.createLinearGradient(x1, y1, x2, y2); ctx.globalAlpha = 0.9; color.addColorStop( 0, "rgb(" + duixiang[i].r + "," + duixiang[i].g + "," + duixiang[i].b + ")" ); color.addColorStop( 1, "rgb(" + duixiang[j].r + "," + duixiang[j].g + "," + duixiang[j].b + ")" ); } ctx.save(); ctx.strokeStyle = color; ctx.lineWidth = 0.5; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); //ctx.restore();}
//document.onmousemove = function(e){// move.x = e.clientX;// move.y = e.clientY;//}//console.log(move)//去掉注释 ,可以与背景互动
window.onresize = function () { location.reload();};</script>


复制代码

 鼠标点击特效

1.鼠标点击效果


鼠标点击效果

2.鼠标点击效果

<!--鼠标点击css--><style>  #canvasEvent {  position: fixed;  pointer-events: none;  width: 100%;  height: 100%;  overflow: auto;  z-index: 999;}</style>
<!--鼠标点击html--><canvas id="canvasEvent" style="whdth: 100%;height: 100%"></canvas>
<!--鼠标点击html--><script>var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; };})();function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}var getRandom = function getRandom(min, max) { return Math.random() * (max - min) + min;};
var getRandomInt = function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min;};
var getRandomColor = function getRandomColor() { var colors = [ "rgba(231, 76, 60, 1)", // 红 "rgba(241, 196, 15, 1)", // 黄 "rgba(46, 204, 113, 1)", // 绿 "rgba(52, 152, 219, 1)", // 蓝 "rgba(155, 89, 182, 1)", // 紫色 ];
return colors[getRandomInt(0, colors.length)];};
// Particle//粒子模块var Particle = (function () { function Particle(system, x, y) { _classCallCheck(this, Particle); this.system = system; this.universe = this.system.world.universe; this.x = x; this.y = y; this.color = getRandomColor(); this.life = 1; this.aging = getRandom(0.99, 0.999); // 0.99, 0.999 || 0.999, 0.9999
this.r = getRandomInt(12, 16); //初始粒子半径范围 this.speed = getRandom(18, 18.5); //粒子爆炸速度范围 this.velocity = [ getRandom(-this.speed, this.speed), getRandom(-this.speed, this.speed), ]; } _createClass(Particle, [ { key: "update", value: function update(dt) { this.life *= this.aging;
if ( this.r < 0.1 || this.life === 0 || this.x + this.r < 0 || this.x - this.r > this.universe.width || this.y + this.r < 0 || this.y - this.r > this.universe.height ) { this.system.removeObject(this); }
this.r *= this.life; this.x += this.velocity[0]; this.y += this.velocity[1]; }, }, { key: "render", value: function render(ctx) { // Main circle //亮圈模块
ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.r * 1.2, 0, 2 * Math.PI, false); ctx.fill(); ctx.closePath();
var r = this.color.match(/([0-9]+)/g)[0]; var g = this.color.match(/([0-9]+)/g)[1]; var b = this.color.match(/([0-9]+)/g)[2];
// Gradient//梯度变化曲线
var spread = 1.5; var gradient = ctx.createRadialGradient( this.x, this.y, this.r, this.x, this.y, this.r * spread );
gradient.addColorStop(0, "rgba(" + r + ", " + g + ", " + b + ", 0.5)"); gradient.addColorStop(1, "rgba(" + r + ", " + g + ", " + b + ", 0)");
ctx.globalCompositeOperation = "lighter"; ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(this.x, this.y, this.r * spread, 0, 2 * Math.PI, false); ctx.fill(); ctx.closePath(); ctx.globalCompositeOperation = "source-over";
// Aberration//偏差
var offset = this.r * 0.5; var color = "rgba(" + g + ", " + b + ", " + r + ", 0.5)";
ctx.globalCompositeOperation = "lighter"; ctx.fillStyle = color; ctx.beginPath(); ctx.arc( this.x + offset, this.y + offset, this.r, 0, 2 * Math.PI, false ); ctx.fill(); ctx.closePath(); ctx.globalCompositeOperation = "source-over"; }, }, ]); return Particle;})();
// Crown //水波纹圈模块var Crown = (function () { function Crown(system, x, y) { _classCallCheck(this, Crown); this.system = system; this.x = x; this.y = y; this.r = getRandomInt(5, 15); // 5, 20 水波纹圈半径范围 this.mod = 1.1; this.life = 0.5; //水波纹线 this.aging = getRandom(0.83, 0.899); this.speed = getRandom(8, 9); this.color = { r: getRandomInt(236, 242), g: getRandomInt(70, 80), b: getRandomInt(50, 70), };
this.angle1 = Math.PI * getRandom(0, 2); this.angle2 = this.angle1 + Math.PI * getRandom(0.3, 0.4); //水波纹圈完整度 } _createClass(Crown, [ { key: "update", value: function update(dt) { this.life *= this.aging;
if (this.life <= 0.0001) this.system.removeObject(this);
this.r += Math.abs(1 - this.life) * this.speed;
this.x1 = this.x + this.r * Math.cos(this.angle1); this.y1 = this.y + this.r * Math.sin(this.angle1);
this.angle3 = this.angle1 + (this.angle2 - this.angle1) / 2; this.x2 = this.x + this.r * this.mod * Math.cos(this.angle3); this.y2 = this.y + this.r * this.mod * Math.sin(this.angle3); }, }, { key: "render", value: function render(ctx) { var gradient = ctx.createRadialGradient( this.x, this.y, this.r * 0.9, this.x, this.y, this.r );
gradient.addColorStop( 0, "rgba(" + this.color.r + ", " + this.color.g + ", " + this.color.b + ", " + this.life + ")" ); gradient.addColorStop( 1, "rgba(" + this.color.r + ", " + this.color.g + ", " + this.color.b + ", " + this.life * 0.5 + ")" );
ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, this.angle1, this.angle2, false); ctx.quadraticCurveTo(this.x2, this.y2, this.x1, this.y1); ctx.fill(); ctx.closePath(); }, }, ]); return Crown;})();
// Explosion //爆炸模块var Explosion = (function () { function Explosion(world, x, y) { _classCallCheck(this, Explosion); this.world = world; this.x = x; this.y = y; this.objects = [];
var particles = getRandomInt(10, 30); // 10, 30 //爆炸 粒子数量 var crowns = particles * getRandom(0.4, 0.5);
while (crowns-- > 0) { this.addCrown(); } while (particles-- > 0) { this.addParticle(); } } _createClass(Explosion, [ { key: "update", value: function update(dt) { this.objects.forEach(function (obj) { if (obj) obj.update(dt); });
if (this.objects.length <= 0) { this.world.clearExplosion(this); } }, }, { key: "render", value: function render(ctx) { this.objects.forEach(function (obj) { if (obj) obj.render(ctx); }); }, }, { key: "addCrown", value: function addCrown() { this.objects.push(new Crown(this, this.x, this.y)); }, }, { key: "addParticle", value: function addParticle() { this.objects.push(new Particle(this, this.x, this.y)); }, }, { key: "removeObject", value: function removeObject(obj) { var index = this.objects.indexOf(obj);
if (index !== -1) { this.objects.splice(index, 1); } }, }, ]); return Explosion;})();
// Worldvar ConfettiWorld = (function () { function ConfettiWorld() { _classCallCheck(this, ConfettiWorld); } _createClass(ConfettiWorld, [ { key: "init", value: function init() { this.objects = []; window.addEventListener("click", this.explode.bind(this));
// Initial explosion //初始爆炸 var counter = 0; while (counter-- > 0) { this.explode({ clientX: window.event.clientX, //getRandomInt(10, this.universe.width) , //this.universe.width / 2, clientY: window.event.clientY, //getRandomInt(10, 50) //this.universe.height / 2 }); } }, }, { key: "update", value: function update(dt) { this.objects.forEach(function (obj) { if (obj) obj.update(dt); });
var amount = this.objects.reduce(function (sum, explosion) { return (sum += explosion.objects.length); }, 0); }, }, { key: "render", value: function render(ctx) { this.objects.forEach(function (obj) { if (obj) obj.render(ctx); }); }, }, { key: "explode", value: function explode(event) { var x = event.clientX; var y = event.clientY;
this.objects.push(new Explosion(this, x, y)); }, }, { key: "clearExplosion", value: function clearExplosion(explosion) { var index = this.objects.indexOf(explosion);
if (index !== -1) { this.objects.splice(index, 1); } }, }, ]); return ConfettiWorld;})();
// Timevar Time = (function () { function Time() { _classCallCheck(this, Time); this.now = 0; // 当前粒子时间 this.prev = 0; // 上一粒子时间 this.elapsed = 0; //最后粒子时间 this.delta = 0; // 从上次更新开始的时间 this.fps = 60; // 期望fps this.step = 1 / 60; // 步长 } _createClass(Time, [ { key: "update", value: function update(time) { this.now = time; this.elapsed = (this.now - this.prev) / 1000; this.prev = this.now; this.delta += this.elapsed; }, }, { key: "raf", value: function raf(func) { window.requestAnimationFrame(func); }, }, { key: "hasFrames", value: function hasFrames() { return this.delta >= this.step; }, }, { key: "processFrame", value: function processFrame() { this.delta -= this.step; }, }, ]); return Time;})();
// Canvasvar Universe = (function () { function Universe(element) { _classCallCheck(this, Universe); this.el = element; this.ctx = this.el.getContext("2d"); this.pixelRatio = window.devicePixelRatio; this.time = new Time();
this.worlds = {}; this.world = null; // current state
this.updateSize(); window.addEventListener("resize", this.updateSize.bind(this));
this.addWorld("confetti", ConfettiWorld); this.setWorld("confetti");
this.start(); } _createClass(Universe, [ { key: "start", value: function start() { this.time.raf(this.tick.bind(this)); }, }, { key: "tick", value: function tick(time) { this.time.update(time);
if (this.time.hasFrames()) { this.update(); this.time.processFrame(); }
this.render(); this.time.raf(this.tick.bind(this)); }, }, { key: "update", value: function update() { this.world.update(this.time.step); }, }, { key: "render", value: function render() { var gradient = this.ctx.createLinearGradient( 0, 0, this.width, this.height ); this.ctx.clearRect(0, 0, this.width, this.height); this.world.render(this.ctx); },
// Helpers 库 }, { key: "updateSize", value: function updateSize() { this.width = window.innerWidth; this.height = window.innerHeight; this.el.width = this.width * this.pixelRatio; this.el.height = this.height * this.pixelRatio; this.el.style.width = window.innerWidth + "px"; this.el.style.height = window.innerHeight + "px"; this.ctx.scale(this.pixelRatio, this.pixelRatio); }, }, { key: "addWorld", value: function addWorld(worldName, World) { this.worlds[worldName] = new World(); this.worlds[worldName].universe = this; this.worlds[worldName].init(); }, }, { key: "setWorld", value: function setWorld(worldName) { this.world = this.worlds[worldName]; }, }, ]); return Universe;})();
// Mainconsole.clear();var element = document.querySelector("#canvasEvent");window.Canvas = new Universe(element);
</script>

复制代码

喜欢就给我点一个大大的赞是👍 外加一个关注

发布于: 2022 年 08 月 05 日阅读数: 49
用户头像

Five

关注

有事多研究,没事瞎琢磨 2022.08.02 加入

CSDN 前端领域优质创作者 , 博客专家认证。 退役ACMer, IT技术狂热爱好者 擅长领域,web前端,算法, 业务架构,可视化,富文本编辑器等。 github: https://github.com/Five-great

评论

发布
暂无评论
酷炫一款动态背景+鼠标点击效果(HTML +js canvas)_Hexo_Five_InfoQ写作社区