圣诞
分析
定义了一个名为myLabels
的数组,其中包含了三个字符串元素,分别是“Merry Christmas”, “健健康康,平安喜乐”, “一定要站在你所热爱的世界里闪闪发光”。
代码
let myLabels = [
"Merry Christmas",
"健健康康,平安喜乐",
"一定要站在你所热爱的世界里闪闪发光",
];
分析
创建了一个 然后获取了页面的高度和宽度,用于确定雪花的起始和结束位置。 接下来,定义了生成一片雪花的毫秒数,以及一个定时器,定期生成一片雪花。 在每个定时器回调函数中,随机生成雪花的起始和结束位置、大小、持续时间、透明度等参数。 然后,克隆出一个雪花,并根据上述参数设置其样式,并插入到页面中。 接下来设置了一个一次性定时器,用于在雪花生成后一段时间后,修改雪花的样式,使其具有下落效果。 最后,在雪花落下后一段时间,再次设置一个定时器,将雪花从页面中删除。 代码 调用函数 分析 使用MorphSVGPlugin插件来将指定的多边形转换为路径。 首先,调用 然后,定义了两个命名空间常量, 接下来,定义了两个辅助函数 然后,通过 接下来,定义了一些变量, 然后,定义了一个粒子池数组 代码 分析 使用GSAP动画库(GreenSock Animation Platform)来操作SVG元素的动画效果。 首先,通过 接下来,使用 然后定义了一个函数 接着使用 最后,创建了一个 代码 分析 定义一个名为 该函数接受一个参数 首先,通过 然后,使用 初始状态下,设置透明度为1,即完全可见。 然后,设置动画的持续时间为0.07秒,并将透明度设置为一个随机值,范围在0到1之间。 最后,设置动画重复播放,使得闪烁效果无限循环。 代码 分析 定义了一个名为 首先,注释掉了变量 接着,定义了变量 然后,使用 接下来,设置粒子的填充颜色,通过 然后,为粒子设置 最后,使用 代码 分析 定义一个名为 接下来,定义了一个名为 然后,通过 接下来,使用 然后,创建一个时间轴对象 在动画过程中,设置了动画的持续时间为0.61到6秒之间的随机数。 使用 同时,设置了粒子的缩放比例和旋转角度为随机的范围值。 设置了动画的缓动函数为 在动画开始时调用了 在动画重复时,通过 代码 分析 定义一个名为 接下来,使用 接着,使用 然后,使用 最后,使用 代码 分析 定义了一个名为 接下来,使用 然后,使用 接着,使用 最后,使用 代码 分析 定义一个名为 然后,定义了一些变量,包括色调色彩 接下来,创建了一个用于绘制星星的源图像 接着,定义了一个 定义了一个 创建了一个 然后,使用循环创建了指定数量的星星对象。 最后,定义了一个 代码 分析 执行了 代码 大部分都是js代码,其实还有一些html和css需要自己研究一下,需要源码私信,祝大家平安夜圣诞夜快乐
function snow() {
// 1、定义一片雪花模板
var flake = document.createElement("div");
// 雪花字符 ❄❉❅❆✻✼❇❈❊✥✺
flake.innerHTML = "❆";
flake.style.cssText = "position:absolute;color:#fff;";
//获取页面的高度 相当于雪花下落结束时Y轴的位置
var documentHieght = window.innerHeight;
//获取页面的宽度,利用这个数来算出,雪花开始时left的值
var documentWidth = window.innerWidth;
//定义生成一片雪花的毫秒数
var millisec = 100;
//2、设置第一个定时器,周期性定时器,每隔一段时间(millisec)生成一片雪花;
setInterval(function () {
//页面加载之后,定时器就开始工作
//随机生成雪花下落 开始 时left的值,相当于开始时X轴的位置
var startLeft = Math.random() * documentWidth;
//随机生成雪花下落 结束 时left的值,相当于结束时X轴的位置
var endLeft = Math.random() * documentWidth;
//随机生成雪花大小
var flakeSize = 5 + 20 * Math.random();
//随机生成雪花下落持续时间
var durationTime = 4000 + 7000 * Math.random();
//随机生成雪花下落 开始 时的透明度
var startOpacity = 0.7 + 0.3 * Math.random();
//随机生成雪花下落 结束 时的透明度
var endOpacity = 0.2 + 0.2 * Math.random();
//克隆一个雪花模板
var cloneFlake = flake.cloneNode(true);
//第一次修改样式,定义克隆出来的雪花的样式
cloneFlake.style.cssText += `
left: ${startLeft}px;
opacity: ${startOpacity};
font-size:${flakeSize}px;
top:-25px;
transition:${durationTime}ms;
`;
//拼接到页面中
document.body.appendChild(cloneFlake);
//设置第二个定时器,一次性定时器,
//当第一个定时器生成雪花,并在页面上渲染出来后,修改雪花的样式,让雪花动起来;
setTimeout(function () {
//第二次修改样式
cloneFlake.style.cssText += `
left: ${endLeft}px;
top:${documentHieght}px;
opacity:${endOpacity};
`;
//4、设置第三个定时器,当雪花落下后,删除雪花。
setTimeout(function () {
cloneFlake.remove();
}, durationTime);
}, 0);
}, millisec);
}
snow();
2.3、设置背景粒子
MorphSVGPlugin.convertToPath("polygon")
方法,将ID为“polygon”的多边形元素转换为路径元素。xmlns
和xlinkns
,分别用于设置XML命名空间和Xlink命名空间。select
和selectAll
,用于选择一个或多个元素。select
函数选择了一些DOM元素,例如.pContainer
、.mainSVG
、#star
、.sparkle
、#tree
等。showParticle
为true
表示显示粒子,particleColorArray
是一个颜色数组,particleTypeArray
是一个粒子类型数组,用于指定粒子的形状。particlePool
、一个粒子计数器particleCount
以及一个粒子数量numParticles
。
MorphSVGPlugin.convertToPath("polygon");
var xmlns = "http://www.w3.org/2000/svg",
xlinkns = "http://www.w3.org/1999/xlink",
select = function (s) {
return document.querySelector(s);
},
selectAll = function (s) {
return document.querySelectorAll(s);
},
pContainer = select(".pContainer"),
mainSVG = select(".mainSVG"),
star = select("#star"),
sparkle = select(".sparkle"),
tree = select("#tree"),
showParticle = true,
particleColorArray = [
"#E8F6F8",
"#ACE8F8",
"#F6FBFE",
"#A2CBDC",
"#B74551",
"#5DBA72",
"#910B28",
"#910B28",
"#446D39",
],
particleTypeArray = ["#star", "#circ", "#cross", "#heart"],
// particleTypeArray = ['#star'],
particlePool = [],
particleCount = 0,
numParticles = 201;
2.4、操作动画效果
gsap.set
设置了SVG的可见性为“visible”,表示将SVG元素设置为可见状态。gsap.set
设置了sparkle
元素的transformOrigin
为"50% 50%",并将其y坐标设置为-100,这将影响后续的动画效果。getSVGPoints
,用于获取SVG路径中的点坐标。该函数接受一个路径元素作为参数,通过MotionPathPlugin.getRawPath
方法获取路径的原始数据,并将其转换为点坐标的数组。getSVGPoints
函数分别获取了.treePath
和.treeBottomPath
的点坐标,并存储在treePath
和treeBottomPath
变量中。mainTl
的GSAP时间轴和一个starTl
的动画时间轴,用于控制整体的动画效果。
// gsap动画库
gsap.set("svg", {
visibility: "visible",
});
gsap.set(sparkle, {
transformOrigin: "50% 50%",
y: -100,
});
let getSVGPoints = (path) => {
let arr = [];
var rawPath = MotionPathPlugin.getRawPath(path)[0];
rawPath.forEach((el, value) => {
let obj = {};
obj.x = rawPath[value * 2];
obj.y = rawPath[value * 2 + 1];
if (value % 2) {
arr.push(obj);
}
//console.log(value)
});
return arr;
};
let treePath = getSVGPoints(".treePath");
var treeBottomPath = getSVGPoints(".treeBottomPath");
//console.log(starPath.length)
var mainTl = gsap.timeline({ delay: 0, repeat: 0 }),
starTl;
2.5、定义闪烁效果
flicker
的函数,用于实现一个闪烁效果。p
,表示要应用闪烁效果的对象。gsap.killTweensOf
方法停止对象p
的所有关于透明度的动画效果。gsap.fromTo
方法设置对象p
的透明度动画效果。
function flicker(p) {
//console.log("flivker")
gsap.killTweensOf(p, { opacity: true });
gsap.fromTo(
p,
{
opacity: 1,
},
{
duration: 0.07,
opacity: Math.random(),
repeat: -1,
}
);
}
2.6、定义粒子对象
createParticles
的函数,用于创建和初始化粒子(particles)。step
的初始化代码和打印starPath.length
的语句。i
,初始值为numParticles
。变量p
表示粒子的元素,particleTl
是粒子的动画时间轴,step
用于确定粒子在treePath
路径中的位置,pos
用于存储具体的粒子位置。while
循环逐个创建粒子对象。在每次循环中,通过select
方法选择一个粒子的类型,使用cloneNode(true)
方法对其进行克隆,并将克隆的粒子对象添加到mainSVG
中。particleColorArray
数组来循环设置粒子的颜色属性。class
属性为particle
,并将其添加到particlePool
数组中,以便后续使用。gsap.set
方法将粒子对象的初始位置设置为(-100, -100),并设置transformOrigin
为"50% 50%"。
function createParticles() {
//var step = numParticles/starPath.length;
//console.log(starPath.length)
var i = numParticles,
p,
particleTl,
step = numParticles / treePath.length,
pos;
while (--i > -1) {
p = select(particleTypeArray[i % particleTypeArray.length]).cloneNode(
true
);
mainSVG.appendChild(p);
p.setAttribute(
"fill",
particleColorArray[i % particleColorArray.length]
);
p.setAttribute("class", "particle");
particlePool.push(p);
//hide them initially
gsap.set(p, {
x: -100,
y: -100,
transformOrigin: "50% 50%",
});
}
}
2.7、粒子对象播放
getScale
的函数,用于生成一个随机的缩放比例。该函数使用了gsap.utils.random
方法,传入了最小值0.5、最大值3、步长0.001和布尔值参数true。这意味着生成的随机数将在0.5到3之间,并以0.001为步长。playParticle
的函数,用于播放粒子动画。在函数内部,首先判断是否允许显示粒子,如果不允许,则直接返回。particlePool
数组获取当前要播放的粒子对象。gsap.set
方法设置粒子的初始位置为.pContainer
元素的x和y属性的值,并设置缩放比例为通过getScale
函数生成的随机数。tl
,并使用tl.to
方法对粒子对象进行动画操作。physics2D
属性实现了一个物理引擎效果,具体的速度、角度和重力值通过gsap.utils.random
方法生成。power1
。flicker
函数,并传入了粒子对象作为参数。onRepeat
方法设置了粒子的缩放比例为通过getScale
函数生成的随机数。
var getScale = gsap.utils.random(0.5, 3, 0.001, true); // 圣诞树开始绘画时小光点动画的特效(参数:最小值,最大值,延迟)
function playParticle(p) {
if (!showParticle) {
return;
}
var p = particlePool[particleCount];
gsap.set(p, {
x: gsap.getProperty(".pContainer", "x"),
y: gsap.getProperty(".pContainer", "y"),
scale: getScale(),
});
var tl = gsap.timeline();
tl.to(p, {
duration: gsap.utils.random(0.61, 6),
physics2D: {
velocity: gsap.utils.random(-23, 23),
angle: gsap.utils.random(-180, 180),
gravity: gsap.utils.random(-6, 50),
},
scale: 0,
rotation: gsap.utils.random(-123, 360),
ease: "power1",
onStart: flicker,
onStartParams: [p],
//repeat:-1,
onRepeat: (p) => {
gsap.set(p, {
scale: getScale(),
});
},
onRepeatParams: [p],
});
//
//particlePool[particleCount].play();
particleCount++;
//mainTl.add(tl, i / 1.3)
particleCount = particleCount >= numParticles ? 0 : particleCount;
}
2.8、绘制星星
drawStar
的函数,用于绘制星星动画。在函数内部,首先创建了一个时间轴对象starTl
,并设置了更新回调函数为playParticle
。to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画过程中,设置了动画的持续时间为6秒,并使用motionPath
属性指定了动画的路径为.treePath
元素,并禁用了自动旋转效果。设置了动画的缓动函数为linear
。to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画开始时,通过onStart
函数将showParticle
变量设置为false
,表示不显示粒子。设置了动画的持续时间为1秒,并将元素的x和y属性设置为treeBottomPath[0].x
和treeBottomPath[0].y
。to
方法对.pContainer
和.sparkle
元素进行动画操作。在动画开始时,通过onStart
函数将showParticle
变量设置为true
,表示显示粒子。设置了动画的持续时间为2秒,并使用motionPath
属性指定了动画的路径为.treeBottomPath
元素,并禁用了自动旋转效果。设置了动画的缓动函数为linear
。from
方法对.treeBottomMask
元素进行动画操作。设置了动画的持续时间为2秒,并使用drawSVG
属性指定了路径的起始结束百分比为0% 0%
,即不显示路径,同时设置了画笔的颜色为#FFF
,表示白色。设置了动画的缓动函数为linear
。
function drawStar() {
starTl = gsap.timeline({ onUpdate: playParticle });
starTl
.to(".pContainer, .sparkle", {
duration: 6,
motionPath: {
path: ".treePath",
autoRotate: false,
},
ease: "linear",
})
.to(".pContainer, .sparkle", {
duration: 1,
onStart: function () {
showParticle = false;
},
x: treeBottomPath[0].x,
y: treeBottomPath[0].y,
})
.to(
".pContainer, .sparkle",
{
duration: 2,
onStart: function () {
showParticle = true;
},
motionPath: {
path: ".treeBottomPath",
autoRotate: false,
},
ease: "linear",
},
"-=0"
)
// 圣诞树中间那条横线动画 .treeBottomMask 是绑定class='treeBottomMask'这个标签
.from(
".treeBottomMask",
{
duration: 2,
drawSVG: "0% 0%",
stroke: "#FFF",
ease: "linear",
},
"-=2"
);
//gsap.staggerTo(particlePool, 2, {})
}
2.9、绘制圣诞树
drawMain
的函数,用于绘制主要的圣诞树动画。在函数内部,首先创建了一个时间轴对象mainTl
。from
方法对.treePathMask
和.treePotMask
元素进行动画操作。设置了动画的持续时间为6秒,并使用drawSVG
属性指定了路径的起始结束百分比为0% 0%
,即不显示路径,同时设置了画笔的颜色为#FFF
表示白色。设置了动画的缓动函数为linear
。from
方法对.treeStar
元素进行动画操作。设置了动画的持续时间为3秒,并设置了元素的scaleY
属性为0、scaleX
属性为0.15,表示缩放比例,使用transformOrigin
属性指定了缩放的基点在元素的中心。设置了动画的缓动函数为elastic(1,0.5)
。to
方法对.sparkle
元素进行动画操作。设置了动画的持续时间为3秒,并将元素的透明度设置为0,使用了rough
缓动函数,该缓动函数会在动画期间以随机方式改变元素的透明度值。该动画将在前一个动画的结束点之后开始。to
方法对.treeStarOutline
元素进行动画操作。设置了动画的持续时间为1秒,并将元素的透明度设置为0.3,使用了rough
缓动函数,该缓动函数会在动画期间以随机方式改变元素的透明度值。该动画将在前一个动画的结束点之后开始。
function drawMain() {
mainTl
// 圣诞树上半身轮廓动画
.from([".treePathMask", ".treePotMask"], {
duration: 6,
drawSVG: "0% 0%",
stroke: "#FFF",
stagger: {
each: 6,
},
duration: gsap.utils.wrap([6, 1, 2]),
ease: "linear",
})
// 圣诞树头上的星星动画
.from(
".treeStar",
{
duration: 3,
//skewY:270,
scaleY: 0,
scaleX: 0.15,
transformOrigin: "50% 50%",
ease: "elastic(1,0.5)",
},
"-=4"
)
// 当绘画圣诞树的小光点绘制完时,让小光点消失
.to(
".sparkle",
{
duration: 3,
opacity: 0,
ease: "rough({strength: 2, points: 100, template: linear, taper: both, randomize: true, clamp: false})",
},
"-=0"
)
// 给圣诞树头上的星星加个白色特效
.to(
".treeStarOutline",
{
duration: 1,
opacity: 0.3,
ease: "rough({strength: 2, points: 16, template: linear, taper: none, randomize: true, clamp: false})",
},
"+=1"
);
/* .to('.whole', {
opacity: 0
}, '+=2') */
}
2.10、绘制星星背景动画
drawStars
的函数,用于绘制星星背景动画。在函数内部,首先获取了stars
元素,然后创建了一个canvas
元素并将其上下文赋给ctx
变量。接着,设置了canvas
的宽度和高度为窗口的宽度和高度,并分别赋给w
和h
变量。hue
、保存星星对象的数组stars
、计数器count
和最大星星数量maxStars
。canvas2
,并获取其上下文赋给ctx2
变量。设置了canvas2
的宽度和高度为100,并创建了径向渐变gradient2
,以半径为0的圆开始,到半径为half
的圆结束。根据色调色彩hue
的不同,设置了不同的颜色。然后,使用路径arc
创建了一个圆,并使用fill
方法填充了渐变。random
函数,用于生成指定范围内的随机数。maxOrbit
函数,用于根据屏幕宽高计算星星的移动范围。Star
构造函数,用于实例化星星对象。在构造函数中,设置了星星的移动半径、大小、圆心位置、初始角度、移动速度和透明度等属性,并将新创建的星星对象存入stars
数组。Star
对象定义了一个draw
方法,用于绘制星星。在该方法中,根据星星的移动半径和角度计算出星星在屏幕上的位置。根据随机数判断星星是否变亮或变暗,并根据透明度绘制星星。最后,更新星星的角度。animation
函数,用于执行星星的动画效果。在该函数中,首先绘制了一个半透明的背景颜色,然后使用for
循环调用每个星星对象的draw
方法进行绘制。最后,通过window.requestAnimationFrame
方法不断循环调用animation
函数,实现动画效果。
function drawStars() {
let canvas = document.getElementById("stars"),
ctx = canvas.getContext("2d"),
w = (canvas.width = window.innerWidth),
h = (canvas.height = window.innerHeight),
hue = 37, //色调色彩
stars = [], //保存所有星星
count = 0, //用于计算星星
maxStars = 1300; //星星数量
//canvas2是用来创建星星的源图像,即母版,
//根据星星自身属性的大小来设置
var canvas2 = document.createElement("canvas"),
ctx2 = canvas2.getContext("2d");
canvas2.width = 100;
canvas2.height = 100;
//创建径向渐变,从坐标(half,half)半径为0的圆开始,
//到坐标为(half,half)半径为half的圆结束
var half = canvas2.width / 2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, "#CCC");
//hsl是另一种颜色的表示方式,
//h->hue,代表色调色彩,0为red,120为green,240为blue
//s->saturation,代表饱和度,0%-100%
//l->lightness,代表亮度,0%为black,100%位white
gradient2.addColorStop(0.1, "hsl(" + hue + ", 61%, 10%)");
gradient2.addColorStop(0.25, "hsl(" + hue + ", 64%, 2%)");
gradient2.addColorStop(1, "transparent");
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
// End cache
function random(min, max) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
//返回min和max之间的一个随机值
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function maxOrbit(x, y) {
var max = Math.max(x, y),
diameter = Math.round(Math.sqrt(max * max + max * max));
//星星移动范围,值越大范围越小,
return diameter / 2;
}
var Star = function () {
//星星移动的半径
this.orbitRadius = random(maxOrbit(w, h));
//星星大小,半径越小,星星也越小,即外面的星星会比较大
this.radius = random(60, this.orbitRadius) / 8;
//所有星星都是以屏幕的中心为圆心
this.orbitX = w / 2;
this.orbitY = h / 2;
//星星在旋转圆圈位置的角度,每次增加speed值的角度
//利用正弦余弦算出真正的x、y位置
this.timePassed = random(0, maxStars);
//星星移动速度
this.speed = random(this.orbitRadius) / 50000;
//星星图像的透明度
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
};
Star.prototype.draw = function () {
//星星围绕在以屏幕中心为圆心,半径为orbitRadius的圆旋转
var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
twinkle = random(10);
//星星每次移动会有1/10的几率变亮或者变暗
if (twinkle === 1 && this.alpha > 0) {
//透明度降低,变暗
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
//透明度升高,变亮
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
//使用canvas2作为源图像来创建星星,
//位置在x - this.radius / 2, y - this.radius / 2
//大小为 this.radius
ctx.drawImage(
canvas2,
x - this.radius / 2,
y - this.radius / 2,
this.radius,
this.radius
);
//没旋转一次,角度就会增加
this.timePassed += this.speed;
};
//初始化所有星星
for (var i = 0; i < maxStars; i++) {
new Star();
}
function animation() {
//以新图像覆盖已有图像的方式进行绘制背景颜色
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 0.9; //尾巴
ctx.fillStyle = "hsla(" + hue + ", 64%, 6%, 2)";
ctx.fillRect(0, 0, w, h);
//源图像和目标图像同时显示,重叠部分叠加颜色效果
ctx.globalCompositeOperation = "lighter";
for (var i = 1, l = stars.length; i < l; i++) {
stars[i].draw();
}
//调用该方法执行动画,并且在重绘的时候调用指定的函数来更新动画
//回调的次数通常是每秒60次
window.requestAnimationFrame(animation);
}
animation();
}
2.11、定义初始化函数并调用
init
函数,接着依次执行了createParticles
、drawStar
、drawMain
和drawStars
等函数,并将它们添加到了mainTl
时间轴中。最后,通过gsap.globalTimeline.timeScale(1.5)
方法设置了全局时间轴的绘画速率。
function init() {
let element = document.getElementById("header");
for(let i = 0; i < myLabels.length; i++) {
let _p = document.createElement("p");
_p.className = "header-item";
_p.innerHTML = myLabels[i];
element.appendChild(_p);
}
let labels = document.getElementsByClassName('header-item');
for(let i = 0; i < myLabels.length; i++) {
setTimeout(() => {
labels[i].classList.add("show");
}, 1000 * i);
}
}
init();
createParticles()
drawStar();
drawMain();
mainTl.add(starTl, 0);
gsap.globalTimeline.timeScale(1.5); // 圣诞树开始绘画时小光点动画的绘画速率,越大越快
drawStars();
3、结尾