【发布时间】:2015-09-23 22:20:41
【问题描述】:
请参阅本文末尾的更新 3,了解最近的活动/plunker
我在 Node/Express 应用程序之上使用 AngularJS。在这个应用程序中,我使用 three.js 来显示一个 3D 对象。包裹这个对象的纹理会改变,但文件名不会改变(例如,纹理图像的颜色会改变,但文件名仍然是 Texture_0.png)。
纹理文件存储在 Azure Blob 存储中,并且我启用了 CORS,因此它可以正确显示。如果我在新会话中更新图像并将其上传到 Azure Blob 存储,则在我第一次渲染 3D 对象时,它会显示纹理及其更改。但是,每当我上传新更改并尝试重新渲染时,它都会显示浏览器缓存的图像,而不是服务器中存储和引用的新图像。需要刷新页面才能看到更改,但我需要在单击弹出模式的按钮后显示此内容,而不是页面刷新。
如何在不刷新页面的情况下让 AngularJS 显示纹理图像的服务器版本而不是浏览器缓存?
我尝试添加一些随机数学来强制浏览器从服务器下载,但它不起作用。相关代码如下:
Three.JS 3D 对象代码:
$scope.generate3D = function () {
// 3D OBJECT - Variables
var texture0 = baseBlobURL + 'Texture_0.png?' + Math.random();
var boxDAE = baseBlobURL + 'Box.dae?' + Math.random();
var scene;
var camera;
var renderer;
var box;
var controls;
var newtexture;
// 3D OBJECT - Generate
newtexture = THREE.ImageUtils.loadTexture(texture0);
//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(boxDAE, function (collada) {
box = collada.scene;
box.traverse(function (child) {
if (child instanceof THREE.SkinnedMesh) {
var animation = new THREE.Animation(child, child.geometry.animation);
animation.play();
}
});
box.scale.x = box.scale.y = box.scale.z = .2;
box.updateMatrix();
init();
animate();
});
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xdddddd);
renderer.setSize(500, 500);
// Load the box file
scene.add(box);
// Lighting
var light = new THREE.AmbientLight();
scene.add(light);
// Camera
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
// Rotation Controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.noZoom = false;
controls.noPan = false;
var myEl = angular.element(document.querySelector('#webGL-container'));
myEl.append(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
}
在模态中调用 3D 对象和弹出的 Angular 函数:
$scope.boxPreview = function () {
$scope.generate3D();
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: 'lg'
}
作为脚本标签嵌入的模态(我需要在视图中使用它,因为图像 URL 是唯一的,并且运行我的视图的代码需要这些变量以及 3D 对象代码):
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">Box Preview</h3>
</div>
<div class="modal-body">
<div id="webGL-container" width="500px">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-ng-click="ok()">Close</button>
</div>
</script>
更新 1:
在 Chrome 中查看网络选项卡时,我可以看到它正在拉下正确的图像,但只是没有在 Modal 中显示。我尝试禁用缓存,但这没有效果。这就像 three.js 将图像保存在某个地方......但我只是不知道如何清除它。
更新 2:
使用来自 Mr.doob listed in this post 的建议,在出现以下错误之前,我可以在不刷新页面的情况下重新加载它:
RangeError: 超出最大调用堆栈大小
当我将以下代码添加到我实例化加载程序的位置时:
THREE.ImageLoader.prototype._load = THREE.ImageLoader.prototype.load;
THREE.ImageLoader.prototype.load = function (url, onLoad, onProgress, onError) {
this._load(url + '?' + Math.random(), onLoad, onProgress, onError);
};
//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();
这是事件的顺序:
1) 在第一次单击以在新会话中显示 3D 框时,会显示更改
2) 更改纹理并上传,然后在同一会话中单击显示 3D 框,它会显示更改。以前,它在页面刷新之前不会显示。
3) 更改纹理并上传,然后单击以在同一会话中显示 3D 框。 RangeError: 超出最大调用堆栈大小
明确地说,我在模态中打开它。并且已经看到 Modals 产生这些错误的问题,除了我在路由级别只保留一个控制器调用。
更新 3:
我整理了以下内容:
http://plnkr.co/edit/DGZA9LUBZWsLWrmXaaKD
它正在使用我的 Dropbox 公用文件夹来获取图像。我遇到了同样的问题,如果我覆盖纹理文件,当我选择框预览时它不会更新,除非我刷新页面。我需要这个来刷新点击时的盒子纹理。一些重要说明:
1) 我在控制台记录了术语“已加载”,以表明即使在模态关闭后它仍会继续呈现。我不确定是否需要连续渲染/动画,因为我只需要使用 OrbitControls 旋转盒子。请让我知道是否有更好的方法或者这是否导致缓存问题/我们需要销毁场景/重新创建它以更新框
2)使用Mr.Doob推荐的代码,我可以更新服务器上的图像并让它重新正确渲染一次,然后它给我一个错误:
未捕获的 RangeError:超出最大调用堆栈大小
代码如下:
THREE.ImageLoader.prototype._load = THREE.ImageLoader.prototype.load;
THREE.ImageLoader.prototype.load = function (url, onLoad, onProgress, onError) {
this._load(url + '?' + Math.random(), onLoad, onProgress, onError);
};
我已将这段代码留在原处,因为它在崩溃之前至少实现了我想要的一次。
3) 由于我们使用的是公共保管箱,我不确定那些协助我的人是否能够用更改覆盖 Texture_0.png 文件(我在油漆中打开它,只是涉足了一些东西并重新上传到dropbox),但您可以将 URL 更改为您自己的 dropbox 以进行测试,因为您可以上传并看到该框纹理不会刷新,除非您重新加载网页 (plunker)。
【问题讨论】:
-
第三方dom相关代码属于一个指令
-
关于如何将其放入指令的任何指导?这会解决浏览器缓存问题吗?它有点棘手,因为此页面上的代码从 routeparams 获取传递给它的变量以确定图像的 URL 路径。有没有非指令选项?
-
可以在指令中注入
$routeParams。切换代码并不难。我没有看到该 dom 元素如何与代码相关联。虽然每次打开模式时都会是新实例。 -
我的页面也需要匹配的路由参数,所以这就是我犹豫是否要拆分它的原因。我已经看到很多关于制定指令/许多方法的参考资料。你有任何你认为符合我需要的链接吗?
-
指令公开了它绑定的实际元素。可以从中访问应用程序的任何其他部分,如果范围未隔离,则继承父控制器范围。还可以访问任何服务。如果您可以注入控制器,则可以注入指令。很容易找到关于如何在指令中集成 3rd 方代码的文章
标签: javascript angularjs azure three.js browser-cache