CSS 实现任意角度圆环

参考链接: css 制作圆环 - 掘金

主要思路: 利用 CSS 的 clip-path 属性进行裁剪 

clip-path 具体信息参考 polygon() - MDN (mozilla.org) 

该属性原理是:利用多边形进行对图形的裁剪。

根据具体代码,去分析

clip-path: polygon(50% 0%, 100% 50%,50% 100%,0% 50%);

 根据代码,我们可以得到4组数据,分别是:【黄色部分为 X 轴,绿色部分为Y轴】

  1.  50% 0%
  2.  100% 50% 
  3.  50% 100%
  4.  0% 50%

 提示: polygon 括号里面有 N 组数据,多边形就有 N 个顶点

这样我们就可以得到一个菱形

 根据这个原理,去裁剪圆环,就能得到任意角度的圆环。


正文部分

 先写 JS 部分,去控制百分比【CSS变量】

        function get(angle, flag = true) {

            if (angle <= 45) {
                if (flag) {
                    return ((Math.tan(angle * 2 * Math.PI / 360) * 0.5 + 0.5) * 100).toFixed(2) + "%"
                }
                return ((Math.tan(angle * 2 * Math.PI / 360) * 0.5) * 100).toFixed(2) + "%"
            }

            if (angle <= 135) {
                // 首先将 145 分成2段进行处理
                if (angle <= 90) {
                    // 45 - 90
                    return get(angle - 45, false)
                } else {
                    // 90 - 145  
                    return get(angle - 90)
                }
            }

            if (angle <= 225) {
                // 与 135 同理,也分成 2 段
                if (angle <= 180) {
                    let v1 = get(angle - 135, false)
                    let result = (100 - parseFloat(v1.substring(0, v1.length - 4))).toFixed(2)
                    return result + "%"
                } else {
                    let v2 = get(angle - 180)
                    let result = (100 - parseFloat(v2.substring(0, v2.length - 4))).toFixed(2)
                    return result + "%"
                }
            }

            if (angle <= 315) {
                if (angle <= 225) {
                    let v1 = get(angle - 225, false)
                    let result = (100 - parseFloat(v1.substring(0, v1.length - 4))).toFixed(2)
                    return result + "%"
                } else {
                    let v2 = get(angle - 270)
                    let result = (100 - parseFloat(v2.substring(0, v2.length - 4))).toFixed(2)
                    return result + "%"
                }
            }

            if (angle <= 360) {
                return get(angle - 315, false)
            }

            // 当以上条件都不满足,参数不正确
            throw new Error("参数必须为 0 - 360")
        }

样式部分:【结构部分】

<div class="container">
        <div class="circle cirque360" data-angle="0"></div>
        <div class="rect"></div>
        <div class="backup"></div>
    </div>
:root {
            --cirque-percent: 0;
        }

        .container {
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            width: 500px;
            height: 500px;
            margin: 100px auto;
            background-color: #c5e1a5;
        }

        .rect {
            position: absolute;
            top: calc(50% - 50px);
            left: calc(50% - 50px);
            width: 100px;
            height: 100px;
            background-color: yellow;
            z-index: 0;
        }

        .backup {
            position: absolute;
            top: calc(50% - 50px);
            left: calc(50% - 50px);
            width: 100px;
            height: 100px;
            background-color: green;
            border-radius: 50%;
            z-index: 1;
        }

        .circle {
            width: 100px;
            height: 100px;
            border-radius: 50%;
            background-color: blue;
            border: 10px solid #9c27b0;

            box-sizing: border-box;
            z-index: 2;
        }

        .cirque45 {
            /* 剪切圆环 */
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 0);
        }

        .cirque135 {
            clip-path: polygon(50% 0, 50% 50%, 100% var(--cirque-percent), 100% 0);
        }

        .cirque225 {
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 100%, 100% 100%, 100% 0);
        }

        .cirque315 {
            clip-path: polygon(50% 0, 50% 50%, 0% var(--cirque-percent), 0% 100%, 100% 100%, 100% 0%);
        }

        .cirque360 {
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
        }

重点修改这个

 cirque360 要更改成 cirque45 cirque135 cirque225 cirque360 四种 

比如: cirque45 ,输入角度不能大于45。cirque135,输入角度不能大于135

现在打开浏览器:

控制台改变 CSS 变量

document.documentElement.style.setProperty('--cirque-percent', get(120));

运行结果:

完整代码如下:(可能与上面不同)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        :root {
            --cirque-percent: 50%;
        }

        .container {
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            width: 500px;
            height: 500px;
            margin: 100px auto;
            background-color: #c5e1a5;
        }

        button {
            position: absolute;
            bottom: 25px;
            right: 50px;
            width: 70px;
            height: 45px;
            background-color: #0072f5;
            outline: none;
            border: none;
            border-radius: 10px;
            color: white;
            font-size: 1.2rem;
        }

        button:hover {
            background-color: #73b0f5;
        }

        .circle-track {
            position: relative;
            width: 120px;
            height: 120px;
            border: 30px solid black;
            border-radius: 50%;
            box-sizing: border-box;
        }

        .circle {
            position: absolute;
            top: -20px;
            left: -20px;
            width: 100px;
            height: 100px;
            border-radius: 50%;
            border: 10px solid #9198e5;
            box-sizing: border-box;
        }

        .cirque45 {
            /* 剪切圆环 */
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 0);
        }

        .cirque135 {
            clip-path: polygon(50% 0, 50% 50%, 100% var(--cirque-percent), 100% 0);
        }

        .cirque225 {
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 100%, 100% 100%, 100% 0);
        }

        .cirque315 {
            clip-path: polygon(50% 0, 50% 50%, 0% var(--cirque-percent), 0% 100%, 100% 100%, 100% 0%);
        }

        .cirque360 {
            clip-path: polygon(50% 0, 50% 50%, var(--cirque-percent) 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="circle-track">
            <div class="circle"></div>
        </div>
        <button>+10</button>
    </div>

    <script>
        let count = 0;
        const btn = document.querySelector("button")
        btn.onclick = () => {
            count += 10;
            if (count >= 360) {
                count = 0;
            }
            console.log(count);
            document.documentElement.style.setProperty('--cirque-percent', get(count));
        }

        const cirque = document.querySelector(".circle");

        function get(angle, flag = true) {

            if (angle <= 45) {
                cirque.className = "circle cirque45"
                if (flag) {
                    return ((Math.tan(angle * 2 * Math.PI / 360) * 0.5 + 0.5) * 100).toFixed(2) + "%"
                }
                return ((Math.tan(angle * 2 * Math.PI / 360) * 0.5) * 100).toFixed(2) + "%"
            }

            if (angle <= 135) {
                // 首先将 145 分成2段进行处理
                if (angle <= 90) {
                    let v1 = get(angle - 45, false)
                    cirque.className = "circle cirque135"
                    return v1
                } else {
                    let v1 = get(angle - 90)
                    cirque.className = "circle cirque135"
                    return v1
                }
            }

            if (angle <= 225) {
                // 与 135 同理,也分成 2 段
                if (angle <= 180) {
                    let v1 = get(angle - 135, false)
                    let result = (100 - parseFloat(v1.substring(0, v1.length - 4))).toFixed(2) + "%"
                    cirque.className = "circle cirque225"
                    return result
                } else {
                    let v2 = get(angle - 180)
                    let result = (100 - parseFloat(v2.substring(0, v2.length - 4))).toFixed(2) + "%"
                    cirque.className = "circle cirque225"
                    return result
                }
            }

            if (angle <= 315) {
                if (angle <= 225) {
                    let v1 = get(angle - 225, false)
                    let result = (100 - parseFloat(v1.substring(0, v1.length - 4))).toFixed(2) + "%"
                    cirque.className = "circle cirque315"
                    return result
                } else {
                    let v2 = get(angle - 270)
                    let result = (100 - parseFloat(v2.substring(0, v2.length - 4))).toFixed(2) + "%"
                    cirque.className = "circle cirque315"
                    return result
                }
            }

            if (angle <= 360) {
                let v1 = get(angle - 315, false)
                cirque.className = "circle cirque360"
                return v1
            }

            // 当以上条件都不满足,参数不正确
            throw new Error("参数必须为 0 - 360")
        }


    </script>
</body>

</html>

 

 

posted @ 2023-05-09 18:48  辰梦starDream  阅读(76)  评论(0编辑  收藏  举报  来源