实现目标
分析问题
整个图主要是用canvas实现,其中难点是将线的长度控制在一定范围内、并且透明度随长度变化。
前置知识
canvas绘制点、线、三角形、弧形
// 点
ctx.moveTo(this.x, this.y);
ctx.arc(this.x, this.y, this.r,
0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
// 线
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
// 三角形
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.lineTo(p3.x, p3.y);
ctx.closePath();
// 弧形
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI / 2, false); // 从 0° 到 90°(顺时针)
ctx.strokeStyle = "blue";
ctx.lineWidth = 3;
ctx.stroke();
代码实战
实现思路
随机生成n个点,然后随机选m个 三个随机点(属于n个点中) 组成的集合绘制三角形。
<head>
<style>
* {
margin: 0 auto;
padding: 0;
}
canvas {
position: fixed;
background: black;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas></canvas>
<script src="./index.js"></script>
</body>
// 获取 canvas节点
let cts = document.querySelector("canvas");
let ctx = cts.getContext("2d");
// 设置宽高
cts.width = window.innerWidth;
cts.height = window.innerHeight;
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
this.r = 1;
}
draw() {
ctx.moveTo(this.x, this.y);
ctx.arc(this.x, this.y, this.r,
0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
}
}
class Graph {
constructor() {
// 圆点个数
this.pointSize = 500;
this.maxHeight = window.innerHeight;
this.maxWidth = window.innerWidth;
// 对角线
this.maxLine = Math.sqrt(this.maxHeight * this.maxHeight + this.maxWidth * this.maxWidth);
// 所有点集
this.points = new Array(this.pointSize).fill(0)
.map(() =>
new Point(Math.random() * this.maxWidth, Math.random() * this.maxHeight))
}
// 绘制 p1-p2 直线
drawLine(p1, p2) {
let tLine = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
let at = 0.2 - tLine / 500;// this.maxLine;
// 太长的线不绘制
if (tLine > 100) return;
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.strokeStyle = `rgba(255, 255, 255, ${at})`;
}
// 绘制三角形
drawRan(p1, p2, p3) {
if (!p1 || !p2 || !p3) return;
ctx.beginPath();
this.drawLine(p1, p2);
this.drawLine(p2, p3);
ctx.stroke();
}
draw() {
// 绘制所有圆点
for (let i = 0; i < this.pointSize; i++) {
let p1 = this.points[i];
p1.draw();
}
// 选取随机的三点绘制三角形
for (let i = 0; i < this.pointSize * this.pointSize / 10; i++) {
let t1 = Math.floor(Math.random() * this.pointSize);
let t2 = Math.floor(Math.random() * this.pointSize);
let t3 = Math.floor(Math.random() * this.pointSize);
let p1 = this.points[t1];
let p2 = this.points[t2];
let p3 = this.points[t3];
this.drawRan(p1, p2, p3);
}
}
}
let init = () => {
let g = new Graph();
g.draw();
}
init();
优化
点集动态移动(弧形),随机选点、弧形半径随机。
let cts = document.querySelector("canvas");
let ctx = cts.getContext("2d");
let setWH = () => {
cts.width = window.innerWidth;
cts.height = window.innerHeight;
}
let clearBG = () => {
ctx.clearRect(0, 0, cts.width, cts.height);
}
class Point {
constructor(x, y) {
this.px = x;
this.py = y;
this.r = 1;
this.radius = 500 * Math.random();
this.angle = 0;
}
draw() {
ctx.moveTo(this.x, this.y);
ctx.arc(this.x, this.y, this.r,
0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
}
move() {
this.x = this.px + this.radius * Math.cos(this.angle);
this.y = this.py + this.radius * Math.sin(this.angle);
this.angle = (this.angle + 0.05) % (Math.PI * 2);
}
}
class Graph {
constructor() {
this.pointSize = 500;
this.maxHeight = window.innerHeight;
this.maxWidth = window.innerWidth;
this.maxLine = Math.sqrt(this.maxHeight * this.maxHeight + this.maxWidth * this.maxWidth);
this.points = new Array(this.pointSize).fill(0)
.map(() =>
new Point(Math.random() * this.maxWidth, Math.random() * this.maxHeight))
}
drawLine(p1, p2) {
let tLine = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
let at = 0.2 - tLine / 500;// this.maxLine;
if (tLine > 100) return;
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.strokeStyle = `rgba(255, 255, 255, ${at})`;
}
drawRan(p1, p2, p3) {
if (!p1 || !p2 || !p3) return;
ctx.beginPath();
this.drawLine(p1, p2);
this.drawLine(p2, p3);
ctx.stroke();
}
draw() {
for (let i = 0; i < this.pointSize; i++) {
let p1 = this.points[i];
p1.move();
p1.draw();
}
for (let i = 0; i < this.pointSize * this.pointSize / 10; i++) {
let t1 = Math.floor(Math.random() * this.pointSize);
let t2 = Math.floor(Math.random() * this.pointSize);
let t3 = Math.floor(Math.random() * this.pointSize);
let p1 = this.points[t1];
let p2 = this.points[t2];
let p3 = this.points[t3];
this.drawRan(p1, p2, p3);
}
}
}
let timer = null;
let init = () => {
setWH();
let g = new Graph();
timer = setInterval(() => {
clearBG();
g.draw();
}, 1000)
}
init();