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

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

一. 效果展示

  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顺时针运动,我们该如何让它逆时针运动呢?🤔

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【NR 定位】3GPP NR Positioning 5G定位标准解读(六)

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

JavaScript基础Ⅱ

目录 第2章 JavaScript基础语法(掌握) 11-JS代码调试 12-JS函数 第3章 JS事件 14-事件的绑定方式 常用事件(了解) 15-常用事件 第4章 JS内置对象(掌握) 16-数组 17-日期 18-数学运算 19-数字 20-全局函数 第2章 JavaScript基础语法(掌握) 11-JS代码调试 12-JS函数…

青少年如何从零开始学习Python编程?有它就够了!

文章目录 写在前面青少年为什么要学习编程 推荐图书图书特色内容简介 推荐理由粉丝福利写在最后 写在前面 本期博主给大家带来一本非常适合青少年学习编程的图书&#xff0c;快来看看吧~ 青少年为什么要学习编程 青少年学习编程&#xff0c;就好比在他们年轻时就开始掌握一种…

基于单片机的医院输液系统设计

目 录 摘 要 Ⅰ Abstract Ⅱ 引 言 1 1系统方案设计与论证 3 1.1系统硬件结构总体设计方案 3 1.2点滴速度测量电路方案的选择与论证 3 1.3液面检测电路方案的选择与论证 4 1.4通过电机控制滴速电路的方案与论证 4 1.5显示器接口电路方案选择与论证 5 1.6键盘接口电路方案选择与…

1.2_3 TCP/IP参考模型

文章目录 1.2_3 TCP/IP参考模型&#xff08;一&#xff09;OSI参考模型与TCP/IP参考模型&#xff08;二&#xff09;5层参考模型&#xff08;三&#xff09;5层参考模型的数据封装与解封装 1.2_3 TCP/IP参考模型 &#xff08;一&#xff09;OSI参考模型与TCP/IP参考模型 TCP/I…

Xilinx 7系列 FPGA硬件知识系列(一)——FPGA选型参考

目录 1.1 Xilinx-7系列产品的工艺级别 ​编辑1.2 Xilinx-7系列产品的特点 1.2.1 Spartan-7系列 1.2.2 Artix-7系列 1.2.3 Kintex-7系列 1.2.4 Virtex-7系列 1.3 Xilinx-7系列FPGA对比 1.3.1 DSP资源柱状图 ​1.3.2 Block RAM资源柱状图 ​1.3.3 高速串行收…

Neoverse CSS N3:实现市场领先能效的最快途径

区分老的架构 从云到边缘&#xff0c;Arm Neoverse 提供无与伦比的性能、效率、设计灵活性和 TCO 优势&#xff0c;正在颠覆传统基础设施芯片。 我们看到云和超大规模服务运营商正在推动更高的计算密度。随着 128 核心 CPU 设计上市&#xff08;Microsoft Cobalt、阿里巴巴 Y…

搭建Zabbix监控系统

概述 Zabbix是一个基于Web界面的企业级开源监控套件&#xff0c;提供分布式系统监控与网络监视功能。具 备主机的性能监控&#xff0c;网络设备性能监控&#xff0c;数据库性能监控&#xff0c;多种告警方式&#xff0c;详细报表、图表的绘制等 功能。监测的对象可以是Linux或 …

PB-03F 模组烧录流程

文章目录 前言一、准备1. 器材2. 软件&#xff08;1&#xff09;点击下面链接下载固件烧录工具&#xff08;2&#xff09;点击下面链接下载固件包&#xff08;3&#xff09;解压文件 二、烧录1. 打开PhyPlusKit...软件2. 选择串口及波特率并打开串口3. 选择文件并输入MAC地址4.…

【Flink网络数据传输(3)】RecordWriter的能力:实现数据分发策略或广播到下游InputChannel

文章目录 一.创建RecordWriter实例都做了啥1. 根据recordWrites数量创建不同的代理类2. 创建RecordWriters3. 单个RecordWriter的创建细节 二. RecordWriter包含的主要组件1. RecordWriter两种实现类分别实现分发策略和广播2. ChannelSelectorRecordWriter的发送策略2.1. Chann…

Qwen-Agent自定义Tool

qwen-agent项目部署 1、下载qwen-agent https://github.com/QwenLM/Qwen-Agent2、安装依赖环境 pip3 install -r requirements.txt自定义Tool cd qwen_agent/tools参考其他的工具&#xff0c;我这里创建了一个查询手机号归属地的工具get_mobile_address.py&#xff1a; im…

php常见的45个漏洞及解决方案

[TOC]&#xff08;太多了&#xff0c;目录只列出最重要的几个&#xff0c;剩下的同学们自己翻&#xff09; PHP作为一种广泛应用的服务器端脚本语言&#xff0c;在历史上曾曝出过多种安全漏洞。以下是一些PHP漏洞的类别及其简要解释&#xff0c;以及如何解决这些问题&#xff1…

vue3引入字体

一、首先挑选字体 推荐个网站&#xff1a; DaFont - Download fonts 这个网站里面有很多字体供我们下载。点击圈起来的地方可以选择不同的字体样式预览。 英文不好就翻译一下吧&#xff08;狗头&#xff09;。 二、使用 比如我点击LCD类型的&#xff0c;数码类型的。 点击输…

视频剪辑如何提取伴奏?短视频剪辑有妙方

在多媒体处理中&#xff0c;音频的编辑和处理是不可或缺的一部分。很多时候&#xff0c;我们可能想要从一段视频或音频中提取伴奏&#xff0c;或者实现人声的分离&#xff0c;以便于进一步制作或混音。以下&#xff0c;将为您介绍一种简单而有效的方法来实现这一目标。 一、提取…

Docker部署ruoyi前后端分离项目

目录 一. 介绍前后端项目 二. 搭建局域网 2.1 创建网络 2.2 注意点 三. Redis 3.1 安装 3.2 配置redis.conf文件 3.3 测试 四. 安装MySQL 4.1 安装 4.2 配置my2.cnf文件 4.3 充许远程连接 五. 若依部署后端服务 5.1 数据导入 5.2 使用Dockerfile自定义镜像 5.3 运行…

MySQL-视图:视图概述、使用视图注意点、视图是否影响基本表

视图 一、视图概述二、使用视图注意点三、视图操作是否影响基本表 一、视图概述 在数据库管理系统中&#xff0c;视图&#xff08;View&#xff09;是一种虚拟表&#xff0c;它并不实际存储数据&#xff0c;而是基于一个或多个实际表的查询结果。视图提供了一种对数据库中数据…

VUE——v-cloak指令

VUE——v-cloak指令 属性选择器&#xff0c;可以控制vue实例化完成前的dom样式 功能&#xff1a;利用vue实例化后v-cloak属性会消失&#xff0c;设置其样式 官网介绍 没用前效果&#xff1a;当vue没渲染完前&#xff0c;界面效果会看到{{aboutCloak}}字符&#xff0c;影响用户…

腾讯云99元一年服务器,真香购买链接来了

腾讯云服务器99元一年是真的吗&#xff1f;真的&#xff0c;只是又降价了&#xff0c;现在只要61元一年&#xff0c;配置为2核2G3M轻量应用服务器&#xff0c;40GB SSD盘&#xff0c;腾讯云百科txybk.com分享腾讯云官方活动购买链接 https://curl.qcloud.com/oRMoSucP 活动打开…

kafka进阶(二)

文章目录 前言一、Ack机制二、ISR集合总结 前言 本篇主要介绍kafka 的 Ack机制 和 ISR集合 一、Ack机制 Kafka提供了三种不同的应答机制&#xff08;ACK&#xff09;&#xff1a; acks0&#xff1a;这是最不可靠的模式。在这种模式下&#xff0c;生产者不会等待来自服务器的…

linux 安装OpenRestry

一、OpenRestry官网 openRestry中文官网 openRestry英文官网 二、OpenRestry搭建 可以参考官方提供的网址进行搭建&#xff1a;OpenRestry安装官网 ​ 三、开始安装 1、安装依赖库 yum install libtermcap-devel ncurses-devel libevent-devel readline-devel pcre-deve…