JS实现动态点图酷炫效果

news2025/4/3 1:27:06

实现目标

在这里插入图片描述

分析问题

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【思路篇】A题解题全流程(持续更新)

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】A题解题全流程-思路&#xff08;持续更新&#xff09; 写在前面&#xff1a; 1、A题、C题将会持续更新&#xff0c;陆续更新发布文章 2、赛题交流咨询Q群&#xff1a;1037590285 3、全家桶依旧包含&#xff1a; 代码、…

爱普生晶体单元FC2012AN在5G RedCap中的应用

在 5G 技术向物联网领域深度渗透的今天&#xff0c;RedCap&#xff08;5G 轻量化&#xff09;作为衔接中高速物联网场景的关键技术&#xff0c;正加速推动工业、医疗、可穿戴等领域的智能化升级。爱普生 FC2012AN 低 ESR 晶体单元凭借其突破性的小尺寸、低功耗与高稳定性设计&a…

vue 两种路由模式

一、两种模式比较 在vue.js中&#xff0c;路由模式分为两种&#xff1a;hash 模式和 history 模式。这两种模式决定了URL的结构和浏览器历史记录的管理方式。 1. hash 模式带 #&#xff0c;#后面的地址变化不会引起页面的刷新。换句话说&#xff0c;hash模式不会将#后面的地址…

Java-servlet(十)使用过滤器,请求调度程序和Servlet线程(附带图谱表格更好对比理解)

Java-servlet&#xff08;十&#xff09;使用过滤器&#xff0c;请求调度程序和Servlet线程 前言一、Servlet 间通信&#xff08;了解即可&#xff09;二、Servlet 请求处理&#xff1a;getAttribute 和 getParameter 的区别与应用1.getAttribute 方法2.getParameter 方法 三、…

ue5 学习笔记 FPS游戏制作35 GameMode与GameInstance

文章目录 相似GameMode介绍声明设置生效调用 GameInstance介绍声明设置生效调用 相似 两者都用来保存公共的数据和方法 数据都在内存里&#xff0c;关闭程序后数据消失 GameMode 介绍 生命周期跟随关卡&#xff0c;关卡销毁GameMode也跟随销毁 内部可以定义属性和方法 声明…

山洪预警秒级响应-AI本地化部署在极端降雨短临预测中的技术突破。AI智能体开发与大语言模型的本地化部署、优化技术

极端降雨预测的技术痛点与边缘破局 ‌1. 传统预警系统的三重瓶颈‌ ‌延迟致命‌&#xff1a;WRF模式在1km分辨率下3小时预报耗时>45分钟&#xff0c;错过山洪黄金响应期 ‌地形干扰大‌&#xff1a;复杂地形区&#xff08;如横断山脉&#xff09;降水预测误差超50% ‌数…

矿山自动化监测解决方案

1.行业现状 为贯彻落实《中共中央国务院关于推进安全生产领域改革发展的意见》《“十四五”矿山安全生产规划》&#xff08;应急〔2022〕64号&#xff09;、《国务院安委会办公室关于加强矿山安全生产工作的紧急通知》&#xff08;安委办〔2021〕3号&#xff09;等有关工作部署…

pytorch学习(b站小土堆学习)

1 环境配置 参考链接 2. dir 和 help函数 dir()&#xff1a;用于查看某一模块函数的方法 help()&#xff1a; 用于查看某方法的使用方法 3. dataset类实战 利用Image对象打开图片&#xff0c;利用os模块的地址拼接组成图片路径 当我们用方括号访问元素对象时&#xff0c;…

【最新】探索CFD的未来:从OpenFOAM到深度学习,全面解析计算流体力学的顶级资源与前沿技术

计算流体力学(CFD)作为现代工程与科学研究的核心工具,正以前所未有的速度迈向智能化与多物理场耦合的新时代。本文全面梳理了在线学习CFD的顶级资源,涵盖了从传统数值模拟到深度学习驱动的物理信息模型的广泛领域,旨在为研究者、工程师和学生提供一站式参考指南。内容分为…

算法专题一:双指针算法(下)

书接上回 5.有效三角形个数 力扣&#xff1a; 有效三角形的个数 在做这道题前我们先讲一个数学知识&#xff1a;已知 a < b < c ,此时 ab>c 可以得出 有效三角形。 所以&#xff0c;我们做这道题时&#xff0c;可以不使用暴力算法。 可以优化为先排序&#xff…

咪咕MG101_晨星MSO9380芯片_安卓5.1.1_免拆卡刷固件包

咪咕MG101_晨星MSO9380芯片_安卓5.1.1_免拆卡刷固件包&#xff08;内有教程&#xff09; 刷机教程简单说明&#xff1a; 1、把下载好的刷机包&#xff0c;U盘里建立一个upgrade文件夹&#xff0c;固件放入此文件夹里&#xff0c;放入U盘中&#xff0c;注意升级包为压缩包不要对…

T11 TensorFlow入门实战——优化器对比实验

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習紀錄博客&#x1f356; 原作者&#xff1a;K同学啊 | 接輔導、項目定制 一、前期准备 1. 导入数据 # Import the required libraries import pathlib import matplotlib.pyplot as plt import tensorflow as t…

2023年3月全国计算机等级考试真题(二级C语言)

&#x1f600; 第1题 下列叙述中错误的是 A. 向量是线性结构 B. 非空线性结构中只有一个结点没有前件 C. 非空线性结构中只有一个结点没有后件 D. 只有一个根结点和一个叶子结点的结构必定是线性结构 概念澄清 首先&#xff0c;我们需要明确几个关键概念&#xf…

在MFC中使用Qt(四):使用属性表(Property Sheet)实现自动化Qt编译流程

前言 首先回顾下前面文章介绍的&#xff1a; 在MFC中使用Qt&#xff08;一&#xff09;&#xff1a;玩腻了MFC&#xff0c;试试在MFC中使用Qt&#xff01;&#xff08;手动配置编译Qt&#xff09; 在MFC中使用Qt&#xff08;二&#xff09;&#xff1a;实现Qt文件的自动编译流…

Python-八股总结

目录 1 python 垃圾处理机制2 yield3 python 多继承&#xff0c;两个父类有同名方法怎么办&#xff1f;4 python 多线程/多进程/协程4.1 多线程与GIL全局解释器锁4.2 多进程4.3 协程 5 乐观锁/悲观锁6 基本数据结构**1. 列表&#xff08;List&#xff09;****2. 元组&#xff0…

局域网数据同步软件,局域网数据备份的方法

局域网数据备份的方法&#xff1a; 局域网数据备份是确保数据安全性的重要措施&#xff0c;以下是一些常用的局域网数据备份方法&#xff1a; 1.使用NAS设备备份 特点&#xff1a;网络附加存储&#xff08;NAS&#xff09;设备提供了一种便捷的备份方式。 操作&#xff1a;…

座舱与智驾“双轮驱动”,芯擎科技打造智能汽车“芯”标杆

在比亚迪、吉利、奇瑞等各大主机厂打响“全民智驾”的关键时期&#xff0c;以芯擎科技为代表中国芯片厂商开始“放大招”。 2025年3月27日&#xff0c;芯擎科技在南京举办了“擎随芯动、智融万象”生态科技日&#xff0c;重磅发布了“星辰一号”、“星辰一号Lite”&#xff0c…

《新能源汽车 DEEA 平台开发策略》

一、引言 在新能源汽车行业加速向智能化、电动化转型的当下&#xff0c;电子电气架构&#xff08;EEA&#xff09;成为汽车技术创新的关键领域。DEEA 平台作为应对行业变革的重要举措&#xff0c;其开发策略对于提升汽车产品竞争力、满足市场多样化需求意义重大。本策略围绕平台…

从零开始:Windows 系统中 PowerShell 配置 FFmpeg 的详细步骤

在Windows系统中不想每次都 cd 到FFmpeg目录中应用&#xff0c;现在可以通过PowerShell在任意目录下应用了。 PowerShell 基础概念 跨平台脚本工具 PowerShell 是微软开发的命令行外壳和脚本语言&#xff0c;支持 Windows、Linux 和 macOS 系统。其核心优势在于面向对象的操作…

Java-拼图小游戏跟学笔记

阶段项目-01-项目介绍和界面搭建_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV17F411T7Ao?p144 代码 1.主界面分析(组件) JFrame:最外层的窗体 JMenuBar:最上层的菜单 JLabel:管理文字和图片的容器 1.界面 --关闭模式-- DO_NOTHING_ON_CLOSE&#xff1a;当用户…