Я создаю серию веб-приложений внутри Angular SPA. Каждое из этих приложений расположено внутри шаблона с угловыми углами, а между ними перемещается полоска и заменяет соответствующие элементы DOM и запускает скрипты из контроллеров.
Мой вопрос здесь более общий: при переходе от сцены Three.js и навигации назад, очевидно, что элементы DOM и сами скрипты перезапускаются, в результате чего сцена начинается с "нуля". Есть ли способ сохранить сцену в фоновом режиме, чтобы пользователь мог вернуться к приложению и быть там, где они остановились?
Это даже целесообразно? Я знаю, что метод requestAnimationFrame останавливает анимацию, когда пользователь переходит на другую вкладку, но как это работает в угловом контексте?
Например, здесь веб-страница WIP. Попробуйте перейти от вкладки StarFinder, а затем обратно, и вы поймете, что я имею в виду.
EDIT: Здесь JSFiddle, чтобы продемонстрировать, что я имею в виду (в этом случае он изменяет DOM без углового).
Действительно, бит, о котором идет речь, - это средство визуализации, которое получает повторное инициирование при навигации назад:
function render() {
requestAnimationFrame(render);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
Если вы используете ui-router, вы можете загрузить остальную часть своего сайта во вложенном виде, а затем просто скрыть div в родительском представлении, в котором есть ваша анимация, без фактической разгрузки. Поместите requestAnimationFrame(render);
в выражении if
который проверяет логический флаг. Затем обновите этот флаг, когда ваш маршрут изменится. См. Мой ответ здесь, чтобы узнать, как определить изменения маршрута. Если вы переходите к своей сцене, а затем вызовите render()
чтобы снова запустить анимацию.
Другой вариант может состоять в том, чтобы разрешить его выгрузку, но сохранить любые большие активы и/или настройки для вашей анимации в localStorage, чтобы время запуска было меньше.
угловое уничтожение DOM при перекомпиляции шаблона, а THREE.js использует средство рендеринга webGL, привязанное к холсту.
Если у вас есть только один рендеринг холста за один раз для THREE.js, я бы рекомендовал использовать внешний холст и перенести его в директиву при создании и вернуться к статическому контейнеру при удалении (с помощью $ destroy)
попробуй это:
создать директиву, которая будет прослушивать испускания для отображения/скрытия событий и создания функционального трехмерного холста
затем поместите этот селектор директивы в 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 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 not destroyed
tempHolder.appendChild(renderer.domElement);
});
}
};
});
<div class="container">
<threejs-canvas></threejs-canvas>
<div ng-view></div>
</div>
поэтому вам просто нужно исправить из вашего контроллера элемент, в котором вы хотите, чтобы холст отображал и передал обратный вызов, чтобы получить объекты THREE.js
tempHolder
чтобы сохранить tempHolder
работы сайта.