SVG 立方體內嵌路徑拼接
我使用了jquery編寫互動的旋轉,因為初學所以不太熟練,還請見諒。樣式我是寫stylus編碼,自動生成css。
2.正文
話不多說,先上一張效果圖。

我將其分成三部分。第一部分是正方體部分( SVG
),第二部分是svg中的路徑動畫了( animateMotion
+ jQuery
),第三部分則是互動旋轉( jQuery
)。
1.正方體
做一個正方體
我的思路是用六塊 svg
正方形畫板通過 css
屬性旋轉和平移來構成正方體。
html
程式碼:
<div class="page"> <div class="state"> <!-- 定位--> <div class="container"> <!--旋轉--> <!-- 前 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="front"> <rect class="rect"></rect> </svg> <!-- 後 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="behind"> <rect class="rect "></rect> </svg> <!-- 左 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="left"> <rect class="rect "></rect> </svg> <!-- 右 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="right"> <rect class="rect "></rect> </svg> <!-- 上 --> <svg xmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="top"> <rect class="rect "></rect> </svg> <!-- 下 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="bottom"> <rect class="rect "></rect> </svg> </div> </div> </div> 複製程式碼
stylus
程式碼:
html margin 0 padding 0 height 100% width 100% body height 100% width 100% .page//頁面 .state//用於定位的盒子 height 300px width 300px position absolute top 50% left 50% transform translate(-50%,-50%)//修正位置 .container//放置六個svg平面旋轉平移後,可視作為立方體 transform-style preserve-3d position relative height 300px width 300px transform rotateX(0deg) rotateY(0deg) svg position absolute height 300px width 300px stroke-width 5px stroke brown fill transparent //填充用透明 .rect height 300px width 300px .top transform rotateX(90deg) translateZ(150px) .bottom transform rotateX(-90deg) translateZ(150px) .left transform rotateY(-90deg) translateZ(150px) .right transform rotateY(90deg) translateZ(150px) .front transform rotateY(0deg) translateZ(150px) .behind transform rotateY(180deg) translateZ(150px) 複製程式碼
通常有兩種方式做成立方體。
第一種:先平移再旋轉。優點是不許太強的空間構造能力,寫起來比較簡單。缺點就是:程式碼數會多一些,需要在平移後設置旋轉基點。樣式附在下面替換一下即可。
.top fill blue transform-origin: bottom transform translateY(-200px) rotateX(90deg) .bottom fill red transform-origin: top transform translateY(200px) rotateX(-90deg) .left fill green transform-origin: right transform translateX(-200px) rotateY(-90deg) .right fill black transform-origin: left transform translateX(200px) rotateY(90deg) .front fill grey transform translateZ() .behind fill pink transform translateZ(-200px) 複製程式碼
第二種:先旋轉再平移。這個的特點就是與上面的相反了。(我使用的是這種)
兩種方式都能生成正方體。
兩種正方體生成的原理圖
第一種
平移後的狀況

第二種
旋轉後的狀況

以上就是兩種立方體的構成方法的概念了。
2. 路徑動畫
先上程式碼:
比較冗雜
<div class="state"> <!-- 定位--> <div class="container"> <!--旋轉--> <!-- 前 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="front"> <rect class="rect"></rect> <circle x="0" y="0" r="5" stroke="none" fill="red"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#frontY"></mpath> </animateMOtion> </circle> <circle x="0" y="0" r="5" stroke="none" fill="blue"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#frontX"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m150.75,0.75l0,300" id="frontY" /> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m300,150c-300,0 -300,0 -300,0" id="frontX" /> </svg> <!-- 後 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="behind"> <rect class="rect "></rect> <circle x="0" y="0" r="5" stroke="none" fill="red"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#behindY"></mpath> </animateMOtion> </circle> <circle x="0" y="0" r="5" stroke="none" fill="blue"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#behindX"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m150,300c0,0 1,-300 0,-300" id="behindY" /> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m300,150c-300,0 -300,0 -300,0" id="behindX" /> </svg> <!-- 左 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="left"> <rect class="rect "></rect> <circle x="0" y="0" r="5" stroke="none" fill="blue"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#leftX"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m300,150c-300,0 -300,0 -300,0" id="leftX" /> </svg> <!-- 右 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="right"> <rect class="rect "></rect> <circle x="0" y="0" r="5" stroke="none" fill="blue"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#rightX"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m300,150c-300,0 -300,0 -300,0" id="rightX" /> </svg> <!-- 上 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="top"> <rect class="rect "></rect> <circle x="0" y="0" r="5" stroke="none" fill="red"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#topY"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m150.75,0.75l0,300" id="topY" /> </svg> <!-- 下 --> <svgxmlns="http://www.w3/org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="bottom"> <rect class="rect "></rect> <circle x="0" y="0" r="5" stroke="none" fill="red"> <animateMOtion dur="3s" begin="infinite"> <mpath xlink:href="#bottomY"></mpath> </animateMOtion> </circle> <path fill="#fff" stroke="#000" stroke-width="1.5" stroke-opacity="null" fill-opacity="null" opacity="0.5" d="m150.75,0.75l0,300" id="bottomY" /> </svg> </div> </div> 複製程式碼
路徑動畫則是由 animateMotion
元素來做的。
首先每個 svg
中圓點的路徑是 path
動畫,在這裡我用了直線,也可以換成別的路徑,只要第一個路徑的結束部分和第二個路徑的起始部分接近重合就可以做到看著像連線到一起的動畫。
路徑我是用 Method Draw 畫的editor.method.ac/
有興趣的可以自己設計一下
接下來就是重點的路徑控制了
$(document).ready(function () { const animate = document.getElementsByTagName('animateMotion'); // 0 frontY 1 frontX 2 behindY 3 behindX 4 leftX 5 rightX 6 topY 7 bottomY var frontY = animate[0], frontX = animate[1], behindY = animate[2], behindX = animate[3], leftX = animate[4], rightX = animate[5], topY = animate[6], bottomY = animate[7]; // Y面球體運動 (() => { //先執行一次 frontY.beginElement(); setTimeout(() => { bottomY.beginElement(); }, 3000); setTimeout(() => { behindY.beginElement(); }, 6000); setTimeout(() => { topY.beginElement(); }, 9000); // 迴圈執行動畫 var time = setInterval(() => { frontY.beginElement(); setTimeout(() => { bottomY.beginElement(); }, 3000); setTimeout(() => { behindY.beginElement(); }, 6000); setTimeout(() => { topY.beginElement(); }, 9000); }, 12000); })(); // X面球體運動 (() => { //先執行一次 frontX.beginElement(); setTimeout(() => { leftX.beginElement(); }, 3000); setTimeout(() => { behindX.beginElement(); }, 6000); setTimeout(() => { rightX.beginElement(); }, 9000); // 迴圈執行動畫 var time = setInterval(() => { frontX.beginElement(); setTimeout(() => { leftX.beginElement(); }, 3000); setTimeout(() => { behindX.beginElement(); }, 6000); setTimeout(() => { rightX.beginElement(); }, 9000); }, 12000); })(); }) 複製程式碼
我的控制方式是全部由jQuery來控制, 在 animateMotion
元素中設定的起始時間 begin
屬性為 infinite
這是在頁面接在完後不會自己執行的 。
我使用jQuery來控制動畫的開始。
首先先獲取每個動畫元素 const animate = document.getElementsByTagName('animateMotion');
將每個動畫元素都標記好是什麼動畫。
接著我在這使用了計時器 setInterval
和 setTimeout
來控制動畫。 用 setInterval
來迴圈播放動畫,再每次迴圈中分別用 setTimeout
來控制動畫的的先後順序。 每個 setTimeout
計時器的延遲等於之前所有動畫的總時間,可以獲取元素的dur等方法獲取和設定,在這為圖方便設定了固定值。
最後有兩個方法可以控制動畫的停止與繼續,是 svg
內建的API
如果要使用這兩個API的話,最好將動畫的 begin
值設定為 上一個動畫.end
, begin
的值支援很多型別,詳情請看張鑫旭大佬的文章
www.zhangxinxu.com/wordpress/2…
// svg指當前svg DOM元素 // 暫停 svg.pauseAnimations(); // 重啟動 svg.unpauseAnimations() 複製程式碼
3.旋轉控制
旋轉控制是我還沒完善的地方,體驗不是十分好,還望大佬們幫我指出錯誤。另一個旋轉方案過一兩天再新增上來
先上程式碼:
var X = 0;//記錄X軸旋轉過的角度 var Y = 0;//記錄Y軸旋轉過的角度 // 旋轉控制 $('.container').mousedown(function (event) { var mousedownX = event.clientX; var mousedownY = event.clientY; $('body').mousemove(function (event) { var mousemoveX = event.clientX; var mousemoveY = event.clientY; var scaleY = ((mousemoveX - mousedownX) / 200); var scaleX = ((mousemoveY - mousedownY) / 200); Y = ((Y + scaleY) % 360); X = ((X + scaleX) % 360); $('.container').animate({}, function () { $('.container').css({ 'transform': `rotateX(${X}deg) rotateY(${Y}deg)` }); }) }) }) $('body').mouseup(function () { $('body').unbind('mousemove'); $('body').unbind('mousedown'); }) 複製程式碼
旋轉事件由 在立方體上滑鼠按下事件觸發啟動 ,觸發後由 在頁面上滑鼠移動來觸發旋轉 ,結束則由 在頁面上滑鼠回彈觸發 移除滑鼠旋轉事件。
首先在旋轉控制的函式前需要儲存上次旋轉的角度所以設定了 X``Y
的變數。
接著在立方體元素中新增 mousedown()
事件,在mousedown的回撥函式中先記錄下滑鼠點選的位置 var mousemoveX = event.clientX;
並且在 body
元素上新增 mousemove()
事件因為是要在整個頁面上移動。
最後就是最重要的移動部分, 先記錄滑鼠移動的位置 var mousemoveX = event.clientX;
然後計算滑鼠移動的距離 var scaleY = ((mousemoveX - mousedownX) / 200);
這裡面200是可隨意更改的,因為滑鼠移動距離對於旋轉角度來說太大了所以要除以一個倍率可以自己來設定, 其次是計算正方體對於初始的位置旋轉的多少角度 Y = ((Y + scaleY) % 360);
這裡要除以360做範圍限制,其實不新增也可以, rotate
屬性支援超過360度。 接著就是設定旋轉角度了
$('.container').animate({}, function () { $('.container').css({ 'transform': `rotateX(${X}deg) rotateY(${Y}deg)` }); }) 複製程式碼
通過 animate()
方法來將旋轉做動畫效果在裡邊通過 css()
方法來設定旋轉的角度。