前言
有需求写一个大转盘的功能
网上搜了一些,一部分没有实现样式,直接用了一个大转盘的UI图片
还有一些是写死了样式
感觉不是很灵活,所以打算自己写一个
今天先实现样式,主要是奖项的旋转角度和扇形的实现,能根据奖项数量自动计算样式,效果如图
思路
有一个外部容器,里面放着若干奖项元素
奖项元素宽度为100%,高度为外部容器的一半,position为absolute,left、top都为0
奖项元素的旋转角度为360度除以奖项数量,旋转基点为底部中间位置
奖项元素为扇形,使用clip-path的path来切割形状为倒三角形,然后外部容器的overflow为hidden,这样就能遮挡倒三角的外围
代码实现
html
<div class="wheel">
<div class="prize">Prize 1</div>
<div class="prize">Prize 2</div>
<div class="prize">Prize 3</div>
<div class="prize">Prize 4</div>
<div class="prize">Prize 5</div>
<div class="prize">Prize 6</div>
<div class="prize">Prize 7</div>
<div class="prize">Prize 8</div>
</div>
上面为外部容器和奖项元素,不做过多介绍
CSS样式
.wheel {
width: 400px;
height: 400px;
position: relative;
background-color: #f39c12;
border-radius: 50%;
overflow: hidden;
}
.prize {
width: 100%;
height: 50%;
position: absolute;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
transform-origin: center bottom;
}
.prize:nth-child(1) { background-color: #3498db; }
.prize:nth-child(2) { background-color: #e74c3c; }
.prize:nth-child(3) { background-color: #2ecc71; }
.prize:nth-child(4) { background-color: #e67e22; }
.prize:nth-child(5) { background-color: #9b59b6; }
.prize:nth-child(6) { background-color: #f1c40f; }
.prize:nth-child(7) { background-color: #1abc9c; }
.prize:nth-child(8) { background-color: #34495e; }
设置外部容器的基本样式,比如尺寸,位置以及溢出隐藏等
设置奖项元素的尺寸,位置,弹性盒子,旋转基点等
JS代码
js代码的主要有2个功能:
计算每个奖项元素的旋转角度
这个比较简单啦,上面也说了360/奖项数量
/**
* @description: 得出奖项旋转角度
* @return {*}
*/
function getRotate(){
// 获取奖项列表
let items = document.querySelectorAll('.prize');
// 得出每个奖项的旋转角度
return jiaodu = 360 / items.length;
}
计算扇形的clip-path的path路径
这个需要用到三角函数求边长的知识,作为初中文化水平的我,也是费了点劲儿才搞定,哈哈
比如一共有5个奖项元素,那么每个奖项元素占据的角度就是72°,青色的角度就是36°,直到矩形高度为200宽度为400,需要求得?的值,知道?的值,就能得出path的三个顶点位置,通过三角函数的tan能得出X的值,?的值就是宽度/2 - X
需要注意的是js中角度需要换算为弧度在再进行使用
弧度 = 角度 * Math.PI / 180
下面直接上代码,多了我也说不清
设直角三角形中C=90°
1、若已知A及对边a,则:c=a/sinA, b=a/tanA;
2、若已知A及临边b,则:c=b/cosA, a=b*tanA.
我也是根据上面的公式算出来
/**
* @description: 根据已知条件计算出clip-path的切割路径
* @param {*} height 矩形的高
* @param {*} width 矩形的宽
* @return {*}
*/
function getPath(height, width){
// 获取奖项列表
let items = document.querySelectorAll('.prize');
// 得出每个奖项的角度,然后除以2得出夹角度数
let jiaodu = 360 / items.length / 2;
// 得出短直角边的长度
let duan = (width/2) - Math.tan(jiaodu/180*Math.PI)*height;
// let duan = Math.sin(jiaodu*Math.PI/180)*height;
// 拼接路径信息
let path = `M ${duan} 0 L ${width-duan} 0 L ${width/2} ${height}`;
return path;
}
根据SVG中的path的解释
说一下16行这个路径的含义,只看Prize 1 ,就是1,2,3的顺序切割了一块
然后样式自动根据奖项数量变化就完成了
总结
主要用到了三角函数、clip-path的path、transform的rotate
明天再写一下转盘转动以及停到中奖位置的功能吧