577 lines
19 KiB
JavaScript
577 lines
19 KiB
JavaScript
$(function () {
|
||
// 初始化界面
|
||
function init() {
|
||
placeholderPic()
|
||
sd1('.sd1')
|
||
sd1('.sd2')
|
||
sd2('.sd3')
|
||
sd2('.sd4')
|
||
jz()
|
||
animate()
|
||
}
|
||
init()
|
||
|
||
// 自定义字体大小
|
||
function placeholderPic() {
|
||
w = document.documentElement.clientWidth / 80;
|
||
document.documentElement.style.fontSize = w + 'px';
|
||
}
|
||
|
||
// 闪电一,二
|
||
function sd1(ele) {
|
||
var width, height
|
||
var step = 0;
|
||
var canvas = document.createElement('canvas')
|
||
var ctx = canvas.getContext('2d')
|
||
|
||
var bg = [4, 10, 11]
|
||
document.querySelector(ele).appendChild(canvas)
|
||
setTimeout(() => {
|
||
var timeID = setInterval(() => {
|
||
pt1.x += 10;
|
||
if (pt1.x > width - 10) {
|
||
clearInterval(timeID)
|
||
}
|
||
}, 60);
|
||
}, 1000)
|
||
|
||
var pt1
|
||
var pt2
|
||
|
||
window.addEventListener('resize', setup)
|
||
|
||
setup()
|
||
|
||
function setup() {
|
||
canvas.width = width = document.querySelector(ele).clientWidth
|
||
canvas.height = height = document.querySelector(ele).clientHeight
|
||
|
||
ctx.beginPath();
|
||
ctx.rect(0, 0, width, height)
|
||
ctx.fillStyle = `rgba(${bg[0]}, ${bg[1]}, ${bg[2]}, ${1})`
|
||
ctx.fill()
|
||
|
||
pt1 = { x: -20, y: height / 2 }//闪电起点
|
||
pt2 = { x: -20, y: height / 2 } //闪电终点
|
||
// draw()
|
||
}
|
||
|
||
setInterval(animate, 60)
|
||
// window.requestAnimationFrame(animate);
|
||
|
||
function blur(ctx, canvas, amt) {
|
||
ctx.filter = `blur(${amt}px)`
|
||
ctx.drawImage(canvas, 0, 0)
|
||
ctx.filter = 'none'
|
||
}
|
||
|
||
function fade(ctx, amt, width, height) {
|
||
ctx.beginPath();
|
||
ctx.rect(0, 0, width, height)
|
||
ctx.fillStyle = `rgba(${bg[0]}, ${bg[1]}, ${bg[2]}, ${amt})`
|
||
ctx.fill()
|
||
}
|
||
|
||
function animate() {
|
||
step++
|
||
|
||
blur(ctx, canvas, 1)
|
||
draw()
|
||
fade(ctx, 0.1, width, height)
|
||
|
||
// window.requestAnimationFrame(function(){animate()})
|
||
}
|
||
|
||
function draw() {
|
||
|
||
var iterations = [pt1, pt2]
|
||
var newiterations, i, j
|
||
for (i = 0; i < 8; i++) {
|
||
newiterations = [iterations[0]]
|
||
for (j = 1; j < iterations.length; j++) {
|
||
newiterations.push(getRandMidpoint(iterations[j - 1], iterations[j], 200 / (i * i + 1)))
|
||
newiterations.push(iterations[j])
|
||
}
|
||
iterations = newiterations.concat([])
|
||
}
|
||
ctx.beginPath();
|
||
ctx.moveTo(iterations[0].x, iterations[0].y);
|
||
ctx.lineWidth = 2;
|
||
ctx.strokeStyle = '#04e4c9';
|
||
// ctx.strokeStyle = `hsla(${Math.sin( step / 30) * 120 + 50},${90}%,${70}%,1)`
|
||
for (i = 1; i < iterations.length; i++) {
|
||
ctx.lineTo(iterations[i].x, iterations[i].y);
|
||
}
|
||
ctx.stroke()
|
||
ctx.closePath()
|
||
}
|
||
|
||
function getRandMidpoint(pa, pb, range) {
|
||
var a = Math.atan2(pb.y - pa.y, pb.x - pa.x) + Math.PI / 2
|
||
var half = { y: (pb.y - pa.y) / 2 + pa.y, x: (pb.x - pa.x) / 2 + pa.x }
|
||
var offset = Math.random() * range / 3 - range / 6 //这里控制闪电的抖动幅度
|
||
var ho = {
|
||
x: Math.cos(a) * offset + half.x,
|
||
y: Math.sin(a) * offset + half.y
|
||
}
|
||
return ho
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
//
|
||
//
|
||
|
||
// 闪电三,四
|
||
function sd2(ele) {
|
||
var width, height
|
||
var step = 0;
|
||
var canvas = document.createElement('canvas')
|
||
var ctx = canvas.getContext('2d')
|
||
|
||
var bg = [4, 10, 11]
|
||
document.querySelector(ele).appendChild(canvas)
|
||
setTimeout(() => {
|
||
var timeID = setInterval(() => {
|
||
pt1.x -= 10;
|
||
if (pt1.x < 10) {
|
||
clearInterval(timeID)
|
||
}
|
||
}, 60);
|
||
}, 1000)
|
||
|
||
var pt1
|
||
var pt2
|
||
|
||
window.addEventListener('resize', setup)
|
||
|
||
setup()
|
||
|
||
function setup() {
|
||
canvas.width = width = document.querySelector(ele).clientWidth
|
||
canvas.height = height = document.querySelector(ele).clientHeight
|
||
|
||
ctx.beginPath();
|
||
ctx.rect(0, 0, width, height)
|
||
ctx.fillStyle = `rgba(${bg[0]}, ${bg[1]}, ${bg[2]}, ${1})`
|
||
ctx.fill()
|
||
|
||
pt1 = { x: width + 20, y: height / 2 }//闪电起点
|
||
pt2 = { x: width + 20, y: height / 2 } //闪电终点
|
||
// draw()
|
||
}
|
||
|
||
setInterval(animate, 60)
|
||
// window.requestAnimationFrame(animate);
|
||
|
||
function blur(ctx, canvas, amt) {
|
||
ctx.filter = `blur(${amt}px)`
|
||
ctx.drawImage(canvas, 0, 0)
|
||
ctx.filter = 'none'
|
||
}
|
||
|
||
function fade(ctx, amt, width, height) {
|
||
ctx.beginPath();
|
||
ctx.rect(0, 0, width, height)
|
||
ctx.fillStyle = `rgba(${bg[0]}, ${bg[1]}, ${bg[2]}, ${amt})`
|
||
ctx.fill()
|
||
}
|
||
|
||
function animate() {
|
||
step++
|
||
|
||
blur(ctx, canvas, 1)
|
||
draw()
|
||
fade(ctx, 0.1, width, height)
|
||
|
||
// window.requestAnimationFrame(function(){animate()})
|
||
}
|
||
|
||
function draw() {
|
||
|
||
var iterations = [pt1, pt2]
|
||
var newiterations, i, j
|
||
for (i = 0; i < 8; i++) {
|
||
newiterations = [iterations[0]]
|
||
for (j = 1; j < iterations.length; j++) {
|
||
newiterations.push(getRandMidpoint(iterations[j - 1], iterations[j], 200 / (i * i + 1)))
|
||
newiterations.push(iterations[j])
|
||
}
|
||
iterations = newiterations.concat([])
|
||
}
|
||
ctx.beginPath();
|
||
ctx.moveTo(iterations[0].x, iterations[0].y);
|
||
ctx.lineWidth = 2;
|
||
ctx.strokeStyle = '#04e4c9';
|
||
// ctx.strokeStyle = `hsla(${Math.sin( step / 30) * 120 + 50},${90}%,${70}%,1)`
|
||
for (i = 1; i < iterations.length; i++) {
|
||
ctx.lineTo(iterations[i].x, iterations[i].y);
|
||
}
|
||
ctx.stroke()
|
||
ctx.closePath()
|
||
}
|
||
|
||
function getRandMidpoint(pa, pb, range) {
|
||
var a = Math.atan2(pb.y - pa.y, pb.x - pa.x) + Math.PI / 2
|
||
var half = { y: (pb.y - pa.y) / 2 + pa.y, x: (pb.x - pa.x) / 2 + pa.x }
|
||
var offset = Math.random() * range / 3 - range / 6 //这里控制闪电的抖动幅度
|
||
var ho = {
|
||
x: Math.cos(a) * offset + half.x,
|
||
y: Math.sin(a) * offset + half.y
|
||
}
|
||
return ho
|
||
}
|
||
}
|
||
|
||
// 加载动画
|
||
function jz() {
|
||
$('.jz1 ul li').each((index, item) => {
|
||
item.style.opacity = 1 - index / 10;
|
||
})
|
||
setInterval(() => {
|
||
$('.jz1 ul li').each((index, item) => {
|
||
if (item.style.opacity == 0) {
|
||
item.style.opacity = 1
|
||
}
|
||
item.style.opacity = parseFloat(item.style.opacity) - 0.1
|
||
})
|
||
}, 100)
|
||
$('.jz2 ul li').each((index, item) => {
|
||
item.style.opacity = 1 - index / 10;
|
||
})
|
||
setInterval(() => {
|
||
$('.jz2 ul li').each((index, item) => {
|
||
if (item.style.opacity == 0) {
|
||
item.style.opacity = 1
|
||
}
|
||
item.style.opacity = parseFloat(item.style.opacity) - 0.1
|
||
})
|
||
}, 100)
|
||
}
|
||
|
||
// 中间背景动画
|
||
function animate() {
|
||
var App = {};
|
||
App.setup = function () {
|
||
// 创建canvas元素,并加入body中
|
||
var canvas = document.createElement('canvas');
|
||
this.filename = "spipa";
|
||
// 控制canvas幕布的大小
|
||
canvas.width = document.querySelector('.animate').clientWidth;
|
||
canvas.height = document.querySelector('.animate').clientHeight;
|
||
this.canvas = canvas;
|
||
document.querySelector('.animate').appendChild(canvas);
|
||
this.ctx = this.canvas.getContext('2d');
|
||
this.width = this.canvas.width;
|
||
this.height = this.canvas.height;
|
||
this.dataToImageRatio = 1;
|
||
this.ctx.imageSmoothingEnabled = false;
|
||
this.ctx.webkitImageSmoothingEnabled = false;
|
||
this.ctx.msImageSmoothingEnabled = false;
|
||
this.xC = this.width / 2;
|
||
this.yC = this.height / 2;
|
||
|
||
this.stepCount = 0;
|
||
this.particles = [];
|
||
this.lifespan = 1000;
|
||
this.popPerBirth = 1;
|
||
this.maxPop = 200;
|
||
this.birthFreq = 5;
|
||
|
||
// Build grid
|
||
this.gridSize = 8;// 运动坐标
|
||
this.gridSteps = Math.floor(1000 / this.gridSize);
|
||
this.grid = [];
|
||
var i = 0;
|
||
for (var xx = -500; xx < 500; xx += this.gridSize) {
|
||
for (var yy = -500; yy < 500; yy += this.gridSize) {
|
||
// 径向场,r的三角函数,最大值在r0附近
|
||
var r = Math.abs(xx) + Math.abs(yy),//Math.sqrt(xx*xx+yy*yy),
|
||
r0 = 3*w, //中间方形的大小
|
||
field;
|
||
|
||
if (r < r0) field = 255 / r0 * r;
|
||
else if (r > r0) field = 255 - Math.min(255, (r - r0) / 2);
|
||
|
||
this.grid.push({
|
||
x: xx,
|
||
y: yy,
|
||
busyAge: 0,
|
||
spotIndex: i,
|
||
isEdge: (xx == -500 ? 'left' :
|
||
(xx == (-500 + this.gridSize * (this.gridSteps - 1)) ? 'right' :
|
||
(yy == -500 ? 'top' :
|
||
(yy == (-500 + this.gridSize * (this.gridSteps - 1)) ? 'bottom' :
|
||
false
|
||
)
|
||
)
|
||
)
|
||
),
|
||
field: field
|
||
});
|
||
i++;
|
||
}
|
||
}
|
||
this.gridMaxIndex = i;
|
||
|
||
|
||
|
||
this.initDraw();
|
||
};
|
||
App.evolve = function () {
|
||
var time1 = performance.now();
|
||
|
||
this.stepCount++;
|
||
|
||
// Increment all grid ages
|
||
this.grid.forEach(function (e) {
|
||
if (e.busyAge > 0) e.busyAge++;
|
||
});
|
||
|
||
if (this.stepCount % this.birthFreq == 0 && (this.particles.length + this.popPerBirth) < this.maxPop) {
|
||
this.birth();
|
||
}
|
||
App.move();
|
||
App.draw();
|
||
|
||
var time2 = performance.now();
|
||
|
||
|
||
|
||
};
|
||
App.birth = function () {
|
||
var x, y;
|
||
var gridSpotIndex = Math.floor(Math.random() * this.gridMaxIndex),
|
||
gridSpot = this.grid[gridSpotIndex],
|
||
x = gridSpot.x, y = gridSpot.y;
|
||
|
||
var particle = {
|
||
hue: -10,// + Math.floor(50*Math.random()),
|
||
sat: 95,//30 + Math.floor(70*Math.random()),
|
||
lum: 20 + Math.floor(40 * Math.random()),
|
||
x: x, y: y,
|
||
xLast: x, yLast: y,
|
||
xSpeed: 0, ySpeed: 0,
|
||
age: 0,
|
||
ageSinceStuck: 0,
|
||
attractor: {
|
||
oldIndex: gridSpotIndex,
|
||
gridSpotIndex: gridSpotIndex,// Pop at random position on grid
|
||
},
|
||
name: 'seed-' + Math.ceil(10000000 * Math.random())
|
||
};
|
||
this.particles.push(particle);
|
||
};
|
||
App.kill = function (particleName) {
|
||
var newArray = _.reject(this.particles, function (seed) {
|
||
return (seed.name == particleName);
|
||
});
|
||
this.particles = _.cloneDeep(newArray);
|
||
};
|
||
App.move = function () {
|
||
for (var i = 0; i < this.particles.length; i++) {
|
||
// Get particle
|
||
var p = this.particles[i];
|
||
|
||
// Save last position
|
||
p.xLast = p.x; p.yLast = p.y;
|
||
|
||
// Attractor and corresponding grid spot
|
||
var index = p.attractor.gridSpotIndex,
|
||
gridSpot = this.grid[index];
|
||
|
||
// Maybe move attractor and with certain constraints
|
||
if (Math.random() < 0.5) {
|
||
// Move attractor
|
||
if (!gridSpot.isEdge) {
|
||
// Change particle's attractor grid spot and local move function's grid spot
|
||
var topIndex = index - 1,
|
||
bottomIndex = index + 1,
|
||
leftIndex = index - this.gridSteps,
|
||
rightIndex = index + this.gridSteps,
|
||
topSpot = this.grid[topIndex],
|
||
bottomSpot = this.grid[bottomIndex],
|
||
leftSpot = this.grid[leftIndex],
|
||
rightSpot = this.grid[rightIndex];
|
||
|
||
// Choose neighbour with highest field value (with some desobedience...)
|
||
var chaos = 30;
|
||
var maxFieldSpot = _.maxBy([topSpot, bottomSpot, leftSpot, rightSpot], function (e) {
|
||
return e.field + chaos * Math.random()
|
||
});
|
||
|
||
var potentialNewGridSpot = maxFieldSpot;
|
||
if (potentialNewGridSpot.busyAge == 0 || potentialNewGridSpot.busyAge > 15) {// Allow wall fading
|
||
//if (potentialNewGridSpot.busyAge == 0) {// Spots busy forever
|
||
// Ok it's free let's go there
|
||
p.ageSinceStuck = 0;// Not stuck anymore yay
|
||
p.attractor.oldIndex = index;
|
||
p.attractor.gridSpotIndex = potentialNewGridSpot.spotIndex;
|
||
gridSpot = potentialNewGridSpot;
|
||
gridSpot.busyAge = 1;
|
||
} else p.ageSinceStuck++;
|
||
|
||
} else p.ageSinceStuck++;
|
||
|
||
if (p.ageSinceStuck == 10) this.kill(p.name);
|
||
}
|
||
|
||
// Spring attractor to center with viscosity
|
||
var k = 8, visc = 0.4;
|
||
var dx = p.x - gridSpot.x,
|
||
dy = p.y - gridSpot.y,
|
||
dist = Math.sqrt(dx * dx + dy * dy);
|
||
|
||
// Spring
|
||
var xAcc = -k * dx,
|
||
yAcc = -k * dy;
|
||
|
||
p.xSpeed += xAcc; p.ySpeed += yAcc;
|
||
|
||
// Calm the f*ck down
|
||
p.xSpeed *= visc; p.ySpeed *= visc;
|
||
|
||
// Store stuff in particle brain
|
||
p.speed = Math.sqrt(p.xSpeed * p.xSpeed + p.ySpeed * p.ySpeed);
|
||
p.dist = dist;
|
||
|
||
// Update position
|
||
p.x += 0.1 * p.xSpeed; p.y += 0.1 * p.ySpeed;
|
||
|
||
// Get older
|
||
p.age++;
|
||
|
||
// Kill if too old
|
||
if (p.age > this.lifespan) {
|
||
this.kill(p.name);
|
||
this.deathCount++;
|
||
}
|
||
}
|
||
};
|
||
App.initDraw = function () {
|
||
this.ctx.beginPath();
|
||
this.ctx.rect(0, 0, this.width, this.height);
|
||
this.ctx.fillStyle = 'transparent';
|
||
this.ctx.fill();
|
||
this.ctx.closePath();
|
||
};
|
||
|
||
App.draw = function () {
|
||
this.drawnInLastFrame = 0;
|
||
if (!this.particles.length) return false;
|
||
|
||
this.ctx.beginPath();
|
||
this.ctx.rect(0, 0, this.width, this.height);
|
||
// this.ctx.fillStyle = 'transparent';
|
||
this.ctx.fillStyle = 'rgba(12, 22, 25, 0.1)';
|
||
this.ctx.fill();
|
||
this.ctx.closePath();
|
||
for (var i = 0; i < this.particles.length; i++) {
|
||
// Draw particle
|
||
var p = this.particles[i];
|
||
|
||
var h, s, l, a;
|
||
|
||
h = p.hue + this.stepCount / 30;
|
||
s = p.sat;
|
||
l = p.lum;
|
||
a = 1;
|
||
|
||
var last = this.dataXYtoCanvasXY(p.xLast, p.yLast),
|
||
now = this.dataXYtoCanvasXY(p.x, p.y);
|
||
var attracSpot = this.grid[p.attractor.gridSpotIndex],
|
||
attracXY = this.dataXYtoCanvasXY(attracSpot.x, attracSpot.y);
|
||
var oldAttracSpot = this.grid[p.attractor.oldIndex],
|
||
oldAttracXY = this.dataXYtoCanvasXY(oldAttracSpot.x, oldAttracSpot.y);
|
||
|
||
this.ctx.beginPath();
|
||
|
||
this.ctx.strokeStyle = 'green';
|
||
this.ctx.fillStyle = 'hsla(' + h + ', ' + s + '%, ' + l + '%, ' + a + ')';
|
||
|
||
// Particle trail
|
||
this.ctx.moveTo(last.x, last.y);
|
||
this.ctx.lineTo(now.x, now.y);
|
||
|
||
this.ctx.lineWidth = 1.5 * this.dataToImageRatio;
|
||
this.ctx.stroke();
|
||
this.ctx.closePath();
|
||
|
||
// Attractor positions
|
||
this.ctx.beginPath();
|
||
this.ctx.lineWidth = 1.5 * this.dataToImageRatio;
|
||
this.ctx.moveTo(oldAttracXY.x, oldAttracXY.y);
|
||
this.ctx.lineTo(attracXY.x, attracXY.y);
|
||
this.ctx.arc(attracXY.x, attracXY.y, 1.5 * this.dataToImageRatio, 0, 2 * Math.PI, false);
|
||
|
||
//a /= 20;
|
||
this.ctx.strokeStyle = 'green';
|
||
this.ctx.fillStyle = 'green';
|
||
//this.ctx.stroke();
|
||
this.ctx.fill();
|
||
|
||
this.ctx.closePath();
|
||
|
||
// UI counter
|
||
this.drawnInLastFrame++;
|
||
}
|
||
|
||
};
|
||
App.dataXYtoCanvasXY = function (x, y) {
|
||
var zoom = 1.6;
|
||
var xx = this.xC + x * zoom * this.dataToImageRatio,
|
||
yy = this.yC + y * zoom * this.dataToImageRatio;
|
||
|
||
return { x: xx, y: yy };
|
||
};
|
||
|
||
setTimeout(function(){
|
||
console.log(1123)
|
||
App.setup();
|
||
App.draw();
|
||
|
||
var frame = function () {
|
||
App.evolve();
|
||
requestAnimationFrame(frame);
|
||
};
|
||
frame();
|
||
},5000)
|
||
|
||
|
||
/**
|
||
* Some old util I use at times
|
||
*
|
||
* @param {Number} Xstart X value of the segment starting point
|
||
* @param {Number} Ystart Y value of the segment starting point
|
||
* @param {Number} Xtarget X value of the segment target point
|
||
* @param {Number} Ytarget Y value of the segment target point
|
||
* @param {Boolean} realOrWeb true if Real (Y towards top), false if Web (Y towards bottom)
|
||
* @returns {Number} Angle between 0 and 2PI
|
||
*/
|
||
segmentAngleRad = function (Xstart, Ystart, Xtarget, Ytarget, realOrWeb) {
|
||
var result;// Will range between 0 and 2PI
|
||
if (Xstart == Xtarget) {
|
||
if (Ystart == Ytarget) {
|
||
result = 0;
|
||
} else if (Ystart < Ytarget) {
|
||
result = Math.PI / 2;
|
||
} else if (Ystart > Ytarget) {
|
||
result = 3 * Math.PI / 2;
|
||
} else { }
|
||
} else if (Xstart < Xtarget) {
|
||
result = Math.atan((Ytarget - Ystart) / (Xtarget - Xstart));
|
||
} else if (Xstart > Xtarget) {
|
||
result = Math.PI + Math.atan((Ytarget - Ystart) / (Xtarget - Xstart));
|
||
}
|
||
|
||
result = (result + 2 * Math.PI) % (2 * Math.PI);
|
||
|
||
if (!realOrWeb) {
|
||
result = 2 * Math.PI - result;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
}
|
||
}) |