mirror of
https://github.com/visgl/luma.gl.git
synced 2026-02-01 14:33:49 +00:00
AnimationLoopProxy tests (#1184)
This commit is contained in:
parent
ad7040c939
commit
b1de8b2b6e
@ -3,6 +3,33 @@ import {getPageLoadPromise, getCanvas} from '@luma.gl/webgl';
|
||||
import {requestAnimationFrame, cancelAnimationFrame} from '@luma.gl/webgl';
|
||||
import {log, assert} from '../utils';
|
||||
|
||||
function initializeCanvas(_self, canvas) {
|
||||
const eventHandlers = new Map();
|
||||
|
||||
canvas.addEventListener = (type, handler) => {
|
||||
_self.postMessage({command: 'addEventListener', type});
|
||||
if (!eventHandlers.has(type)) {
|
||||
eventHandlers.set(type, []);
|
||||
}
|
||||
eventHandlers.get(type).push(handler);
|
||||
};
|
||||
canvas.removeEventListener = (type, handler) => {
|
||||
_self.postMessage({command: 'removeEventListener', type});
|
||||
const handlers = eventHandlers.get(type);
|
||||
if (handlers) {
|
||||
handlers.splice(handlers.indexOf(handler), 1);
|
||||
}
|
||||
};
|
||||
canvas.dispatchEvent = (type, event) => {
|
||||
const handlers = eventHandlers.get(type);
|
||||
if (handlers) {
|
||||
handlers.forEach(handler => handler(event));
|
||||
}
|
||||
};
|
||||
|
||||
_self.canvas = canvas;
|
||||
}
|
||||
|
||||
export default class AnimationLoopProxy {
|
||||
// Create the script for the rendering worker.
|
||||
// @param opts {object} - options to construct an AnimationLoop instance
|
||||
@ -15,39 +42,12 @@ export default class AnimationLoopProxy {
|
||||
});
|
||||
|
||||
self.canvas = null;
|
||||
|
||||
function initializeCanvas(canvas) {
|
||||
const eventHandlers = new Map();
|
||||
|
||||
canvas.addEventListener = (type, handler) => {
|
||||
self.postMessage({command: 'addEventListener', type});
|
||||
if (!eventHandlers.has(type)) {
|
||||
eventHandlers.set(type, []);
|
||||
}
|
||||
eventHandlers.get(type).push(handler);
|
||||
};
|
||||
canvas.removeEventListener = (type, handler) => {
|
||||
self.postMessage({command: 'removeEventListener', type});
|
||||
const handlers = eventHandlers.get(type);
|
||||
if (handlers) {
|
||||
handlers.splice(handlers.indexOf(handler), 1);
|
||||
}
|
||||
};
|
||||
canvas.dispatchEvent = (type, event) => {
|
||||
const handlers = eventHandlers.get(type);
|
||||
if (handlers) {
|
||||
handlers.forEach(handler => handler(event));
|
||||
}
|
||||
};
|
||||
|
||||
self.canvas = canvas;
|
||||
}
|
||||
|
||||
self.addEventListener('message', evt => {
|
||||
switch (evt.data.command) {
|
||||
self.onmessage = evt => {
|
||||
const message = evt.data;
|
||||
switch (message.command) {
|
||||
case 'start':
|
||||
initializeCanvas(evt.data.opts.canvas);
|
||||
animationLoop.start(evt.data.opts);
|
||||
initializeCanvas(self, message.opts.canvas);
|
||||
animationLoop.start(message.opts);
|
||||
break;
|
||||
|
||||
case 'stop':
|
||||
@ -55,17 +55,17 @@ export default class AnimationLoopProxy {
|
||||
break;
|
||||
|
||||
case 'resize':
|
||||
self.canvas.width = evt.data.width;
|
||||
self.canvas.height = evt.data.height;
|
||||
self.canvas.width = message.width;
|
||||
self.canvas.height = message.height;
|
||||
break;
|
||||
|
||||
case 'event':
|
||||
self.canvas.dispatchEvent(evt.data.type, evt.data.event);
|
||||
self.canvas.dispatchEvent(message.type, message.event);
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -99,8 +99,6 @@ export default class AnimationLoopProxy {
|
||||
|
||||
this._running = false;
|
||||
this._animationFrameId = null;
|
||||
this._resolveNextFrame = null;
|
||||
this._nextFramePromise = null;
|
||||
|
||||
// bind methods
|
||||
this._onMessage = this._onMessage.bind(this);
|
||||
@ -151,8 +149,6 @@ export default class AnimationLoopProxy {
|
||||
if (this._running) {
|
||||
cancelAnimationFrame(this._animationFrameId);
|
||||
this._animationFrameId = null;
|
||||
this._nextFramePromise = null;
|
||||
this._resolveNextFrame = null;
|
||||
this._running = false;
|
||||
this.props.onFinalize(this);
|
||||
}
|
||||
@ -160,15 +156,6 @@ export default class AnimationLoopProxy {
|
||||
return this;
|
||||
}
|
||||
|
||||
waitForRender() {
|
||||
if (!this._nextFramePromise) {
|
||||
this._nextFramePromise = new Promise(resolve => {
|
||||
this._resolveNextFrame = resolve;
|
||||
});
|
||||
}
|
||||
return this._nextFramePromise;
|
||||
}
|
||||
|
||||
// PRIVATE METHODS
|
||||
|
||||
_onMessage(evt) {
|
||||
@ -210,11 +197,6 @@ export default class AnimationLoopProxy {
|
||||
|
||||
_updateFrame() {
|
||||
this._resizeCanvasDrawingBuffer();
|
||||
if (this._resolveNextFrame) {
|
||||
this._resolveNextFrame(this);
|
||||
this._nextFramePromise = null;
|
||||
this._resolveNextFrame = null;
|
||||
}
|
||||
this._animationFrameId = requestAnimationFrame(this._updateFrame);
|
||||
}
|
||||
|
||||
@ -224,7 +206,7 @@ export default class AnimationLoopProxy {
|
||||
|
||||
// Create an offscreen canvas controlling the main canvas
|
||||
if (!screenCanvas.transferControlToOffscreen) {
|
||||
log.error('OffscreenCanvas is not available in your browser.')(); // eslint-disable-line
|
||||
log.error('OffscreenCanvas is not available in your browser.')();
|
||||
}
|
||||
const offscreenCanvas = screenCanvas.transferControlToOffscreen();
|
||||
|
||||
|
||||
@ -1,12 +1,105 @@
|
||||
import {_AnimationLoopProxy} from '@luma.gl/core';
|
||||
import {AnimationLoop, _AnimationLoopProxy as AnimationLoopProxy} from '@luma.gl/core';
|
||||
import test from 'tape-catch';
|
||||
// import {fixture} from 'test/setup';
|
||||
import {fixture} from 'test/setup';
|
||||
|
||||
test('core#AnimationLoopProxy', t => {
|
||||
// const {gl} = fixture;
|
||||
t.ok(_AnimationLoopProxy);
|
||||
function getMockCanvas() {
|
||||
return {
|
||||
getContext: () => fixture.gl
|
||||
};
|
||||
}
|
||||
|
||||
test('core#AnimationLoopProxy.createWorker', t => {
|
||||
const mockWorkerContext = {};
|
||||
|
||||
const animationLoop = new AnimationLoop();
|
||||
|
||||
const getWorker = AnimationLoopProxy.createWorker(animationLoop);
|
||||
t.ok(typeof getWorker === 'function', 'createWorker returns function');
|
||||
|
||||
getWorker(mockWorkerContext);
|
||||
t.ok(typeof mockWorkerContext.onmessage === 'function', 'worker is initialized');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('core#AnimationLoopProxy#events', t => {
|
||||
// create mock worker context
|
||||
const outboundMessages = [];
|
||||
const mockWorkerContext = {
|
||||
postMessage: data => outboundMessages.push(data)
|
||||
};
|
||||
|
||||
// create mock canvas
|
||||
const mockCanvas = getMockCanvas();
|
||||
const clickCalled = [];
|
||||
const onClick = evt => clickCalled.push(evt);
|
||||
|
||||
const animationLoop = new AnimationLoop();
|
||||
|
||||
AnimationLoopProxy.createWorker(animationLoop)(mockWorkerContext);
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'start',
|
||||
opts: {canvas: mockCanvas}
|
||||
}
|
||||
});
|
||||
|
||||
mockCanvas.addEventListener('click', onClick);
|
||||
t.deepEqual(
|
||||
outboundMessages.pop(),
|
||||
{command: 'addEventListener', type: 'click'},
|
||||
'notifies main thread'
|
||||
);
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'event',
|
||||
type: 'click',
|
||||
event: {id: 1}
|
||||
}
|
||||
});
|
||||
t.deepEqual(clickCalled, [{id: 1}], 'event is handled');
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'event',
|
||||
type: 'hover',
|
||||
event: {id: 2}
|
||||
}
|
||||
});
|
||||
t.deepEqual(clickCalled, [{id: 1}], 'event is not handled');
|
||||
|
||||
mockCanvas.removeEventListener('click', onClick);
|
||||
t.deepEqual(
|
||||
outboundMessages.pop(),
|
||||
{command: 'removeEventListener', type: 'click'},
|
||||
'notifies main thread'
|
||||
);
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'event',
|
||||
type: 'hover',
|
||||
event: {id: 3}
|
||||
}
|
||||
});
|
||||
t.deepEqual(clickCalled, [{id: 1}], 'event is not handled');
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'resize',
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
});
|
||||
t.is(mockCanvas.width, 100, 'canvas size is updated');
|
||||
|
||||
mockWorkerContext.onmessage({
|
||||
data: {
|
||||
command: 'stop'
|
||||
}
|
||||
});
|
||||
|
||||
// const animationLoop = new _AnimationLoopProxy(gl).start().stop();
|
||||
// animationLoop.delete();
|
||||
t.end();
|
||||
});
|
||||
|
||||
1
test/apps/webpack.config.local.js
Normal file
1
test/apps/webpack.config.local.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require('../../examples/webpack.config.local');
|
||||
@ -1,14 +1,7 @@
|
||||
import {_AnimationLoopProxy as AnimationLoopProxy} from '@luma.gl/core';
|
||||
import createWorker from 'webworkify-webpack';
|
||||
|
||||
// Required by webworkify-webpack :(
|
||||
const worker = createWorker(require.resolve('./worker'));
|
||||
const worker = new Worker('./worker.js');
|
||||
|
||||
const animationLoop = new AnimationLoopProxy(worker);
|
||||
|
||||
export default animationLoop;
|
||||
|
||||
/* global window */
|
||||
if (!window.website) {
|
||||
animationLoop.start();
|
||||
}
|
||||
animationLoop.start();
|
||||
@ -6,8 +6,7 @@
|
||||
"start-local": "webpack-dev-server --env.local --progress --hot --open -d"
|
||||
},
|
||||
"dependencies": {
|
||||
"luma.gl": "^5.2.0",
|
||||
"webworkify-webpack": "^2.1.0"
|
||||
"luma.gl": "^7.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
const {resolve} = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
const EXAMPLE_DIR = resolve(__dirname, '../../../../examples')
|
||||
|
||||
const CONFIG = {
|
||||
mode: 'development',
|
||||
|
||||
devServer: {
|
||||
// Static assets
|
||||
contentBase: resolve(__dirname, '../../core/picking/')
|
||||
contentBase: resolve(__dirname, 'core/picking/')
|
||||
},
|
||||
|
||||
resolve: {
|
||||
alias: {
|
||||
examples: EXAMPLE_DIR
|
||||
}
|
||||
},
|
||||
|
||||
entry: {
|
||||
@ -16,5 +24,21 @@ const CONFIG = {
|
||||
plugins: [new HtmlWebpackPlugin({title: 'Shadowmap'})]
|
||||
};
|
||||
|
||||
const WORKER_CONFIG = {
|
||||
target: 'webworker',
|
||||
|
||||
entry: {
|
||||
worker: resolve('./worker.js')
|
||||
},
|
||||
|
||||
plugins: []
|
||||
};
|
||||
|
||||
// This line enables bundling against src in this repo rather than installed module
|
||||
module.exports = env => (env ? require('../../webpack.config.local')(CONFIG)(env) : CONFIG);
|
||||
module.exports = env => {
|
||||
const config = env ? require('../../webpack.config.local')(CONFIG)(env) : CONFIG;
|
||||
|
||||
const workerConfig = Object.assign({}, config, WORKER_CONFIG);
|
||||
|
||||
return [config, workerConfig];
|
||||
};
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import {_AnimationLoopProxy as AnimationLoopProxy} from '@luma.gl/core';
|
||||
|
||||
import animationLoop from '../../core/cubemap/app';
|
||||
// import animationLoop from '../../core/fragment/app';
|
||||
// import animationLoop from '../../core/instancing/app';
|
||||
// import animationLoop from '../../core/mandelbrot/app';
|
||||
// import animationLoop from '../../core/picking/app';
|
||||
// import animationLoop from '../../core/shadowmap/app';
|
||||
// import animationLoop from '../../core/transform/app';
|
||||
// import animationLoop from '../../core/transform-feedback/app';
|
||||
// import AnimationLoop from 'examples/core/cubemap/app';
|
||||
// import AnimationLoop from 'examples/core/fragment/app';
|
||||
// import AnimationLoop from 'examples/core/instancing/app';
|
||||
// import AnimationLoop from 'examples/core/mandelbrot/app';
|
||||
// import AnimationLoop from 'examples/core/picking/app';
|
||||
import AnimationLoop from 'examples/core/shadowmap/app';
|
||||
// import AnimationLoop from 'examples/core/transform/app';
|
||||
// import AnimationLoop from 'examples/core/transform-feedback/app';
|
||||
|
||||
export default AnimationLoopProxy.createWorker(animationLoop);
|
||||
export default AnimationLoopProxy.createWorker(new AnimationLoop())(self);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user