canvas实现蜘蛛网动态背景特效

本文分享了一款基于Canvas的连线背景特效重构过程,通过代码优化增强了交互体验,实现了更流畅的动画效果。作者详细介绍了如何调整小方块的位置、速度及与鼠标互动的机制,同时提供了完整的HTML和JS代码,方便读者学习和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上效果再说废话(滑稽)

https://jc1144096387.github.io/canvas_nest/

第一次看到这个特效时顿时惊为天人,默默地玩了几分钟= =,可惜那个网站只有压缩后的代码,搜连线背景特效只能搜到类似的,交互效果并不好,于是我便花了n个小时进行了代码重构,并添加了注释。就在刚刚,在我工作即将完成的时候,我在一篇蜘蛛网特效的文章中看到了代码= =。。。。不过似乎注释不是很多,效果也略有不同。所以看一下我的代码也是不错的选择= =。。。

html文件,用来测试

<!doctype html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="Generator" content="EditPlus®">

<meta name="Author" content="">

<meta name="Keywords" content="">

<meta name="Description" content="">

<title>canvas场景连线特效</title>

<style type="text/css">

*{

margin: 0px;

padding: 0px;

}

body{

background-color: #f4f4f4;

}

</style>

</head>

<body>

<!-- <canvas id="c_n9" width="1366" height="403" style="position: fixed; top: 0px; left: 0px; z-index: -1; opacity: 0.5;"></canvas> -->

<script type="text/javascript" src="test-clear.js" opacity= 0.6></script>

</body>

</html>

 

 

js文件

//立即执行函数

//!的作用是告诉javascript引擎这是一个函数表达式,不是函数声明,()、!、+、-等运算符都能实现这个作用,不过()是最安全的

//在!function(){}后面加上()会立即调用这个函数

//这样做可以模仿一个私有作用域,这样html文件引用多个js文件时便不会造成变量冲突

! function () {

 

//canvas元素相关

//创建canvas元素,并设置canvas元素的id

var canvas = document.createElement("canvas"),

context = canvas.getContext("2d"),

attr = getAttr();

 

//设置创建的canvas的相关属性

canvas.id = "c_n" + attr.length;

canvas.style.cssText = "position:fixed;top:0;left:0;z-index:" + attr.z + ";opacity:" + attr.opacity;

//将canvas元素添加到body元素中

document.getElementsByTagName("body")[0].appendChild(canvas);

//该函数设置了canvas元素的width属性和height属性

getWindowWH();

//onresize 事件会在窗口或框架被调整大小时发生

//此处即为当窗口大小改变时,重新获取窗口的宽高和设置canvas元素的宽高

window.onresize = getWindowWH;

 

//该函数会得到引用了本文件的script元素,

//因为本文件中在赋值时执行了一次getScript函数,html文件引用本文件时,本文件之后的script标签还没有被浏览器解释,

//所以得到的script数组中,引用了本文的script元素在该数组的末尾

//该函数的用意为使开发者能直接修改在html中引入该文件的script元素的属性来修改画布的一些属性,画布的z-index,透明度和小方块数量,颜色

//与前面往body元素添加canvas元素的代码配合,当开发者想要使用该特效作为背景时,只需在html文件中添加script元素并引用本文件即可

function getAttr() {

let scripts = document.getElementsByTagName("script"),

len = scripts.length,

script = scripts[len - 1];//v为最后一个script元素,即引用了本文件的script元素

return {

length: len,

z: script.getAttribute("zIndex") || -1,

opacity: script.getAttribute("opacity") || 0.5,

color: script.getAttribute("color") || "0,0,0",

count: script.getAttribute("count") || 99

}

}

//获得窗口宽高,并设置canvas元素宽高

function getWindowWH() {

W = canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,

H = canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

}





 

//生成随机位置的小方块

var random = Math.random,

squares = [];//存放小方块

 

//往squares[]数组放小方块

for(let p = 0; p < attr.count; p ++){

var square_x = random() * W,//横坐标

square_y = random() * H,//纵坐标

square_xa = 2 * random() - 1,//x轴位移 -1,1

square_ya = 2 * random() - 1;//y轴位移

squares.push({

x: square_x,

y: square_y,

xa: square_xa,

ya: square_ya,

max: 6000

})

}

 

//生成鼠标小方块

var mouse = {

x: null,

y: null,

max: 20000

};

//获取鼠标所在坐标

window.onmousemove = function (i) {

//i为W3C DOM,window.event 为 IE DOM,以实现兼容IE

//不过目前似乎IE已经支持W3C DOM,我用的是IE11,我注释掉下一句代码也能实现鼠标交互效果,

//网上说7/8/9是不支持的,本人没有试验,

//当然加上是没有错的

i = i || window.event;

mouse.x = i.clientX;

mouse.y = i.clientY;

}

//鼠标移出窗口后,消除鼠标小方块

window.onmouseout = function () {

mouse.x = null;

mouse.y = null;

}


 

//绘制小方块,小方块移动(碰到边界反向移动),小方块受鼠标束缚

var animation = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (i) {

window.setTimeout(i, 1000 / 45)

};//各个浏览器支持的requestAnimationFrame有所不同,兼容各个浏览器

 

function draw() {

//清除画布

context.clearRect(0, 0, W, H);

 

var w = [mouse].concat(squares);//连接(合并)鼠标小方块数组和其他小方块数组

var x, v, A, B, z, y;


 

//square属性表:x,y,xa,ya,max

squares.forEach(function (i) {

 

//实现小方块定向移动

i.x += i.xa;

i.y += i.ya;

 

// 控制小方块移动方向

// 当小方块达到窗口边界时,反向移动

i.xa = i.xa * (i.x > W || i.x < 0 ? -1 : 1);

i.ya = i.ya * (i.y > H || i.y < 0 ? -1 : 1);

 

//fillRect前两个参数为矩形左上角的x,y坐标,后两个分别为宽度和高度

//绘制小方块

context.fillRect(i.x - 0.5, i.y - 0.5, 1, 1);

 

//遍历w中所有元素

for (let n = 0; n < w.length; n++) {

x = w[n];

//如果x与i不是同一个对象实例且x的xy坐标存在

if (i !== x && null !== x.x && null !== x.y) {

x_diff = i.x - x.x;//i和x的x坐标差

y_diff = i.y - x.y;//i和x的y坐标差

distance = x_diff * x_diff + y_diff * y_diff;//斜边平方

if(distance < x.max){

//使i小方块受鼠标小方块束缚,即如果i小方块与鼠标小方块距离过大,i小方块会被鼠标小方块束缚,

//造成 多个小方块以鼠标为圆心,mouse.max/2为半径绕成一圈

if(x === mouse && distance > x.max/2){

i.x = i.x - 0.03 * x_diff;

i.y = i.y - 0.03 * y_diff;

}

A = (x.max - distance) / x.max;

context.beginPath();

//设置画笔的画线的粗细与两个小方块的距离相关,范围0-0.5,两个小方块距离越远画线越细,达到max时画线消失

context.lineWidth = A / 2;

//设置画笔的画线颜色为s.c即画布颜色,透明度为(A+0.2)即两个小方块距离越远画线越淡

context.strokeStyle = "rgba(" + attr.color + "," + (A + 0.2) + ")";

//设置画笔的笔触为i小方块

context.moveTo(i.x, i.y);

//使画笔的笔触移动到x小方块

context.lineTo(x.x, x.y);

//完成画线的绘制,即绘制连接小方块的线

context.stroke();

}

}

}

//把i小方块从w数组中去掉

//防止两个小方块重复连线

w.splice(w.indexOf(i), 1);

});

//window.requestAnimationFrame与setTimeout相似,形成递归调用,

//不过window.requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,提供了更好地优化,使动画更流畅

//经过浏览器优化,动画更流畅;

//窗口没激活时,动画将停止,省计算资源;

animation(draw);

}

 

//此处是等待0.1秒后,执行一次draw(),真正的动画效果是用window.requestAnimationFrame实现的

setTimeout(function () {

draw();

}, 100)

}();

 

如有谬误或纰漏,请大佬指正

欢迎道友一起探讨相关知识

最后贴上源码

https://github.com/jc1144096387/canvas_nest

test是改动草稿

test-clear是整理后的文件

min是压缩文件 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值