html5 canvas 矢量,HTML5 Canvas 基于3D矢量类实现的宇宙网络图

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

(function() {

'use strict';

// Configuration options

var opts = {

background: 'black',

numberOrbs: 50, // increase with screen size. 50 to 100 for my 2560 x 1400 monitor

maxVelocity: 2.5, // increase with screen size--dramatically affects line density. 2 for me

orbRadius: 1, // keep small unless you really want to see the dots bouncing. I like <= 1.

minProximity: 100, // controls how close dots have to come to each other before lines are traced

initialColorAngle: 7, // 7 initializes the color phaser on red

colorFrequency: 0.3, // 0.3 default

colorAngleIncrement: 0.009, // 0.009 is slow and even

globalAlpha: 0.010, //controls alpha for lines, but not dots (despite the name)

manualWidth: false, // Default: false, change to your own custom width to override width = window.innerWidth

manualHeight: false // Default: false, change to your own custom height to override height = window.innerHeight

};

// Canvas globals

var canvasTop, linecxt, canvasBottom, cxt, width, height, animationFrame;

// Global objects

var orbs;

// Orb object - these are the guys that bounce around the screen.

// We will draw lines between these dots, but that behavior is found

// in the Orbs container object

var Orb = (function() {

// Constructor

function Orb(radius, color) {

var posX = randBetween(0, width);

var posY = randBetween(0, height);

this.position = new Vector(posX, posY);

var velS = randBetween(0, opts.maxVelocity); // Velocity scalar

this.velocity = Vector.randomDirection().multiply(velS).noZ();

this.radius = radius;

this.color = color;

}

// Orb methods

Orb.prototype = {

update: function() {

// position = position + velocity

this.position = this.position.add(this.velocity);

// bounce if the dot reaches the edge of the container.

// this can be EXTREMELY buggy with large dot radiuses, but it works for this

// drawing.

if (this.position.x + this.radius >= width || this.position.x - this.radius <= 0) {

this.velocity.x = this.velocity.x * -1;

}

if (this.position.y + this.radius >= height || this.position.y - this.radius <= 0) {

this.velocity.y = this.velocity.y * -1;

}

},

display: function() {

cxt.beginPath();

cxt.fillStyle = this.color;

cxt.ellipse(this.position.x, this.position.y, this.radius, this.radius, 0, 0, 2 * Math.PI, false);

cxt.fill();

cxt.closePath();

},

run: function() {

this.update();

this.display();

}

};

return Orb;

})();

// Orbs object - this is a container that manages all of the individual Orb objects.

// In addition, this object holds the color phasing and line-drawing functionality,

// since it already iterates over all the orbs once per frame anyway.

var Orbs = (function() {

// Constructor

function Orbs(numberOrbs, radius, initialColorAngle, globalAlpha, colorAngleIncrement, colorFrequency) {

this.orbs = [];

this.colorAngle = initialColorAngle;

this.colorAngleIncrement = colorAngleIncrement;

this.globalAlpha = globalAlpha;

this.colorFrequency = colorFrequency;

this.color = null;

for (var i = 0; i < numberOrbs; i++) {

this.orbs.push(new Orb(radius, this.color));

}

}

Orbs.prototype = {

run: function() {

this.phaseColor();

for (var i = 0; i < this.orbs.length; i++) {

for (var j = i + 1; j < this.orbs.length; j++) {

// we only want to compare this orb to orbs which are further along in the array,

// since any that came before will have already been compared to this orb.

this.compare(this.orbs[i], this.orbs[j]);

}

this.orbs[i].color = this.color;

this.orbs[i].run();

}

},

compare: function(orbA, orbB) {

// Get the distance between the two orbs.

var distance = Math.abs(orbA.position.subtract(orbB.position).length());

if (distance <= opts.minProximity) {

// the important thing to note here is that we're drawing this onto '#canvas-top'

// since we want to preserve everything drawn to that layer.

linecxt.beginPath();

linecxt.strokeStyle = this.color;

linecxt.globalAlpha = this.globalAlpha;

linecxt.moveTo(orbA.position.x, orbA.position.y);

linecxt.lineTo(orbB.position.x, orbB.position.y);

linecxt.stroke();

linecxt.closePath();

}

},

phaseColor: function() {

// color component = sin(freq * angle + phaseOffset) => (between -1 and 1) * 127 + 128

var r = Math.floor(Math.sin(this.colorFrequency * this.colorAngle + Math.PI * 0 / 3) * 127 + 128);

var g = Math.floor(Math.sin(this.colorFrequency * this.colorAngle + Math.PI * 2 / 3) * 127 + 128);

var b = Math.floor(Math.sin(this.colorFrequency * this.colorAngle + Math.PI * 4 / 3) * 127 + 128);

this.color = 'rgba(' + r + ', ' + g + ', ' + b + ', 1)';

this.colorAngle += this.colorAngleIncrement;

}

};

return Orbs;

})();

// This function is called once and only once to kick off the code.

// It links DOM objects like the canvas to the respective global variable.

function initialize() {

canvasTop = document.querySelector('#canvas-top'); // this canvas is for the lines between dots

canvasBottom = document.querySelector('#canvas-bottom'); // this canvas is for the dots that bounce around

linecxt = canvasTop.getContext('2d');

cxt = canvasBottom.getContext('2d');

window.addEventListener('resize', resize, false);

resize();

}

// This function is called after initialization and window resize.

function resize() {

width = opts.manualWidth ? opts.manualWidth : window.innerWidth;

height = opts.manualHeight ? opts.manualHeight : window.innerHeight;

setup();

}

// after window resize we need to

function setup() {

canvasTop.width = width;

canvasTop.height = height;

canvasBottom.width = width;

canvasBottom.height = height;

//fillBackground(linecxt); // Enable this line if you want to save an image of the drawing.

fillBackground(cxt);

orbs = new Orbs(opts.numberOrbs, opts.orbRadius, opts.initialColorAngle, opts.globalAlpha, opts.colorAngleIncrement, opts.colorFrequency);

// If we hit this line, it was either via initialization procedures (which means animationFrame is undefined)

// or through window resize, in which case we need to cancel the old draw loop and make a new one.

if (animationFrame !== undefined) {

cancelAnimationFrame(animationFrame);

}

draw();

}

// Notice that we only fillBackground on one of the two canvases. This is because we want to animate

// the dot layer (we don't want to leave trails left by the dots), but preserve the line layer.

function draw() {

fillBackground(cxt);

orbs.run();

// Update the global animationFrame variable -- this enables to cancel the redraw loop on resize

animationFrame = requestAnimationFrame(draw);

}

// generic background fill function

function fillBackground(context) {

context.fillStyle = opts.background;

context.fillRect(0, 0, width, height);

}

// get random float between two numbers, inclusive

function randBetween(low, high) {

return Math.random() * (high - low) + low;

}

// get random INT between two numbers, inclusive

function randIntBetween(low, high) {

return Math.floor(Math.random() * (high - low + 1) + low);

}

// Start the code already, dammit!

initialize();

})();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值