How do we handle webgl context lost event in Three.js - three.js

I want to handle a lost context event in Three.js. There is a nice documentation about that here but unfortunately it doesn't work when I apply it to my renderer.domElement. I try to lose the context by clicking and some variable in loseContext() are undefined.
I guess the structure is different in Three.js. Any expert?

You should be able to do something like this about the renderer was initialized and assuming of course that the variable you stored the renderer into is named 'renderer'.
renderer.context.canvas.addEventListener("webglcontextlost", function(event) {
event.preventDefault();
// animationID would have been set by your call to requestAnimationFrame
cancelAnimationFrame(animationID);
}, false);
renderer.context.canvas.addEventListener("webglcontextrestored", function(event) {
// Do something
}, false);
BTW - loseContext is not defined by Three.JS and it isn't a standard method as of this time. You can simulate it by doing the following.
Load this script before Three.JS
https://github.com/vorg/webgl-debug
Then after you've started your renderer you can hook the loseContext to the canvas.
renderer.context.canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(renderer.context.canvas);
To trigger the loseContext you would do this.
renderer.context.canvas.loseContext();
And you can then also have it fail after a set number of calls by doing this.
renderer.context.canvas.loseContextInNCalls(5);

Related

How to write a custom mouse wheel event handler in OrbitControls?

I'm working on a WebGL application using ThreeJS and OrbitControls. How do I write and make use of a custom event handler for wheel spin events?
Suppose my custom handler is
function custom_handleMouseWheel(event) { ... }
I tried adding it as a listener:
window.addEventListener("wheel", custom_handleMouseWheel);
but I suspect this adds my handler to a list of existing handlers (probably only one), and I'd have to remove the original handler. Not sure how to do that. And anyway, my handler never was called, which I checked for by adding a console.log("Wheel!") line to my handler.
Another thing I tried is to replace the handleWheelMouse method in the controls object, like this:
let original_handleMouseWheel;
function custom_handleMouseWheel(event) {
console.log("Custom Wheel!");
... fancy geometry calculations ...
original_handleMouseWheel(event);
}
// somewhere after defining scene, camera, renderer, etc...
controls = new THREE.OrbitControls( camera );
original_handleMouseWheel = controls.handleMouseWheel;
controls.handleMouseWheel = custom_handleMouseWheel;
but again the console.log line never executes.
What is the right way to go about doing this?
Just setting controls.enableZoom = false will stop the default zoom.
The default "wheel" listener is added to the "domElement" which should be the second parameter sent to the OrbitControls constructor.
Try renderer.domElement.addEventListener('wheel', custom_handleMouseWheel);

StaticImage in a layer. Is the change of source synchronous or asynchronous?

I'm developing a an application which displays images ( png ) in a layer of an OpenLayer's map. So far so good, it works like a charm. Nonetheless it may happen
that the requested image has to be created on the fly by the server and then a delay of few or more seconds can be observed before the image appears on the client's side. To make the user understand that displaying the image takes some time I use an animation that appears when the request is sent to the server and should disappear when the image is served and displayed (see code below). What I observe though is that the animation never appears exactly as is the service of the image was processed in an asynchronous way. I really would like to know if my interpretation is correct and in such a case which can of event I should trap and only then make the animation disappear.
document.getElementById('loading').style.display='block';
_im_layer_1 = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'http://'+server+':'+port+'/png/?path="'+_path+'"&si='+_sliceIndex,
projection: _projection_1,
imageExtent: _extent
})
});
console.log("adding the image layer");
_map_1.addLayer(_im_layer_1);
document.getElementById('loading').style.display='none';
I was expecting to listen to the source with
imageStaticSource.on('change', evt => {
console.log('no event, contrary to what I would expect');
});
but it fails contrary to what I expected from the API docs.
So, looking at the code, I've seen there is an imageLoadFunction option for the ol.source.ImageStatic constructor. When not set, this function fallback to a default one. I've created a new one, derived from the default and made some changes to demonstrate how you can get the start of the loading event and then the end of it.
You will find a demo derived from the official sample that should illustrate the process. Try it on you side as the demo does not wait some seconds to return the image, contrary to your use case.
var imageLoadFunction = function(image, src) {
// Where you start showing the loader using a variable
console.time('loader');
image.getImage().addEventListener('load', function() {
// Where you should mention to stop the loader
console.timeEnd('loader');
});
image.getImage().src = src;
};
var imageStaticSource = new ol.source.ImageStatic({
attributions: '© xkcd',
url: 'https://imgs.xkcd.com/comics/online_communities.png',
projection: projection,
imageLoadFunction: imageLoadFunction,
imageExtent: extent
});

Clean up Threejs WebGl contexts

I have a problem while cleaning up my WebGl-Scenes. I'm using Three.js with a WebGlRenderer. In my application I have to change the views quite often and therefore need to render new scenes all the time. Uptil now I destroy and reinitialize the entire Threejs scene. After switching the scenes about 15 - 20 times I get following warning:
WARNING: Too many active WebGL contexts. Oldest context will be lost.
After switching a couple of times more the context is lost completly and the application crashes.
Is there a way to destroy the current WebGl context, when cleaning up? Or does the WebGlRenderer always create a new WebGl context when being instantiated?
I'm using Three.js R64.
I've got same problem, but i couldn't solve it using SPA, because of requirements.
There is .forceContextLoss() method in WebGLRenderer (rev 71, maybe was early) for this situations.
So, my code in 'deallocate' method is somemethig like
_self.renderer.forceContextLoss();
_self.renderer.context = null;
_self.renderer.domElement = null;
_self.renderer = null;
You can keep the same renderer for different scenes. The renderer does not care what scene it will render. You can supply a different Scene everytime you call render() if you like.
// instantiate only once and keep it
var renderer = new THREE.WebGLRenderer();
// current scene and camera. Switch whenever you like
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(...);
fillScene(scene);
// rendering always uses current scene
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
/* ...
* somewhere in your application
* ...
*/
if(condition) {
// switch scene
scene = new THREE.Scene();
fillOtherScene(scene);
}
You should create and use only one WebGlRenderer. In my SPA (single page application) I had weird problem with camera/scene in THREE.js after few redirects. It was because WebGlRenderer was created every time when one particular page was rendered. There was no error in console log (only the warning you wrote).
Bug appeared as change in camera position and problems with rendering.

Do we have canvas Modified Event in Fabric.js?

In Fabric.js we have Object modified events like object:modified. Do we have similar event for the entire canvas.
Actually I am trying to implement undo and redo features. I am saving the canvas as JSON if something happens on it and loading it again for undo feature.
Do we have any better solution for this features in Fabric.js?
Don't forget to check for added/removed objects too. You could implement it like this:
var canvasModifiedCallback = function() {
console.log('canvas modified!');
};
canvas.on('object:added', canvasModifiedCallback);
canvas.on('object:removed', canvasModifiedCallback);
canvas.on('object:modified', canvasModifiedCallback);
This is better explained in this link. Use it this way:
canvas.on('object:moving', function(e) { // or 'object:added'
var activeObject = e.target;
console.log(activeObject.get('left'), activeObject.get('top'));
});

How do I find out with Mootools if an element is being animated?

I need to be able to detect is an animation is currently happening using Mootools.
Of course if there is a way to detect this with plain old js even better. But I couldn't think of a way to do this without running it every ms and seeing if the styles are changing.
How i'm doing the animation
new Fx.Tween(c.getElement('.is-active'), {
property: 'opacity',
duration: e.options.speed,
onComplete: function () {
this.element
.removeClass("is-active")
.addClass("is-hidden")
.setStyle('display', "")
.setStyle('opacity', "");
}
}).start(0).wait(e.options.speed);
One way that I often use is to check if animation is running with isRunning function:
// constructor
var fx = new Fx.Tween( ....
// later when I want to check if animation is running
if ( fx.isRunning() ) ...

Resources