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

前端实现一个绕圆心转动的功能

前言: 今天遇到了一个有意思的需求,如何实现一个元素绕某一个点来进行圆周运动,用到了一些初高中的数学知识,实现起来还是挺有趣的,特来分享🎁。

一. 效果展示

  1. 我们先展示效果,如下图所示,放大镜会绕着我们设定好的一个圆心来进行圆周运动。相信这个需求还是比较常见的,接下来我会一步一步讲解我的实现过程。
    saomiao.gif

  2. tisp: 注意,放大镜是一张 png 的图片,并不是我们手动画出来的

二. 回忆画圆的步骤

  1. 不要着急想代码如何实现,我们先思考如何手动画一个圆?在这里我们很容易想到一个初中学习数学用到的工具----圆规,如下图所示。
    IMB_DQj3Fs.gif

  2. 从上图可以得知,手动画一个圆其实很简单,大致分为三个步骤。

    1. 确定圆心
    2. 确定半径
    3. 旋转圆规
  3. 前两个我们可以很轻松的根据我们的需求设定好,圆心就是确定页面上的一个点坐标而已,半径也是我们手动写死的一个变量值而已,关键点其实就在于第三步我们如何实现。

  4. 在实现第三步之前,我会提前预热一下弧度的知识,因为等会我们需要用到 sincos 的相关知识,而在 js 中的相关三角函数的参数必须为弧度,所以我们需要通过角度来计算得出弧度
    image.png

  5. 我们大家都知道,一个圆有360度,且度数弧度之间有一个转换公式,如下。
    image.png

  6. 得知了转换关系,我们就可以定义一个变量 angle 来表示我们这个 div 做圆周运动时绕圆心转过的角度,则弧度(radian)radian =(angle*π)/180

三. 回忆 sin 和 cos

  1. 我们先在草稿纸上演练一遍我们的逻辑是否可行。让我们先准备一个矩形来代表我们的页面,然后确定一个点来作为圆心
    image.png

  2. 圆心的位置坐标其实很简单,不要想复杂了,就是相对于页面的位置而已,我们记住这个 (100,100) 的值,等会它会作为我们实现圆周运动的圆心位置。
    image.png

  3. 接下来确定半径,这里我就随便取一个 50 作为半径值。

  4. 假设这是我们的 div 已经绕圆心转了一些弧度以后的情景。
    image.png

  5. tips: 在这里有一个十分重要的概念,div 滑过的路径其实是由无数个不同坐标位置的点构成的。
    image.png

  6. 接下来就是本文的关键部分,请大家喝口水认真听讲。我们取一个中间时刻,假设 div 此时做圆周运动到了点 B ,那么我们的问题就转化为了如何求点 B 的坐标信息。(不要忘了,坐标信息其实就是相对于页面上的 left 和 top 而已。)
    image.png

  7. 一步一步来,我们先求 X 坐标的值,换算下来其实就是要求 a 的长度。
    image.png

  8. 此时我们准备好拿出已有的数据,来套公式即可。度数我们是有的,因为我们已经用变量 angle 来假设我们绕过的度数,则弧度radian =(angle*π)/180 ,然后根据三角函数的正弦定理可得 sin(rad)=a/radius

  9. 此时半径已知,sin(rad) 已知,则 a=sin(rad) X 50,然后加上圆心的 x 坐标值 100,即可得出此时 B 点相对于页面的 left 值。

  10. Y 坐标同理,只不过公式换为 cos 即可,换算过程不再重复,但是需要注意的点是,我们计算 Y 坐标 的目的其实在求的是 B 点的 top 值,又因为我们前端的坐标Y轴其实和数学的坐标Y轴的正负极是相反的,所以我们其实要算的值是这一段的距离。如下图:
    image.png

  11. 即 B 点的 top 值为圆心的 Y 坐标值100 - 距离b,至此我们所有需要的数据都已经获得,接下来就是用代码验证我们思路的可行性。

四. 实现圆周运动函数

  1. 经过上面的解释,我们接下来就可以动手写代码了。

  2. 我们先简单设计一个画面,内容很简单,一个普通的蓝底页面中间有一个居中的红色 div,要想脱离文档流自行移动,那么这个 div 肯定是 absolute 绝对定位。
    image.png

  3. 然后提前定义好我们需要用到的变量,为接下来的工作做准备。
    image.png

  4. 因为我们是需要不断通过改变 divX 偏移值和 Y 偏移值来实现圆周运动的,(先不考虑性能和优化)所以很容易想到 setInterval,所以现在你的代码应该是这个样子。

    // 1. 确定圆心的位置
    const centerPointer = { x: 100, y: 100 };
    // 2. 确定圆周运动的半径
    const radius = 50;
    // 3. div 运动时的角度
    let angle = 0;function run() {setInterval(() => {}, 16);
    }
    
  5. 首先我们需要让我们定义好的 angle 自增。

    function run() {setInterval(() => {angle += 1;}, 16);
    }
    
  6. 接下来计算 ab 的值,根据我们上面的出的公式 radian =(angle*π)/180sin(rad)*radius=a,可以写出下面的代码。

    function run() {setInterval(() => {angle += 1;const radian = (angle * Math.PI) / 180;const a = Math.sin(radian) * radius;const b = Math.cos(radian) * radius;}, 16);
    }
    
  7. 根据我们在上面的结论,divtop 值为 半径 + a left 值为 半径 - b,你现在的 run函数 代码应该是这样的。

    
    function run() {setInterval(() => {if (!box.value) return;angle += 1;const radian = (angle * Math.PI) / 180;const a = Math.sin(radian) * radius;const b = Math.cos(radian) * radius;const x = centerPointer.x + a;const y = centerPointer.y - b;box.value.style.left = x + "px";box.value.style.top = y + "px";}, 16);
    }
    
  8. 然后给我们的 div 打上 ref 那到这个 dom 元素。
    image.png

  9. onMounted 里执行我们的 run 函数,接下来就是见证奇迹的时刻。
    yuanzhou.gif

五. 源码

<script setup lang="ts">
import { ref, onMounted,  } from "vue";const box = ref<HTMLDivElement>();
// 1. 确定圆心的位置
const centerPointer = { x: 100, y: 100 };
// 2. 确定圆周运动的半径
const radius = 50;
// 3. div 运动时的角度
let angle = 0;function run() {setInterval(() => {if (!box.value) return;angle += 1;const radian = (angle * Math.PI) / 180;const a = Math.sin(radian) * radius;const b = Math.cos(radian) * radius;const x = centerPointer.x + a;const y = centerPointer.y - b;box.value.style.left = x + "px";box.value.style.top = y + "px";}, 16);
}onMounted(() => {run();
});
</script>
<template><div class="w-full h-full centered bg-blue relative flex flex-col centered"><div ref="box" class="absolute w-50px h-50px bg-red"></div></div>
</template>

六. 思考题

现在我们的 div顺时针运动,我们该如何让它逆时针运动呢?🤔

相关文章:

前端实现一个绕圆心转动的功能

前言&#xff1a; 今天遇到了一个有意思的需求&#xff0c;如何实现一个元素绕某一个点来进行圆周运动&#xff0c;用到了一些初高中的数学知识&#xff0c;实现起来还是挺有趣的&#xff0c;特来分享&#x1f381;。 一. 效果展示 我们先展示效果&#xff0c;如下图所示&…...

【vue.js】文档解读【day 2】 | 响应式基础

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 响应式基础声明响应式状态(属性)响应式代理 vs 原始值声明方法深层响应性DOM 更新时机有状态方法 响应式…...

element-ui radio 组件源码分享

今日简单分享 radio 组件的实现原理&#xff0c;主要从以下三个方面来分享&#xff1a; 1、radio 页面结构 2、radio 组件属性 3、radio 组件方法 一、radio 页面结构 1.1 页面结构如下&#xff1a; 二、radio 属性 2.1 value / v-model 属性&#xff0c;类型为 string / …...

1-安装rabbitmq

rabbitmq官网&#xff1a; https://www.rabbitmq.com/docs/download 本机环境&#xff1a;mac&#xff0c;使用orbstack提供的docker 使用docker部署rabbitmq docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management 然后报错&#xf…...

C/C++编程-理论学习-通信协议理论

通信协议理论 protobuf简述 protobuf 简述 作用&#xff1a; 1. 将结构化数据 序列化 进行信息通信、存储。意为&#xff0c;数据结构化管理&#xff1b;意为&#xff0c;对结构化的数据进行序列化&#xff0c;便于发送、存储。可类比XML、JSON。 弊端&#xff1a; 1. buffe…...

【Apache Camel】基础知识

【Apache Camel】基础知识 Apache Camel是什么Apache Camel基本概念和术语CamelContextEndpointsRoutesRouteBuilderComponentsMessageExchangeProcessorsDomain Specific Language&#xff08;DSL&#xff09; Apache Camel 应用执行步骤Apache Camel 示意图参考 Apache Camel…...

Python之访问集合的迭代器

对迭代器的理解对于我们访问数据量大是有很大的帮助&#xff0c;将介绍它。 一、概念 迭代&#xff1a;是访问集合元素的一种方式&#xff0c;按照某种顺序逐个访问集合中的每一项。 可迭代对象&#xff1a;能够被迭代的对象&#xff0c;称为可迭代对象 判定依据&#xff1a;能…...

【Spring连载】使用Spring Data访问 MongoDB----对象映射之基于类型的转换器

【Spring连载】使用Spring Data访问 MongoDB----对象映射之基于类型的转换器 一、自定义转换二、转换器消歧(Disambiguation)三、基于类型的转换器3.1 写转换3.2 读转换3.3 注册转换器 一、自定义转换 下面的Spring Converter实现示例将String对象转换为自定义Email值对象: R…...

在ubuntu上安装hadoop完分布式

准备工作 Xshell安装包 Xftp7安装包 虚拟机安装包 Ubuntu镜像源文件 Hadoop包 Java包 一、安装虚拟机 创建ubuntu系统 完成之后会弹出一个新的窗口 跑完之后会重启一下 按住首先用ctrlaltf3进入命令界面&#xff0c;输入root&#xff0c;密码登录管理员账号 按Esc 然后输入 …...

Python 语句(二)【循环语句】

循环语句允许执行一个语句或语句组多次&#xff0c;其程序流程图如下&#xff1a; 在python中有三种循环方式&#xff1a; while 循环 当判断条件为 true 时执行循环体&#xff0c;否则退出循环体。for 循环 重复执行语句嵌套循环 &#xff08;在while循环体中嵌套for循环&…...

(3)(3.3) MAVLink高延迟协议

文章目录 前言 1 配置 2 说明 3 消息说明 前言 ArduPilot 支持 MAVLink 高延迟协议(MAVLink High Latency)。该协议专为卫星或 LoRA 等低带宽或高成本链路而设计。 在此协议中&#xff0c;每 5s 只发送一次 HIGH_LATENCY2 MAVLink 信息。对 MAVLink 命令或请求&#xff08…...

【异常处理】Vue报错 Component template should contain exactly one root element.

问题描述 启动VUE项目后控制台报错&#xff1a; Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.翻译为&#xff1a;组件模板应该只包含一个根元素 查看vue代码&#xff0…...

Eth-trunk隧道

目录 Eth-trunk (划为二层) 二层trunk 三层交换机 网关冗余 Eth-trunk (划为二层) 一,...

【Ubuntu】将多个python文件打包为.so文件

1.为什么要将python打包为.so文件&#xff1f; 保护源码 2.实战例子 a.安装相应的包 pip install cython 验证安装是否成功 cython --version b.实战的文件目录和内容 hi.py # This is a sample Python script.# Press ShiftF10 to execute it or replace it with your…...

FreeRtos自学笔记3-----参考正点原子视频

FreeRtos任务的创建与删除 任务的创建与删除本质上是调用FreeRtos的API函数。 API函数&#xff1a; 1.xTaskGreate():动态创建任务函数&#xff1b; 2.xTaskGreateStatic();静态创建任务函数&#xff1b; 3.xTaskDelete():任务删除 动态创建任务&#xff1a;任务的任务控制块以…...

使用J-Link Commander通过J-LINK以命令的形式来访问ARM通用MCU

通常我们的操作是写好程序然后将程序下载到芯片里面&#xff0c;然后运行程序来进行相应的操作&#xff0c;其实还可以使用 J − L i n k C o m m a n d e r J-Link\quad Commander J−LinkCommander通过 J − L I N K J-LINK J−LINK以命令的形式来简单访问ARM通用MCU&#xf…...

19.删除链表的倒数第N个节点

19.删除链表的倒数第N个节点 力扣题目链接(opens new window) 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 进阶&#xff1a;你能尝试使用一趟扫描实现吗&#xff1f; 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n…...

【Linux C | 网络编程】广播概念、UDP实现广播的C语言例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

java 面向对象 day3

这里写目录标题 1、 内部类1.1 成员内部类 静态内部类1.2 局部内部类1.3 匿名内部类[重点] 2、枚举2.1 使用枚举类 设计单例模式2.2 小实例 3、泛型3.1 认识泛型3.2 泛型类3.3 泛型接口3.4 泛型方法3.5 注意事项 1、 内部类 内部类 就是定义在一个类中的类 1.1 成员内部类 静…...

Flink 大数据 学习详情

参考视频&#xff1a; 尚硅谷大数据Flink1.17实战教程从入门到精通_哔哩哔哩_bilibili 核心目标&#xff1a; 数据流上的有状态的计算 具体说明&#xff1a; Apache Flink是一个 框架 和 分布式处理引擎&#xff0c;用于对 无界&#xff08;eg&#xff1a;kafka&#xff09; 和…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...

规则与人性的天平——由高考迟到事件引发的思考

当那位身着校服的考生在考场关闭1分钟后狂奔而至&#xff0c;他涨红的脸上写满绝望。铁门内秒针划过的弧度&#xff0c;成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定"&#xff0c;构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...

WEB3全栈开发——面试专业技能点P4数据库

一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库&#xff0c;基于 mysql 库改进而来&#xff0c;具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点&#xff1a; 支持 Promise / async-await&#xf…...

表单设计器拖拽对象时添加属性

背景&#xff1a;因为项目需要。自写设计器。遇到的坑在此记录 使用的拖拽组件时vuedraggable。下面放上局部示例截图。 坑1。draggable标签在拖拽时可以获取到被拖拽的对象属性定义 要使用 :clone, 而不是clone。我想应该是因为draggable标签比较特。另外在使用**:clone时要将…...

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)

漏洞概述 漏洞名称&#xff1a;Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号&#xff1a;CVE-2023-25194 CVSS评分&#xff1a;8.8 影响版本&#xff1a;Apache Kafka 2.3.0 - 3.3.2 修复版本&#xff1a;≥ 3.4.0 漏洞类型&#xff1a;反序列化导致的远程代…...

RabbitMQ 各类交换机

为什么要用交换机&#xff1f; 交换机用来路由消息。如果直发队列&#xff0c;这个消息就被处理消失了&#xff0c;那别的队列也需要这个消息怎么办&#xff1f;那就要用到交换机 交换机类型 1&#xff0c;fanout&#xff1a;广播 特点 广播所有消息​​&#xff1a;将消息…...

21-Oracle 23 ai-Automatic SQL Plan Management(SPM)

小伙伴们&#xff0c;有没有迁移数据库完毕后或是突然某一天在同一个实例上同样的SQL&#xff0c; 性能不一样了、业务反馈卡顿、业务超时等各种匪夷所思的现状。 于是SPM定位开始&#xff0c;OCM考试中SPM必考。 其他的AWR、ASH、SQLHC、SQLT、SQL profile等换作下一个话题…...

【Zephyr 系列 16】构建 BLE + LoRa 协同通信系统:网关转发与混合调度实战

🧠关键词:Zephyr、BLE、LoRa、混合通信、事件驱动、网关中继、低功耗调度 📌面向读者:希望将 BLE 和 LoRa 结合应用于资产追踪、环境监测、远程数据采集等场景的开发者 📊篇幅预计:5300+ 字 🧭 背景与需求 在许多 IoT 项目中,单一通信方式往往难以兼顾近场数据采集…...