「移動設備陀螺儀」與「preserve-3d」碰撞的火花

原文連接:航洋 blogjavascript

「移動設備陀螺儀」與「preserve-3d」碰撞的火花

涉及知識「CSS:transform、JS:deviceorientation」

廢話很少,先上 DEMO「請使用移動設備查看」css

如何搭建一個簡單的立方體

只須要寥寥幾行 HTML、CSS 代碼就能產出一個「立方體」html

  • 核心 HTML 以下
<div class="cube">
  <span class="cube-face cube-front"></span>
  <span class="cube-face cube-back"></span>
  <span class="cube-face cube-left"></span>
  <span class="cube-face cube-right"></span>
  <span class="cube-face cube-top"></span>
  <span class="cube-face cube-bottom"></span>
</div>

<!-- 6 個 <span /> 表示立方體的 6 個面 -->
<!--
 這裏有個小插曲:
 起初,我使用的 6 個 <i /> 標籤,由於大部分表示「圖形、圖標」的元素都用 <i /> 標籤,
 不過,強迫症的我,細細想來,<i /> 是表示的「斜體文字」,語義上徹底不匹配啊。
 因此,我在知乎上搜到這樣一個描述:[爲何你們都用i標籤<i></i>用做小圖標?](https://www.zhihu.com/question/26880548)
 有個回答:
 「
   你們都遵循開放的標準來作事,將來可能少走彎路。
   少用 hack 的方法解決問題,有助於你寫出向將來兼容的代碼。
  」
  我很贊同,因此就把 <i /> 改爲了 <span />。
 -->
  • CSS 第一步
.cube {
  width: 160px;
  height: 160px;
  position: relative;
  -webkit-transform-style: preserve-3d; /* 這一句重點 */
  transform-style: preserve-3d;
  -webkit-transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg);
  transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg);
}
.cube-face {
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  box-shadow: inset 0 0 4px 1px #fff;
  box-sizing: border-box;
  background: -webkit-linear-gradient(45deg, rgba(156, 144, 144, .6), #000);
  background: -o-linear-gradient(45deg, rgba(156, 144, 144, .6), #000);
  background: linear-gradient(45deg, rgba(156, 144, 144, .6), #000)
}

這個 CSS 過於簡單,就不贅述與解釋。
主要是要設置父元素 .cubetransform-style: preserve-3d
使子元素位於 3D 空間中,否則子元素都是「平面內、扁平化」,達不到 3D 效果。java

給全部子元素 .cube-face 設置了透明的漸變色 rgba(156, 144, 144, .6) 背景,
是爲了更好的觀察到「被遮住的反面」,視覺上更加 立體git

目前效果截圖大概是這個樣子:github

圖片描述

看起來就像一個正方形,實際上是 6 個面所有重疊在一塊兒。web

  • CSS 第二步
.cube-front {
  -webkit-transform: translateZ(80px);
  transform: translateZ(80px);
}

上面 4 行代碼使得「正面 .cube-front」向前移動 80px「也就是立方體一半的邊長」。
同理咱們能夠設置「背面 .cube-back」向後移動 80px
效果大概是這樣:動畫

圖片描述

  • CSS 第三步
.cube-left {
  -webkit-transform: rotateY(90deg);
  transform: rotateY(90deg);
}

上面 4 行代碼使得「左面 .cube-left」先順時針旋轉「90 度」
大概是這個樣子:spa

圖片描述

而後再向「左邊」移動 80px 就 OK 啦,
注意:左邊是 Z 軸負方向。3d

.cube-left {
  -webkit-transform: rotateY(90deg) translateZ(-80px);
  transform: rotateY(90deg) translateZ(-80px);
}

大概是這個樣子:

圖片描述

同理,咱們能夠作出右邊的效果,惟一區別就是,右邊移動方向與左邊相反。
道理相似,殊途同歸,上邊和下邊,想必聰明的你們都掌握了正確寫法姿式。

成品大概是這個樣子:

圖片描述

用陀螺儀使立方體動起來

細心的開發者應該發現了,在最開始,我給父元素 .cube 設置了:
transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg)
認讓父元素在三維空間上旋轉 10 度。
若是咱們動態連續修改這三個值,絕對能夠達到 3D 旋轉動畫的效果。

這個時候,JS 的 deviceorientation「檢測設備方向」 事件閃現忽然閃如今個人腦海。
由於這個事件的回調參數裏面剛好有三個參數「beta、gamma、alpha」,分別表明「X、Y、Z」的旋轉方向。

beta 表示設備在 x 軸上的旋轉角度,範圍爲 [-180, 180] 度。它描述的是設備由前向後旋轉的狀況。
gamma 表示設備在 y 軸上的旋轉角度,範圍爲 [-90, 90] 度。它描述的是設備由左向右旋轉的狀況。
alpha 表示設備沿 z 軸上的旋轉角度,範圍爲 [0, 360] 度。

大概是這個樣子:

圖片描述

  • 註冊 deviceorientation 事件,獲得 x、y、z
const handleOrientation = ({beta: x, gamma: y, alpha: z}) => {
  // 1. 獲得 x、y、z
  // 2. 處理 x、y、z
  // 3. 使用 x、y、z
}

global.addEventListener('deviceorientation', handleOrientation)
  • 處理 x、y、z

因爲咱們指望立方體能夠在 x、y、z 三個反向的旋轉範圍是 [-360, 360] 度,
可是 beta、gamma、alpha 的範圍並非咱們指望的範圍,因此咱們要處理一下數據。

{
  x: x * 2,
  y: y * 4,
  z: (z - 180) * 2
}
  • 使用 x、y、z

咱們如今獲得的 x、y、z 已經在 [-360, 360] 度範圍內了,
接下來要作的就是,使用 x、y、z 修改父元素 .cuberotateX(xdeg) rotateY(ydeg) rotateZ(zdeg) 旋轉值。

完整的代碼大概是這樣:

const cube = document.querySelector('.cube')
const setCubePosition = ({x = 0, y = 0, z = 0}) => {
  cube.style = `transform: rotateX(${x}deg) rotateY(${y}deg) rotateZ(${x}deg);-webkit-transform: rotateX(${x}deg) rotateY(${y}deg) rotateZ(${x}deg);`
}
const handleOrientation = ({beta: x, gamma: y, alpha: z}) => {
  setCubePosition({
    x: x * 2,
    y: y * 4,
    z: (z - 180) * 2
  })
}

global.addEventListener('deviceorientation', handleOrientation)

慶祝時刻

如今咱們已經完成了,一個利用「移動設備陀螺儀」與「preserve-3d」實現的 3D 交互效果。
讓咱們爲本身鼓掌
???

點我查看完整代碼


感謝閱讀

相關文章
相關標籤/搜索