【欧洲杯】用纯前端写一个滚动的足球(下)

怎么样?正五边形简单吧?那么今天我们继续,把整个滚动的足球写出来吧。


一、五角星在足球上的位置

一个传统足球表面有 12 个正五边形。为了便于理解,我们使用地球模型来做讲解。

最简单的,我们在南极北极各放一个正五边形。这两个五边形从正常的屏幕主视角(也叫做前视角)看上去,都是几乎处于水平位置。即:这两个正五边形围绕 X 轴分别向上或向下旋转 90deg

然后我们需要在北半球南半球相同维度各放置五个正五边形。

维度方面:北半球的五个应该放在北纬 30deg 的地方,同样南半球的五个也应该放在南纬 30deg 的地方。这样一来,北极到北纬、北纬到南纬、南纬到南极,角度差均为 60deg

经度方面:完整一圈一共有 360deg,一圈放置 个,那么就平均放在夹角 72deg 的平均分布。并确保南半球北半球相对有一个 36deg 的错位


二、构建创建正五边形的方法

我们从主视角出发,每一个正五边形都创建在主视觉正中间。然后通过 transform 的 3D 属性完成位置旋转。因此需要控制五边形的样式为 3D 模式:

// html
<div class="ball"></div>

// css
.ball {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 1000px;
  height: 1000px;
  margin: auto;
  transform-style: preserve-3d;
}
.five {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 200px;
  height: 0;
  margin: auto;
  border-top: 190.35px solid black;
  border-right: 61.8px solid transparent;
  border-left: 61.8px solid transparent;
  backface-visibility: visible;
}
.five::before {
  position: absolute;
  top: -285px;
  left: -61.8px;
  border-right: 161.8px solid transparent;
  border-bottom: 95.1px solid black;
  border-left: 161.8px solid transparent;
  content: '';
}

我们通过 JavaScript 动态生成一个正五边形元素:

const ball = document.querySelector('.ball');
const five = document.createElement('div');
five.className = 'five';
ball.appendChild(five);

 若要把这个正五边形放到北极,只需要围绕 X 轴向北旋转 90deg

five.style.transform = 'rotateY(0deg) rotateX(90deg) translateZ(500px)';

 同理,放到南极

five.style.transform = 'rotateY(0deg) rotateX(-90deg) translateZ(500px)';

 同样的道理,放置北半球的五个,需要以 72deg 跨度让其围绕 Y 轴旋转:

five.style.transform = 'rotateY(0deg) rotateX(30deg) translateZ(500px)';
five.style.transform = 'rotateY(72deg) rotateX(30deg) translateZ(500px)';
five.style.transform = 'rotateY(144deg) rotateX(30deg) translateZ(500px)';
five.style.transform = 'rotateY(216deg) rotateX(30deg) translateZ(500px)';
five.style.transform = 'rotateY(288deg) rotateX(30deg) translateZ(500px)';

 南半球与北半球在经度方面存在一个 36deg 的错位

five.style.transform = 'rotateY(36deg) rotateX(-30deg) translateZ(500px)';
five.style.transform = 'rotateY(108deg) rotateX(-30deg) translateZ(500px)';
five.style.transform = 'rotateY(180deg) rotateX(-30deg) translateZ(500px)';
five.style.transform = 'rotateY(252deg) rotateX(-30deg) translateZ(500px)';
five.style.transform = 'rotateY(324deg) rotateX(-30deg) translateZ(500px)';

 聪明的你肯定已经找到规律了,咱们不妨将每一个正五角星的创建封装成一个函数:

/**
 * @description 创建一个正五角星
 * @param {Number} num 北半球或者南半球各有 num 个正五角星
 * @param {Number} item 纬度
 * @param {Number} index 北半球或者南半球的第 index 个正五角星
 * @param {Number} translate 南半球与北半球之间在经度上存在一个 36deg 的错位,默认为 0,南半球传入 36
*/
function createFivePolygon(num, item, index, translate = 0) {
  const radius = 500; // 足球半径
  const gap = 360 / num; // 每个五边形之间的空隙
  const ball = document.querySelector('.ball'); // 找到足球 DOM
  const five = document.createElement('div'); // 创建一个正五边形
  five.className = 'five'; // 设置这个正五边形的类名,让其与 CSS 样式关联
  five.style.transform = `rotateY(${index * gap + translate}deg) rotateX(${item}deg) translateZ(${radius}px)`; // 位置控制
  ball.appendChild(five); // 把这个正五边形放到足球 DOM 树上
}

 这样,咱们就封装了一个创建正五边形的函数。


三、在对应位置创建正五边形

北极南极各创建一个正五边形:

createFivePolygon(1, 90, 0); // 北极
createFivePolygon(1, -90, 0); // 南极

北半球南半球各在对应位置创建五个正五边形

createFivePolygon(5, 30, 0); // 北半球
createFivePolygon(5, 30, 1); // 北半球
createFivePolygon(5, 30, 2); // 北半球
createFivePolygon(5, 30, 3); // 北半球
createFivePolygon(5, 30, 4); // 北半球
createFivePolygon(5, -30, 0, 36); // 南半球
createFivePolygon(5, -30, 1, 36); // 南半球
createFivePolygon(5, -30, 2, 36); // 南半球
createFivePolygon(5, -30, 3, 36); // 南半球
createFivePolygon(5, -30, 4, 36); // 南半球

 可以看到,createFivePolygon 方法调用了 12 次,摸清楚其中的规律,我们就可以通过循环调用

function calcPosition() {
  const rotateArr = [30, -30]; // 每一圈绕 X 轴旋转的度数
  const num = 5; // 每一圈有多少个五边形

  rotateArr.forEach(function(item) {
    for (let i = 0; i < num; i++) {
        createFivePolygon(num, item, i, item > 0 ? 0 : 36);
    }
  });
  createFivePolygon(1, 90, 0); // 北极
  createFivePolygon(1, -90, 0); // 南极
}

 这样,我们就通过一个简单的函数封装,实现了 12 个正五边形的创建。


四、让足球滚动起来

咱们通过 CSS 动画,让足球围绕 Y 轴转动:

@keyframes rotate {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(360deg); }
}

为了更加真实一些,我们控制一个“黄赤夹角”,让其滚动的更加真实一些:

.ball {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 1000px;
  height: 1000px;
  margin: auto;
  transform: rotateX(-20deg) rotateY(0deg) rotateZ(10deg);
  transform-style: preserve-3d;
  animation: rotate 10s linear infinite;
}

@keyframes rotate {
  from { transform: rotateX(-20deg) rotateY(0deg) rotateZ(10deg); }
  to { transform: rotateX(-20deg) rotateY(360deg) rotateZ(10deg); }
}

这样,我们就实现了一个足球的滚动效果。


完整源码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>足球</title>
<style type="text/css">
.ball {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 1000px;
  height: 1000px;
  margin: auto;
  /* transform: rotateX(-20deg) rotateZ(10deg) rotateY(0deg); */
  transform: rotateX(-20deg) rotateY(0deg) rotateZ(10deg);
  transform-style: preserve-3d;
  animation: rotate 10s linear infinite;
}
.five {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 200px;
  height: 0;
  margin: auto;
  border-top: 190.35px solid black;
  border-right: 61.8px solid transparent;
  border-left: 61.8px solid transparent;
  backface-visibility: visible;
}
.five::before {
  position: absolute;
  top: -285px;
  left: -61.8px;
  border-right: 161.8px solid transparent;
  border-bottom: 95.1px solid black;
  border-left: 161.8px solid transparent;
  content: '';
}

@keyframes rotate {
  from { transform: rotateX(-20deg) rotateY(0deg) rotateZ(10deg); }
  to { transform: rotateX(-20deg) rotateY(360deg) rotateZ(10deg); }
}
</style>
<script type="text/javascript">
function calcPosition() {
  const rotateArr = [30, -30]; // 每一圈绕 X 轴旋转的度数
  const num = 5; // 每一圈有多少个五边形

  rotateArr.forEach(function(item) {
    for (let i = 0; i < num; i++) {
        createFivePolygon(num, item, i, item > 0 ? 0 : 36);
    }
  });
  createFivePolygon(1, 90, 0); // 北极
  createFivePolygon(1, -90, 0); // 南极
}

/**
 * @description 创建一个正五角星
 * @param {Number} num 北半球或者南半球各有 num 个正五角星
 * @param {Number} item 纬度
 * @param {Number} index 北半球或者南半球的第 index 个正五角星
 * @param {Number} translate 南半球与北半球之间在经度上存在一个 36deg 的错位,默认为 0,南半球传入 36
*/
function createFivePolygon(num, item, index, translate = 0) {
  const radius = 500; // 足球半径
  const gap = 360 / num; // 每个五边形之间的空隙
  const ball = document.querySelector('.ball'); // 找到足球 DOM
  const five = document.createElement('div'); // 创建一个正五边形
  five.className = 'five'; // 设置这个正五边形的类名,让其与 CSS 样式关联
  five.style.transform = `rotateY(${index * gap + translate}deg) rotateX(${item}deg) translateZ(${radius}px)`; // 位置控制
  ball.appendChild(five); // 把这个正五边形放到足球 DOM 树上
}

window.onload = calcPosition;
</script>
</head>
<body>
<div class="ball"></div>
</body>
</html>

仅仅依赖文字讲解,对于这样 3D 模型来说,比较容易难以理解。不久的将来,我会补上视频讲解,以便更加透彻的理解。

大家敬请期待......

关注我,为你提供更多经常内容! 

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值