[玩耍]JS实现几何星空

ACM忙完啦,最近想给自己的xienaoban.github.io做个博客网页,刚好没学过html之类的东西,就从零开始一边学一边做。之前一直对html5做的各种特效很感兴趣,就从网页背景开始写起吧。

曾经看到过别人的博客的背景有种特效,就是背景随机散布若干点不停移动,当两个点足够近的时候就会产生一条线连接两点,就像星座的连线一样;当点离鼠标很近的时候还会被吸引。于是自己也来实现个。

感觉js真的是个很神奇的语言,没有类,就把函数“假装”为类,并作为类似构造函数而存在,然后用prototype添加成员函数。看上去还真像那么回事,哈哈。

//==========================================
// File: background.js
// Title: 几何星空背景
// Auther: XieNaoban
// Version: v0.9
//==========================================

//创建背景画布
var cvs = document.createElement("canvas");
cvs.width = window.innerWidth;
cvs.height = window.innerHeight;
cvs.style.cssText="\
    position:fixed;\
    top:0px;\
    left:0px;\
    z-index:-1;\
    opacity:1.0;\
    ";
document.body.appendChild(cvs);

var ctx = cvs.getContext("2d");

var startTime = new Date().getTime();

//随机数函数
function randomInt(min,max) {
    return Math.floor((max-min+1)*Math.random()+min);
}
function randomFloat(min,max) {
    return (max-min)*Math.random()+min;
}

//构造点类
function Point() {
    this.x = randomFloat(0,cvs.width);
    this.y = randomFloat(0,cvs.height);

    var maxD = 0.08, minD = 0.01;
    this.speed = randomFloat(minD,maxD);
    this.angle = randomFloat(0,2*Math.PI);

    this.r = 1;

    var grey = (this.r*30+200);
    this.color = "rgba("+grey+","+grey+","+grey+",1)";
}

Point.prototype.move = function(dif) {
    var dx = Math.sin(this.angle)*this.speed;
    var dy = Math.cos(this.angle)*this.speed;
    this.x += dx*dif;
    if (this.x<0) {
        this.x=0;
        this.angle=2*Math.PI-this.angle;
    }
    else if (this.x>cvs.width){
        this.x=cvs.width;
        this.angle=2*Math.PI-this.angle;
    }
    this.y += dy*dif;
    if (this.y<0) {
        this.y=0;
        this.angle=Math.PI-this.angle;
    }
    else if (this.y>cvs.height){
        this.y=cvs.height;
        this.angle=Math.PI-this.angle;
    }
}

Point.prototype.draw = function() {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
    ctx.closePath();
    ctx.fill();
}

//绘制每一帧
var points = [];
function initPoints(num) {
    for (var i = 0; i<num; ++i) {
        points.push(new Point());
    }
}

var p0 = new Point();
var degree=5.0;
document.onmousemove = function(ev) {
    p0.x = ev.clientX;
    p0.y = ev.clientY;
}
document.onmousedown = function(ev) {
    degree = 10.0;
    p0.x = ev.clientX;
    p0.y = ev.clientY;
}
document.onmouseup = function(ev) {
    degree = 5.0;
    p0.x = ev.clientX;
    p0.y = ev.clientY;
}

function drawLine(p1,p2,d) {
    var dis = (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
    var t = 100/dis;
    t = Math.min(t,0.4);
    if(t<0.01) return false;
    t = Math.min(1,t*d);
    ctx.strokeStyle = "rgba(255,250,250,"+ t +")";
    ctx.beginPath();
    ctx.lineWidth=1;
    ctx.moveTo(p1.x,p1.y);
    ctx.lineTo(p2.x,p2.y);
    ctx.closePath();
    ctx.stroke();
    return true;
}

function drawFrame() {
    cvs.width = window.innerWidth;
    cvs.height = window.innerHeight;
    ctx.fillStyle = "rgba(0,43,54,1)";
    ctx.fillRect(0,0,cvs.width,cvs.height);
    var endTime = new Date().getTime();
    var dif = endTime-startTime;
    startTime = endTime;
    for(var i = 0; i<points.length; ++i) {
        for(var j = i+1; j<points.length; ++j) {
            var p1 = points[i], p2 = points[j];
            drawLine(p1,p2,3.0);
        }
    }
    for(var i = 0; i<points.length; ++i) {
        var p = points[i];
        drawLine(p0,p,degree);
        p.draw();
        p.move(dif);
    }
    window.requestAnimationFrame(drawFrame);
}

initPoints(70);
drawFrame();

没有去实现那个鼠标跟随,因为感觉我以后应该会自己想一个原创的更好玩的特效,这个就练练手好了。不过实现效果还是蛮炫酷的很满意啊,就是当最大化窗口就会显得稀疏,窗口小了看着太密。

还有个问题就是cpu占用太高了。。。每一帧要渲染70个点、判断 70 ∗ 70 = 490 70*70=490 7070=490条线(以及70个sin、cos可以优化为dx、dy)。。。果然以后必须得换个背景。。。(或者减少点并放大整个图形倒也不错)。

还有个八(te)哥(xing),就是切换到别的页面后不是本页面会停止渲染嘛,过半分钟再切回来会发现所有点挤在四个角落。原因是我是按照时间差来定下一帧每个点的位置的,当下一帧与当前帧的时间差太大的时候,每个点的移动距离都跑到屏幕外面了,于是被强制拉回屏幕的边缘。(感觉我这个实现方法会导致动画在低配电脑上看着很卡)。

你可能感兴趣的:(玩耍,Web,html5,JavaScript,js)