SOURCE

console 命令行工具 X clear

                    
>
console
var NUM_PARTICLES = ((ROWS = 5) * (COLS = 11)),
    LIMIT_MAX = Math.pow(400, 2),
    LIMIT_MIN = Math.pow(50, 2),
    CL_1 = 8 / LIMIT_MAX,
    CL_2 = 10 / LIMIT_MAX,
    CL_3 = 12 / LIMIT_MAX,
    SL = 5 / LIMIT_MAX,
    MARGIN = 150,
    SPACING = 150,
    COLOR = 220,
    color,
    PUSH = 0.95,
    POP = 0.15,
    tog = true,
    container, ctx,
    particle,
    canvas,
    p, list,
    a, offset,
    count = 0,
    w, h,
    mx, my,
    dx, dy,
    d, l, ds,
    s,
    newiterations, i, j, k,
    ClearnData, Clearn;
c = [0, 0, 0]
bg = [13, 27, 34];
pt1 = {
    x: 0,
    y: 0
};
pt2 = {
    x: 0,
    y: 0
};
half = {
    x: 0,
    y: 0
};
ho = {
    x: 0,
    y: 0
};
iterations = [pt1, pt2];
particle = {
    vx: 0,
    vy: 0,
    x: 0,
    y: 0
};

function init() {

    container = document.getElementById('container');
    canvas = document.createElement('canvas');

    ctx = canvas.getContext('2d');

    list = [];
    l = [];
    ds = [];

    w = canvas.width = (COLS - 1) * SPACING + MARGIN * 2;
    h = canvas.height = (ROWS - 1) * SPACING + MARGIN * 2;

    container.style.marginLeft = Math.round(w * -0.5) + 'px';
    container.style.marginTop = Math.round(h * -0.5) + 'px';

    ClearnData = (Clearn = ctx.createImageData(w, h)).data;

    for (i = 0; i < NUM_PARTICLES; i++) {

        p = Object.create(particle);

        if (i % 2 == 0) {

            p = Object.create(particle);
            p.x = p.ox = MARGIN + SPACING * (i % COLS);
            p.y = p.oy = MARGIN + SPACING * Math.floor(i / COLS);

        }

        list[i] = p;
        l[i] = false;
        ds[i] = 0;

        if ((i + 1) % 4 == 0) {
            ClearnData[i] = 255;
        } else {
            ClearnData[i] = 11;
        }

    }

    container.addEventListener('mousemove', function(e) {

        bounds = container.getBoundingClientRect();
        mx = pt2.x = e.clientX - bounds.left;
        my = pt2.y = e.clientY - bounds.top;

    });

    container.appendChild(canvas);

}

function step() {

    if (tog = !tog) {

        for (i = 0; i < NUM_PARTICLES; i = i + 2) {

            p = list[i];
            d = (dx = mx - p.x) * dx + (dy = my - p.y) * dy;
            f = ((LIMIT_MAX + LIMIT_MIN) / 2) / d;
            if (d < LIMIT_MAX && d > LIMIT_MIN) { //只针对半径小于限制的粒子
                t = Math.atan2(dy, dx);
                p.vx += f * Math.cos(t);
                p.vy += f * Math.sin(t);
                l[i] = true;
                ds[i] = LIMIT_MAX - d;
            }
            p.x += p.vx + (p.ox - p.x) * POP; //PUSH向外步长,POP还原步长
            p.y += p.vy + (p.oy - p.y) * POP;
            p.vx = 0;
            p.vy = 0;

        }

    } else { //显示粒子

        ctx.putImageData(Clearn, 0, 0);

        for (i = 0; i < NUM_PARTICLES; i = i + 2) {

            p = list[i];
            color = "#ffffff";

            if (l[i] == true) {
                pt1 = {
                    x: p.x,
                    y: p.y
                };
                c = [7 + ~~(ds[i] * CL_1), 12 - ~~(ds[i] * CL_2), 15 - ~~(ds[i] * CL_3)];
                color = '#' + c[0].toString(16) + '0' + c[1].toString(16) + '0' + c[2].toString(16) + '0';
                s = Math.max(1, ~~(ds[i] * SL));
                lightning();
                l[i] = false;
            }

            ctx.strokeStyle = '#000000';
            ctx.lineWidth = 5;
            ctx.beginPath();
            ctx.arc(~~p.x, ~~p.y, 20, 0, Math.PI * 2, true);
            ctx.closePath();
            ctx.fillStyle = color;
            ctx.fill();
            ctx.stroke();

        }

    }

    requestAnimationFrame(step);
}

function lightning() {

    iterations = [pt1, pt2];
    for (k = 0; k < 8; k++) { //二分法取点
        newiterations = [iterations[0]]
        for (j = 1; j < iterations.length; j++) {
            newiterations.push(getRandMidpoint(iterations[j - 1], iterations[j], 100 / (k * k + 1)))
            newiterations.push(iterations[j])
        }
        iterations = newiterations.concat([])
    }
    ctx.beginPath();
    ctx.moveTo(iterations[0].x, iterations[0].y);
    ctx.lineWidth = s;
    ctx.strokeStyle = color;
    for (k = 1; k < iterations.length; k++) {
        ctx.lineTo(iterations[k].x, iterations[k].y);
    }
    ctx.stroke()
    ctx.closePath()

}

function getRandMidpoint(pa, pb, range) {
    a = Math.atan2(pb.y - pa.y, pb.x - pa.x) + Math.PI / 2;
    half = {
        y: (pb.y - pa.y) / 2 + pa.y,
        x: (pb.x - pa.x) / 2 + pa.x
    };
    offset = Math.random() * range - range / 2;
    ho = {
        x: Math.cos(a) * offset + half.x,
        y: Math.sin(a) * offset + half.y
    }
    return ho;
}

init();
step();
<!DOCTYPE html>
<html>

<head>

    <meta charset="UTF-8">

    <title>Ligtning_Web</title>
    <style>
        html,
        body {
            background: #111111;
        }
        #container {
            background: #111111;
            position: absolute;
            left: 50%;
            top: 50%;
        }
    </style>
    <script src="js/prefixfree.min.js"></script>
</head>

<body>

    <div id='container'></div>
    <script src="js/index.js"></script>
</body>

</html>
html,
body {
    position: absolute;
    width: 100%;
    height: 100%;
    margin: 0 0;
    overflow: hidden;
    font-family: 'Lato', sans-serif;
    background-color: #000;
    color: #fff;
}
.world {
    position: absolute;
    width: 100%;
    height: 100%;
    cursor: pointer;
    cursor: move;
    cursor: -moz-grab;
    cursor: -webkit-grab;
    cursor: grab;
}
.world-bg {
    position: absolute;
    width: 100%;
    height: 100%;
    background-position: 50% 50%;
    background-size: cover;
}
.world-globe {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 0;
    height: 0;
}
.world-globe-pole {
    position: absolute;
    width: 530px;
    height: 530px;
    left: -265px;
    top: -265px;
    border-radius: 50% 50%;
    background-color: #fff;
}
.world-globe-doms-container {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 0;
    height: 0;
}
.world-globe-halo {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 730px;
    height: 715px;
    margin-left: -368px;
    margin-top: -350px;
}
.info {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    padding: 10px 10px;
    box-sizing: border-box;
    background-color: rgba(0, 0, 0, 0.8);
    color: #fff;
    font-size: 12px;
}
.info-desc {
    color: #ddd;
    font-size: 10px;
}
a {
    color: #ff5f5f;
}