2015-06-25 63 views
0

我在Angular SPA內部構建了一系列Web應用程序。這些應用程序中的每一個都位於Angular模板內部,並且它們之間的導航會剝離並替換適當的DOM元素並從控制器運行腳本。有角度的畫布(Three.js)場景

我的問題更多的是一般性問題:從Three.js場景導航離開並回溯時,顯然DOM元素和腳本本身會重新運行,導致場景從「scratch」開始。有沒有辦法讓場景在後臺運行,以便用戶可以導航回到應用程序,並讓它停留在他們離開的地方?

這是更可取的嗎?我知道,當用戶導航到另一個選項卡時,requestAnimationFrame方法會停止動畫,但在Angular上下文中它是如何工作的?

作爲示例,here's the WIP web page。嘗試從StarFinder標籤導航,然後返回,您會看到我的意思。

編輯Here's a JSFiddle來演示我的意思(在這種情況下,它修改了沒有Angular的DOM)。

真的,有問題的是位渲染器,在導航回到它被重新啓動:

function render() { 
     requestAnimationFrame(render); 
     cube.rotation.x += 0.01; 
     cube.rotation.y += 0.01; 
     renderer.render(scene, camera); 
    } 
render(); 
+0

請在這裏添加有意義的代碼和問題描述。不要只是鏈接到需要修復的網站 - 否則,一旦問題解決,這個問題將會給未來的訪問者帶來任何價值。發佈一個證明你的問題的[簡短的,自包含的,正確的例子(SSCCE)](http://www.sscce.org/)將幫助你得到更好的答案。有關更多信息,請參見[我網站上的某些內容不起作用。我可以只粘貼一個鏈接嗎?](http://meta.stackexchange.com/questions/125997/)謝謝! – Cerbrus

+0

@Cerbrus鏈接的網站不是「需要修復」的網站,而且這個問題比基於特定代碼更普遍/理論化。你想如何繼續? –

+0

解決問題時,問題中的鏈接將失去它的價值,因此它不會幫助未來訪問者的問題。你可以在這個問題上發佈SSCCE嗎? – Cerbrus

回答

0

如果您正在使用的用戶界面的路由器,您可以加載您的網站的其餘部分嵌套查看,然後在沒有實際卸載動畫的父視圖中隱藏div。將requestAnimationFrame(render);置於檢查布爾標誌的if語句中。然後在路線改變時更新該標誌。查看我的回答here,瞭解如何檢測路線更改。如果您正在導航您的場景,則還請撥打render()以再次啓動動畫。

另一個選項可能是允許它卸載,但在localStorage中保存動畫的任何大型資產和/或設置,這樣啓動時間就會縮短。

+0

我想要無縫重新加入動畫,所以我會檢查一下您的第一個建議。乾杯。 –

0

重新編譯模板時角毀壞DOM,而THREE.js使用綁定到畫布的webGL渲染器。

如果您一次只有一個畫布渲染THREE.js,我建議使用外部畫布,並在創建時將其移動到指令中,並在移除時移回靜態容器(使用$ destroy)

試試這個:

創建聽聽發出的顯示/隱藏事件指令,然後創建一個3D功能的帆布

然後把該指令選擇在DOM變化的模板之外

這樣

app.directive('threejsCanvas', function directive() { 
 
    return { 
 
    link: function(scope){ 
 
     var scene = new THREE.Scene(); 
 
     
 
     // create a temp holder to save the canvas outside of canvas 
 
     var tempHolder = document.createElement('div'); 
 
     tempHolder.style.display = 'none'; 
 
     window.document.body.appendChild(tempHolder); 
 
     
 
     var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); 
 
     var renderer = new THREE.WebGLRenderer(); 
 
     document.body.appendChild(renderer.domElement); 
 
     
 
     scope.$on('start:webgl', function(view, callback) { 
 
     view.appendChild(renderer.domElement); 
 
     
 
     // you may do somthing like ... 
 
     // renderer.setSize(view.innerWidth, view.innerHeight); 
 
     // and change camera ratio if it have to change 
 
     
 
     // pass the arguments to the caller's callback so the script can interact with the canvas singleton 
 
     callback({ 
 
      scene: scene, 
 
      camera: camera, 
 
      renderer: renderer 
 
     }); 
 
     }); 
 
     
 
     scope.$on('$destroy', function() { 
 
     // move canvas away from template so it's not destroyed 
 
     tempHolder.appendChild(renderer.domElement); 
 
     }); 
 
    } 
 
    }; 
 
});
<div class="container"> 
 
    <threejs-canvas></threejs-canvas> 
 
    <div ng-view></div> 
 
</div>

所以你只要從你的控制器發出要在其中畫布渲染和傳遞一個回調來獲取three.js所元素對象

+0

我也喜歡這種方法。也許你可以將它與我的解決方案結合起來,並暫停在tempHolder中的渲染,以保持網站上的性能。 – adam0101