canvas:绘制点和点之间连线

news2024/10/11 22:21:56

效果图:
在这里插入图片描述

<template>
    <div class="home-box">
        <canvas id="canvas" />
        <div class="lightCircle" ref="circleRef" v-for="(item,index) in 5" :key="index"></div>
        <div class="lightCircle" ref="circleRef2" v-for="(item,index) in 5" :key="index + '1'"></div>
        <div :class="'lightCircle2 lightCircle2'+index" ref="circleRef3" v-for="(item,index) in 5" :key="index + '2'"></div>
        <div ref="circle0" class="circle circle0">
            <span class="chi">一级菜单</span>
        </div>
        <div ref="circle1" class="circle circle1">
            <span class="chi">二级菜单1</span>
        </div>
        <div ref="circle2" class="circle circle2">
            <span class="chi">二级菜单2</span>
        </div>
        <div ref="circle3" class="circle circle3">
            <span class="chi">二级菜单3</span>
        </div>
        <div ref="circle4" class="circle circle4">
            <span class="chi">二级菜单4</span>
        </div>
        <div ref="circle5" class="circle circle5">
            <span class="chi">二级菜单5</span>
        </div>
    </div>
</template>

<script>
export default {
    name: "homePage",
    data () {
        return {
            resizeTimer: null,
        }
    },
    mounted () {
        this.initCanvas();
    },
    methods: {
        initCanvas () {
            let that = this;
            let canvas = document.getElementById("canvas");
            let ctx = canvas.getContext("2d");

            this.canvasResize(canvas, ctx);
            window.onresize = function () {
                setTimeout(() => {
                    that.canvasResize(canvas, ctx, 1);
                }, 500)
            }
        },
        canvasResize (canvas, ctx, flag) {
            canvas.width = canvas.offsetWidth;
            canvas.height = canvas.offsetHeight;
            this.createLine(canvas, ctx, flag);//画线
        },
        createLine (canvas, ctx, flag) {
            let that = this;
            let { circle0, circle1, circle2, circle3, circle4, circle5 } = this.$refs,//offsetLeft依次对应 圆心,左上角
                r0 = circle0.offsetWidth / 2,
                r1 = circle1.offsetWidth / 2,
                dig0 = Math.PI / 9,//20度
                dig1 = Math.PI / 6,//30度
                dig3 = Math.PI / 3,//60度
                dig4 = Math.PI / 18,//10度
                dig5 = Math.PI * 11 / 36,//55度
                // console.log(Math.sin(Math.PI/2));//等于1,Math.PI代表180度
                //五环上的坐标
                valueArr1 = [
                    {//value1
                        x: circle1.offsetLeft + r1 + r1 * Math.cos(dig1),
                        y: circle1.offsetTop + r1 + r1 * Math.sin(dig1),
                    },
                    {//value2
                        x: circle2.offsetLeft + r1 - r1 * Math.sin(dig3),
                        y: circle2.offsetTop + r1 + r1 * Math.cos(dig3),
                    },
                    {//value3
                        x: circle3.offsetLeft,
                        y: circle3.offsetTop + r1,
                    },
                    {//value4
                        x: circle4.offsetLeft + r1 - r1 * Math.sin(dig1),
                        y: circle4.offsetTop + r1 - r1 * Math.cos(dig1),
                    },
                    {//value5
                        x: circle5.offsetLeft + r1 + r1 * Math.cos(dig0),
                        y: circle5.offsetTop + r1 - r1 * Math.sin(dig0),
                    },
                ],
                //圆心上的坐标
                valueArr0 = [
                    {//对应value1
                        x: circle0.offsetLeft - r0 * Math.cos(dig0),
                        y: circle0.offsetTop - r0 * Math.sin(dig0),
                    },
                    {//对应value2
                        x: circle0.offsetLeft + r0 * Math.cos(dig1),
                        y: circle0.offsetTop - r0 * Math.sin(dig1),
                    },
                    {//对应value3
                        x: circle0.offsetLeft + r0 * Math.cos(dig4),
                        y: circle0.offsetTop + r0 * Math.sin(dig4),
                    },
                    {//对应value4
                        x: circle0.offsetLeft + r0 * Math.cos(dig5),
                        y: circle0.offsetTop + r0 * Math.sin(dig5),
                    },
                    {//对应value5
                        x: circle0.offsetLeft - r0 * Math.cos(dig0),
                        y: circle0.offsetTop + r0 * Math.sin(dig0),
                    },
                ];

            clear();
            createCircle(flag);
            for (let i = 0; i < valueArr1.length; i++) {
                drawDynamicLine(valueArr1[i].x, valueArr1[i].y, valueArr0[i].x, valueArr0[i].y);
            }

            /*清除画布*/
            function clear () {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            }

            /*画点*/
            function createCircle (flag) {
                ctx.fillStyle = "#01abf9";

                let style = document.styleSheets[0];//keyframes
                if (flag == 1) {
                    //自适应拖动屏幕时,删除keyframes样式
                    for (let j = 0; j < valueArr1.length; j++) {
                        style.deleteRule("Mylight" + j);
                    }
                }

                for (let i = 0; i < valueArr1.length; i++) {
                    that.$nextTick(() => {
                        if (that.$refs.circleRef[i]) {
                            that.$refs.circleRef[i].style.left = valueArr1[i].x - 1 + 'px';
                            that.$refs.circleRef[i].style.top = valueArr1[i].y - 1 + 'px';
                        }
                        if (that.$refs.circleRef2[i]) {
                            that.$refs.circleRef2[i].style.left = valueArr0[i].x - 1 + 'px';
                            that.$refs.circleRef2[i].style.top = valueArr0[i].y - 1 + 'px';
                        }
                        // 写入keyframes样式
                        style.insertRule(`@keyframes Mylight${i}{
                            0% { left:${that.$refs.circleRef[i].style.left};top:${that.$refs.circleRef[i].style.top}}
                            90%{ opacity:1}
                            100%{left:${that.$refs.circleRef2[i].style.left};opacity:0;top:${that.$refs.circleRef2[i].style.top};}
                        }`, 1);
                    })
                }
                ctx.shadowBlur = 2;//Reseting the blur
            }

            /*
                绘制两点直线
                画动态直线
                @(x1,y1)    起点
                @(x2,y2)    终点
            */
            function drawDynamicLine (x1, y1, x2, y2) {
                const x22 = x2;
                const y22 = y2;

                if (x1 == x2) {
                    drawVerticalLine(x1, y1, x2, y2);   /*斜率不存在的情况*/
                } else {
                    drawCommonLine(x1, y1, x2, y2);    /*斜率为正或者负或者0*/
                }

                /*k存在的情况*/
                function drawCommonLine (x1, y1, x2, y2) {
                    let timer1 = null;
                    clearInterval(timer1);

                    //y=kx+b
                    let k = (y2 - y1) / (x2 - x1)   //斜率k     正 负 0
                    let b = y1 - k * x1           //常数b
                    let i = 0;
                    let flag = compare(x1, x2);

                    function draw () {
                        let xi = x1 + i;
                        let yi = k * xi + b;
                        let xj = x1 + i + 20;     //控制步长决定绘制的是虚线还是实线
                        let yj = k * xj + b;
                        //最后一段 线段的步长缝合
                        if (xj + 20 > x22 || yj + 20 > y22) {
                            let a = x22 + 20 - xj;
                            xj = x1 + i + a;
                            yj = k * xj + b;
                            // console.log(1,xj,yj,x22,y22);
                            drawLine(xi, yi, xj, yj);
                            return
                        }
                        drawLine(xi, yi, xj, yj);
                        i += 20 * flag;

                        if (Math.abs(i) <= Math.abs(x1 - x2)) {
                            timer1 = window.setTimeout(function () {
                                draw();
                            }, 50);
                        }
                    }

                    draw();
                }

                /*k不存在,也就是垂直的情况*/
                function drawVerticalLine (x1, y1, x2, y2) {
                    let timer2 = null;
                    clearInterval(timer2);
                    let i = 0;
                    let flag = compare(y1, y2);

                    function draw () {
                        let yi = y1 + i;
                        let yj = y1 + i + 5 * flag;
                        drawLine(x1, yi, x2, yj);
                        i += 20 * flag;
                        if (Math.abs(i) <= Math.abs(y1 - y2)) {
                            timer2 = window.setTimeout(function () {
                                draw();
                            }, 50);
                        }
                    }
                    draw();
                }

                /*比较函数*/
                function compare (a, b) {
                    if (a < b) {
                        return 1;
                    } else {
                        return -1;
                    }
                }

                /*线条片段*/
                function drawLine (x1, y1, x2, y2) {
                    //线条发光
                    ctx.shadowColor = "#fff";
                    ctx.shadowOffsetX = 0;
                    ctx.shadowOffsetY = 0;
                    ctx.shadowBlur = 15;

                    ctx.beginPath();
                    ctx.moveTo(x1, y1);
                    ctx.lineTo(x2, y2);
                    ctx.lineWidth = 2;
                    ctx.strokeStyle = "#01bbf3";//线条颜色
                    ctx.stroke();
                    ctx.closePath();
                    ctx.fill();
                }
            }
        }
    }
}
</script>

<style scoped lang="less">
.home-box {
	width: 100%;
	height: 100%;
	color: #ffffff;
	font-size: 32px;
	font-weight: 600;
	line-height: 38px;
	position: relative;
	background: #f2f2f2;

	canvas {
		width: 100%;
		height: 100%;
		position: absolute;
	}

	span.chi {
		width: 90px;
		text-align: center;
		height: auto;
		animation: none;
	}

	.circle {
		width: 250px;
		height: 250px;
		display: flex;
		justify-content: center;
		align-items: center;
		position: absolute;
		cursor: pointer;

		&.circle0 {
			width: 360px;
			height: 360px;
			left: 50%;
			top: 45%;
			transform: translateX(-50%) translateY(-50%);

			.chi {
				width: 130px;
				text-align: center;
				height: 92px;
				font-size: 30px;
				font-family: PingFangSC-Semibold, PingFang SC;
				font-weight: 600;
				color: rgba(181, 232, 255, 1);
				line-height: 46px;
				text-shadow: 0px 0px 2px rgba(137, 218, 255, 1);
			}
		}

		&.circle1 {
			left: 22%;
			top: 8%;
		}

		&.circle2 {
			left: 63%;
			top: 5%;
		}

		&.circle3 {
			left: 77%;
			top: 35%;
		}

		&.circle4 {
			overflow: hidden;
			left: 55%;
			top: 69%;
		}

		&.circle5 {
			left: 10%;
			top: 55%;
		}
	}
}

.lightCircle {
	position: absolute;
	width: 5px;
	height: 5px;
	border-radius: 200%;
	background-color: #01abf9;
	box-shadow: 0 0 10px 8px #01abf9;
}

.lightCircle2 {
	display: none\0;
	position: absolute;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background-color: #01abf9;
	box-shadow: 0 0 20px 10px #01abf9;
	&.lightCircle20 {
		animation: Mylight0 5s infinite forwards;
	}
	&.lightCircle21 {
		animation: Mylight1 5s infinite forwards;
	}
	&.lightCircle22 {
		animation: Mylight2 5s infinite forwards;
	}
	&.lightCircle23 {
		animation: Mylight3 5s infinite forwards;
	}
	&.lightCircle24 {
		animation: Mylight4 5s infinite forwards;
	}
}
</style>

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

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

相关文章

makefile与gdb的使用

✨前言✨ &#x1f4d8; 博客主页&#xff1a;to Keep博客主页 &#x1f646;欢迎关注&#xff0c;&#x1f44d;点赞&#xff0c;&#x1f4dd;留言评论 ⏳首发时间&#xff1a;2024年10月11日 &#x1f4e8; 博主码云地址&#xff1a;渣渣C &#x1f4d5;参考书籍&#xff1a…

vue 解决高德地图Uncaught Error: Invalid Object: Pixel(NaN, NaN)

有点啰嗦&#xff0c;可以直接跳到最后看解决方法。 问题排查过程 原因起始于一个新需求&#xff1a;在编辑列表信息时需要修改设备位置。 按照文档一番操作&#xff0c;发现完美需求解决了。后续测试的时候就发现浏览器报错Uncaught Error: Invalid Object: Pixel(NaN, NaN)…

在 Notebook 中启动 FastAPI

如何在 Notebook 使用 FastAPI 对外提供 RestAPI&#xff0c;当我们测试完模型时&#xff0c;有事需要对外提供 API 进行测试。FastAPI 是 Python 中快速提供 Rest API 的框架&#xff0c;本文将对外实现一个 OCR 的图片转文字的服务。 OCR 服务 本文使用 GOT OCR 提供 OCR 识…

[Git] Git下载及使用 从入门到精通 详解(附下载链接)

前言 目录 Git概述 简介 下载 Git代码托管服务 Git常用命令 Git全局配置 获取Git仓库 在本地初始化一个Git仓库 从远程仓库克隆 基本概念 工作区文件状态 本地仓库操作 远程仓库操作 分支操作 标签操作 在IDEA中使用Git 在IDEA中配置Git 本地仓库操作 远程仓…

【unity框架开发7】对象池的使用,如何封装一个对象池管理器

文章目录 什么是对象池&#xff1f;对象池有什么用&#xff1f;对象池的原理对象池的实现1、从对象池获取对象2、回收对象3、回收所有对象4、预先往这个对象池中加载指定数量的游戏对象5、最终代码 封装对象池管理器1、对象池管理器代码2、测试调用3、生成和回收游戏对象时自动…

LLM基础常见面试题

#############【持续更新】############## LLM基础常见面试题 简单介绍一下大语言模型【LLMs】&#xff1f; 大模型&#xff1a;一般指1亿以上参数的模型&#xff0c;但是这个标准一直在升级&#xff0c;目前万亿参数以上的模型也有了。大语言模型&#xff08;Large Languag…

在 Windows 11 安卓子系统中安装 APK 的操作指南

这个软件好像不可以在纯android系统中使用&#xff08;不知道是缺了什么&#xff09;&#xff0c;其他对于android的虚拟机要不缺少必要功能组件&#xff0c;要不性能过于低下。本方法致力于在带有谷歌框架WSA中运行该APK 在 Windows 11 安卓子系统中安装 APK 的操作指南 本指…

渗透测试系列之靶机渗透

Helpline是一个困难的靶机&#xff0c;知识点涉及EFS解密和ME SDP的多个漏洞&#xff0c;包括XXE漏洞、LFI\任意文件下载漏洞、身份认证绕过漏洞以及远程代码执行漏洞等. 通关思维导图 0x01 侦查 端口探测 首先使用nmap进行端口扫描 nmap -Pn -p- -sV -sC -A 10.10.10.13…

Obsidian复制代码块代码正确方式

最近在用obsidain做笔记&#xff0c;整体使用下来感觉不错&#xff0c;尤其是强大的检索功能&#xff0c;但是刚才使用其内置的复制代码块功能时&#xff0c;却被恶心到了。 现有背景是&#xff1a;我有一个pydantic的 code block&#xff0c;编辑器处于编辑模式如下&#xff…

Visual Studio的实用调试技巧总结

对于很多学习编程的老铁们来说&#xff0c;是不是也像下面这张图一样写代码呢&#xff1f; 那当我们这样编写代码的时候遇到了问题&#xff1f;大家又是怎么排查问题的呢&#xff1f;是不是也像下面这张图一样&#xff0c;毫无目的的一遍遍尝试呢&#xff1f; 这篇文章我就以 V…

【C语言】深入理解指针(二)(上)

本篇博客将讲解的知识&#xff1a; &#xff08;1&#xff09;指针的使用和传址调用 &#xff08;2&#xff09;数组名的理解 1、指针的使用和传址调用 &#xff08;1&#xff09;strlen 的模拟实现 库函数strlen的功能是求字符串的长度&#xff0c;统计的是字符串中‘\0’之…

onnx代码解读

一、定义 torch.jit.trace 相关代码解读onnx 内部实现 3 查看是否为aten 算子aten 算子实现torch.autograd.Functions 算子实现自定义算子实现查找未实现的节点一次性发现所有的未实现 aten 算子 二、实现 torch.jit.trace 相关代码解读 1. torch.jit.script() : 将其转换为…

数据库的基本概念、安装MySQL及基础运用

目录 一、数据库的基本概念 1. 使用数据库的必要性 2. 数据&#xff08;Data&#xff09; 3. 表 4. 数据库 5. 数据库管理系统&#xff08;DBMS&#xff09; 6. 数据库管理系统DBMS的优点 7. 使用数据库的必要性总结 8. 访问数据库的流程 二、数据库发展及基本功能 1.…

宠物空气净化器怎么选?希喂、霍尼韦尔、美的宠物哪款除毛好?

身为养宠五年的资深铲屎官&#xff0c;最近收到了很多新手养宠朋友关于宠物空气净化器的挑选疑问。宠物空气净化器作为宠物领域目前最火热的产品&#xff0c;谈论度一直很高&#xff0c;评价也褒贬不一。双十一购物节又即将到来&#xff0c;大家都想赶上这一波优惠活动。 铺天盖…

Automa插件之js脚本小技巧:零依赖的日期时间格式化,亲测好用!

背景 在使用 Automa 插件自动下载文件时,有时候需要根据当前时间重新命名文件,如果是时间戳的话倒是也可以防重复文件命名,只不过那样的话,没有了时间可读性. 所以需要日期时间格式化,分享一个一直在用的纯 js 格式化日期脚本,可实现简单的日期格式化. 文末附完整代码,直接复制…

时序约束进阶四:set_input_delay和set_output_delay详解

目录 一、前言 二、set_input_delay/set_output_delay 2.1 延时约束 2.2 约束设置界面 2.3 示例工程 2.4 Delay Value 2.5 Delay value is relative to clock edge 2.6 Delay value already includes latencies of the specified clock edge 2.7 Rise/Fall 2.8 Max/M…

教育部白名单赛事到底是什么?大家为什么那么重视它?

近年来&#xff0c;随着素质教育的推广和升学竞争的加剧&#xff0c;白名单赛事这一概念变得越来越热门。所谓的白名单赛事&#xff0c;是指经过教育部批准并公布的竞赛名单。这些比赛不仅具备权威性和高含金量&#xff0c;还受到各大中小学、重点高中和高校的广泛认可。在升学…

文件句柄泄漏排查及方法总结

如果只是怀疑文件句柄泄漏&#xff0c;可以通过Process Explorer 找到对应进程&#xff0c;双击点开查看performance中的handles变化即可&#xff0c;然后结合I/O项变化进行大致分析。 ——当然对于程序员而言&#xff0c;不光是要发现问题&#xff0c;还要定位问题。 针对li…

Qt 自绘开关按钮以及设计器中的提升为用法

文章目录 自绘按钮实现概要效果图代码 提升为用法介绍步骤 总结 自绘按钮实现 概要 当我们需要一个开关样式的QPushbutton&#xff0c;没有图片的话&#xff0c;我们可以采用自绘的形式实现。且使用QtDesinger中提升为Promote to的功能加入界面中&#xff0c;而不是使用代码的…

C++入门基础知识107—【关于C++continue 语句】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C continue 语句的相关内容&#xff01;…