当前位置: 首页 > news >正文

JS实现动态点图酷炫效果

实现目标

在这里插入图片描述

分析问题

整个图主要是用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();

相关文章:

  • git命令简陋版本
  • MySQL 复制与主从架构(Master-Slave)
  • Day48 | 657. 机器人能否返回原点、31. 下一个排列、463. 岛屿的周长、1356. 根据数字二进制下 1 的数目排序
  • 嵌入式系统简介
  • PH热榜 | 2025-03-31
  • MTU | 检测 / 设置 / 相关问题解析
  • 【JavaEE进阶】MyBatis(4)-完善图书管理系统
  • ros2--xacro
  • uniapp中如何用iconfont来管理图标集成到我们开发的项目中
  • 基于AT89C52单片机的轮胎压力监测系统
  • 学习threejs,使用THREE.ImageUtils.loadTexture加载纹理贴图
  • C++11:包装器(适配器模式)
  • TCP/IP协议的应用层与传输层
  • 【PythonRS】哨兵2号(Sentinel2)轨道条带说明+图幅统计(表格+矢量)
  • 51单片机的五类指令(四)——控制转移类指令
  • ai画图esrgan放大算法。
  • HTB-Code
  • AWS中S3的使用
  • Python Cookbook-4.18 搜集命名的子项
  • SAPIEN 仿真环境下的 pose
  • 外贸网站怎样做推广/今日国际新闻事件
  • 大网站建设/如何做友情链接
  • 网站排名第一/武汉竞价托管公司
  • 做网站怎么给客户打电话/哪家培训机构学校好
  • 佛山网站制作做多少钱/关键词推广工具
  • 湖北省建设厅官方网站电话/百度搜索app