JS-圆,椭圆等轨迹相关算法

公式
(x0, y0) 圆心坐标
r:半径
x = x0 + cos(angle) * r
y = y0 + sin(angle) * r

1、轨迹
    <div id="div" style="position:relative; width: 20px; height: 20px; background: cadetblue;"></div>
    <script>
        /**
         * 圆心 (x0, y0)
         * 坐标
         * x1 = x0 + cos(angle * Math.PI / 180) * r
         * y1 = y0 + sin(angle * Math.PI / 180) * r
        */
        const div = document.querySelector('#div');
        const x0 = 300;
        const y0 = 400;
        const r = 100;
        
        let angle = 0;

        let x = x0 + Math.cos(angle) * r;
        let y = y0 + Math.sin(angle) * r;

        div.style.top = `${y}px`;
        div.style.left = `${x}px`;

        setInterval(() => {
            angle += 1;
            x = x0 + Math.cos(angle * Math.PI / 180) * r;
            y = y0 + Math.sin(angle * Math.PI / 180) * r;
            div.style.top = `${y}px`;
            div.style.left = `${x}px`;
        }, 10);
    </script>
2、轨迹分布
<style>
    body {
        margin: 0;
        padding: 0;
        height: 100vh;
    }
    .item {
        position: absolute;
        width: 20px;
        height: 20px;
    }
</style>
 <div style="position: relative;display: flex;justify-content: center;height: 100%; align-items: center;">
        <div class="item" style="background-color: red;"></div>
        <div class="item" style="background-color: rgb(255, 170, 0);"></div>
        <div class="item" style="background-color: rgb(0, 157, 255);"></div>
        <div class="item" style="background-color: rgb(0, 81, 255);"></div>
        <div class="item" style="background-color: rgb(0, 255, 115);"></div>
        <div class="item" style="background-color: rgb(187, 255, 0);"></div>
        <div class="item" style="background-color: red;"></div>
        <div class="item" style="background-color: rgb(255, 170, 0);"></div>
        <div class="item" style="background-color: rgb(0, 157, 255);"></div>
        <div class="item" style="background-color: rgb(0, 81, 255);"></div>
        <div class="item" style="background-color: rgb(0, 255, 115);"></div>
        <div class="item" style="background-color: rgb(187, 255, 0);"></div>
    </div>
    <script>
        /**
         * 圆心 (x0, y0)
         * 坐标
         * x1 = x0 + cos(angle * Math.PI / 180) * r
         * y1 = y0 + sin(angle * Math.PI / 180) * r
        */
        const div = document.querySelectorAll('.item');
        const amount = div.length;
        const x0 = 300;
        const y0 = 400;
        const r = 100;
        const single = 360 / amount;
        
        for (let i = 0; i < amount; i++) {
            const x = x0 + Math.cos(single * i * Math.PI / 180) * r - 10;
            const y = y0 + Math.sin(single * i * Math.PI / 180) * r - 10;
            div[i].style.left = `${x}px`;
            div[i].style.top = `${y}px`;
        }
    </script>
3、圆形旋转样例
// 以下代码只适用于节点为偶数个
<style>
    body {
        margin: 0;
        padding: 0;
        height: 100vh;
    }

    .item {
        position: absolute;
        width: 20px;
        font-size: 22px;
        color: rgb(45, 234, 105);
        text-align: center;
    }

    .content {
        position: absolute;
        width: 100px;
        height: 100px;
        background-color: antiquewhite;
        top: 350px;
        left: 250px;
        text-align: center;
        line-height: 100px;
        border-radius: 50%;
        font-size: 30px;
        color: aqua;
    }
</style>

<body>
    <div style="position: relative;display: flex;justify-content: center;height: 100%; align-items: center;">
        <div class="content" id="content"></div>
        <div id="item0" class="item" data-id="item-0">
            <div id="item-0" style="background-color: red;"></div>
            0
        </div>
        <div id="item1" class="item" data-id="item-1">
            <div id="item-1" style="background-color: rgb(255, 170, 0);"></div>
            1
        </div>
        <div id="item2" class="item" data-id="item-2">
            <div id="item-2" style="background-color: rgb(0, 157, 255);"></div>
            2
        </div>
        <div id="item3" class="item" data-id="item-3">
            <div id="item-3" style="background-color: rgb(0, 81, 255);"></div>
            3
        </div>
        <div id="item4" class="item" data-id="item-4">
            <div id="item-4" style="background-color: rgb(0, 255, 115);"></div>
            4
        </div>
        <div id="item5" class="item" data-id="item-5">
            <div id="item-5" style="background-color: rgb(187, 255, 0);"></div>
            5
        </div>
        <div id="item6" class="item" data-id="item-6">
            <div id="item-6" style="background-color: red;"></div>
            6
        </div>
        <div id="item7" class="item" data-id="item-7">
            <div id="item-7" style="background-color: rgb(255, 170, 0);"></div>
            7
        </div>
        <div id="item8" class="item" data-id="item-8">
            <div id="item-8" style="background-color: rgb(0, 157, 255);"></div>
            8
        </div>
        <div id="item9" class="item" data-id="item-9">
            <div id="item-9" style="background-color: rgb(0, 81, 255);"></div>
            9
        </div>
        <div id="item10" class="item" data-id="item-10">
            <div id="item-10" style="background-color: rgb(0, 255, 115);"></div>
            10
        </div>
        <div id="item11" class="item" data-id="item-11">
            <div id="item-11" style="background-color: rgb(187, 255, 0);"></div>
            11
        </div>

    </div>
    <script>
          /**
         * 圆心 (x0, y0)
         * 坐标
         * x1 = x0 + cos(angle) * r
         * y1 = y0 + sin(angle) * r
        */
        const div = document.querySelectorAll('.item');
        const amount = div.length;
        /**
         * 圆心坐标
         * 半径
         * @type {number}
         */
        const x0 = 300;
        const y0 = 400;
        const r = 200;
        // 旋转角度
        const single = 360 / amount;
        // 中间显示内容判断
        let judgeXY = 0;
        let fontSizeList = [];

        function init() {
            for (let i = 0; i < amount; i++) {
                const ele = div[i];
                const angle = single * i * Math.PI / 180;
                const {x, y, sin} = getLocalInfo(i, angle);
                const fontSize = 22 + sin * 10;
                fontSizeList.push({
                    i,
                    fontSize
                });

                changeDom(ele, sin, angle, x, y, fontSize);
            }
            // 判断是否为最前面的元素
            fontSizeList.sort((a, b) => b.fontSize - a.fontSize);
            const {i, fontSize} = fontSizeList[0];
            document.querySelector('#content').innerText = div[i].innerText;
            judgeXY = fontSize;
        }
		// 循环方法
        function loop() {
            for (let i = 0; i < amount; i++) {
                const ele = div[i];
                const oldAngle = +ele.getAttribute('angle');
                const angle = single * Math.PI / 180;
                const newAngle = oldAngle - angle;
                const {x, y, sin} = getLocalInfo(i, newAngle);
                const fontSize = 22 + sin * 10;
                // 处理元素
                changeDom(ele, sin, newAngle, x, y, fontSize);
                // 控制显示信息
                if (fontSize === judgeXY) {
                    document.querySelector('#content').innerText = ele.innerText;
                }
            }
        }

        /**
         * 获取坐标和缩放比
         * */
        function getLocalInfo(i, angle) {
            // 调整第一个元素在正下方 多余加90度
            const rotate = angle + Math.PI / 2;
            const x = x0 + Math.cos(rotate) * r - 10;
            const y = y0 + Math.sin(rotate) * r - 10;
            // 近大远小去处理
            const sin = +Math.sin(rotate).toFixed(3);
            return {
                x,
                y,
                sin
            }
        }

        /**
         * 这里应该通过 transform: scale() 来控制元素大小
         */
        function changeDom(ele, sin, newAngle, x, y, fontSize) {
            const id = ele.dataset.id;
            // 父元素
            ele.style.fontSize = `${fontSize}px`;
            ele.setAttribute('angle', newAngle);
            ele.style.left = `${x}px`;
            ele.style.top = `${y}px`;
            // 子元素
            const contentDom = document.querySelector(`#${id}`);
            contentDom.style.width = `${20 + sin * 10}px`;
            contentDom.style.height = `${20 + sin * 10}px`;
            contentDom.style.margin = `0 auto`
        }

        init();

        setInterval(loop, 2000);

    </script>
</body>

在这里插入图片描述

椭圆

由圆轨迹公式可得出
	x = x0 + Math.cos(angle) * rx;
	y = y0 + Math.sin(angle) * ry;
	rx、ry分别为x轴上的焦半径,y轴的焦半径
// 以下代码只适用于节点为偶数个
 body {
        margin: 0;
        padding: 0;
        height: 100vh;
    }

    .item {
        position: absolute;
        width: 20px;
        font-size: 22px;
        color: rgb(45, 234, 105);
        text-align: center;
    }

    .content {
        position: absolute;
        width: 100px;
        height: 100px;
        background-color: antiquewhite;
        top: 350px;
        left: 550px;
        text-align: center;
        line-height: 100px;
        border-radius: 50%;
        font-size: 30px;
        color: aqua;
    }
</style>

<body>
    <div style="position: relative;display: flex;justify-content: center;height: 100%; align-items: center;">
        <div class="content" id="content"></div>
        <div id="item0" class="item" data-id="item-0">
            <div id="item-0" style="background-color: red;"></div>
            0
        </div>
        <div id="item1" class="item" data-id="item-1">
            <div id="item-1" style="background-color: rgb(255, 170, 0);"></div>
            1
        </div>
        <div id="item2" class="item" data-id="item-2">
            <div id="item-2" style="background-color: rgb(0, 157, 255);"></div>
            2
        </div>
        <div id="item3" class="item" data-id="item-3">
            <div id="item-3" style="background-color: rgb(0, 81, 255);"></div>
            3
        </div>
        <div id="item4" class="item" data-id="item-4" onclick="clickNode(this)">
            <div id="item-4" style="background-color: rgb(0, 255, 115);"></div>
            4
        </div>
        <div id="item5" class="item" data-id="item-5">
            <div id="item-5" style="background-color: rgb(187, 255, 0);"></div>
            5
        </div>
        <div id="item6" class="item" data-id="item-6">
            <div id="item-6" style="background-color: red;"></div>
            6
        </div>
        <div id="item7" class="item" data-id="item-7">
            <div id="item-7" style="background-color: rgb(255, 170, 0);"></div>
            7
        </div>
        <div id="item8" class="item" data-id="item-8">
            <div id="item-8" style="background-color: rgb(0, 157, 255);"></div>
            8
        </div>
        <div id="item9" class="item" data-id="item-9">
            <div id="item-9" style="background-color: rgb(0, 81, 255);"></div>
            9
        </div>
        <div id="item10" class="item" data-id="item-10">
            <div id="item-10" style="background-color: rgb(0, 255, 115);"></div>
            10
        </div>
        <div id="item11" class="item" data-id="item-11">
            <div id="item-11" style="background-color: rgb(187, 255, 0);"></div>
            11
        </div>

    </div>
    <script>
       /**
     * 椭圆中心点 (x0, y0)
     * 坐标
     * x1 = x0 + cos(angle) * rx
     * y1 = y0 + sin(angle) * ry
     */
    const div = document.querySelectorAll('.item');
    const amount = div.length;
    /**
     * 椭圆中心点坐标
     * 半径
     * @type {number}
     */
    const x0 = 600;
    const y0 = 400;
    const rx = 400;
    const ry = 200;

    // 旋转角度
    const single = 360 / amount;
    // 中间显示内容判断
    let judgeXY = 0;
    let fontSizeList = [];

    function init() {
        for (let i = 0; i < amount; i++) {
            const ele = div[i];
            const angle = single * i * Math.PI / 180;
            const {x, y, sin} = getLocalInfo(i, angle);
            const fontSize = 22 + sin * 10;
            fontSizeList.push({
                i,
                fontSize
            });

            changeDom(ele, sin, angle, x, y, fontSize);
        }
        // 判断是否为最前面的元素
        fontSizeList.sort((a, b) => b.fontSize - a.fontSize);
        const {i, fontSize} = fontSizeList[0];
        document.querySelector('#content').innerText = div[i].innerText;
        judgeXY = fontSize;
    }

    function loop() {
        for (let i = 0; i < amount; i++) {
            const ele = div[i];
            const oldAngle = +ele.getAttribute('angle');
            const angle = single * Math.PI / 180;
            const newAngle = oldAngle - angle;
            const {x, y, sin} = getLocalInfo(i, newAngle);
            const fontSize = 22 + sin * 10;
            // 处理元素
            changeDom(ele, sin, newAngle, x, y, fontSize);
            // 控制显示信息
            if (fontSize === judgeXY) {
                document.querySelector('#content').innerText = ele.innerText;
            }
        }
    }

    /**
     * 获取坐标和缩放比
     * */
    function getLocalInfo(i, angle) {
        // 调整第一个元素在正下方
        const rotate = angle + Math.PI / 2;
        const x = x0 + Math.cos(rotate) * rx - 10;
        const y = y0 + Math.sin(rotate) * ry - 10;
        // 近大远小去处理
        const sin = +Math.sin(rotate).toFixed(3);
        return {
            x,
            y,
            sin
        }
    }

    /**
     * 这里应该通过 transform: scale() 来控制元素大小
     */
    function changeDom(ele, sin, newAngle, x, y, fontSize) {
        const id = ele.dataset.id;
        // 父元素
        ele.style.fontSize = `${fontSize}px`;
        ele.setAttribute('angle', newAngle);
        ele.style.left = `${x}px`;
        ele.style.top = `${y}px`;
        // 子元素
        const contentDom = document.querySelector(`#${id}`);
        contentDom.style.width = `${20 + sin * 10}px`;
        contentDom.style.height = `${20 + sin * 10}px`;
        contentDom.style.margin = `0 auto`
    }

    init();

    setInterval(loop, 2000);

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值