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轴】
- 50% 0%
- 100% 50%
- 50% 100%
- 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>