You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
4.3 KiB

2 years ago
<!-- Licensed under a BSD license. See license.html for license -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Three.js - Offscreen Canvas</title>
<style>
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
#c:focus {
outline: none;
}
</style>
</head>
<body>
<canvas id="c" tabindex="1"></canvas>
</body>
<script type="module">
import {init} from './shared-orbitcontrols.js';
const mouseEventHandler = makeSendPropertiesHandler([
'ctrlKey',
'metaKey',
'shiftKey',
'button',
'pointerType',
'clientX',
'clientY',
'pageX',
'pageY',
]);
const wheelEventHandlerImpl = makeSendPropertiesHandler([
'deltaX',
'deltaY',
]);
const keydownEventHandler = makeSendPropertiesHandler([
'ctrlKey',
'metaKey',
'shiftKey',
'keyCode',
]);
function wheelEventHandler(event, sendFn) {
event.preventDefault();
wheelEventHandlerImpl(event, sendFn);
}
function preventDefaultHandler(event) {
event.preventDefault();
}
function copyProperties(src, properties, dst) {
for (const name of properties) {
dst[name] = src[name];
}
}
function makeSendPropertiesHandler(properties) {
return function sendProperties(event, sendFn) {
const data = {type: event.type};
copyProperties(event, properties, data);
sendFn(data);
};
}
function touchEventHandler(event, sendFn) {
const touches = [];
const data = {type: event.type, touches};
for (let i = 0; i < event.touches.length; ++i) {
const touch = event.touches[i];
touches.push({
pageX: touch.pageX,
pageY: touch.pageY,
});
}
sendFn(data);
}
// The four arrow keys
const orbitKeys = {
'37': true, // left
'38': true, // up
'39': true, // right
'40': true, // down
};
function filteredKeydownEventHandler(event, sendFn) {
const {keyCode} = event;
if (orbitKeys[keyCode]) {
event.preventDefault();
keydownEventHandler(event, sendFn);
}
}
let nextProxyId = 0;
class ElementProxy {
constructor(element, worker, eventHandlers) {
this.id = nextProxyId++;
this.worker = worker;
const sendEvent = (data) => {
this.worker.postMessage({
type: 'event',
id: this.id,
data,
});
};
// register an id
worker.postMessage({
type: 'makeProxy',
id: this.id,
});
sendSize();
for (const [eventName, handler] of Object.entries(eventHandlers)) {
element.addEventListener(eventName, function(event) {
handler(event, sendEvent);
});
}
function sendSize() {
const rect = element.getBoundingClientRect();
sendEvent({
type: 'size',
left: rect.left,
top: rect.top,
width: element.clientWidth,
height: element.clientHeight,
});
}
// really need to use ResizeObserver
window.addEventListener('resize', sendSize);
}
}
function startWorker(canvas) {
canvas.focus();
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('offscreencanvas-worker-orbitcontrols.js', {type: 'module'});
const eventHandlers = {
contextmenu: preventDefaultHandler,
mousedown: mouseEventHandler,
mousemove: mouseEventHandler,
mouseup: mouseEventHandler,
pointerdown: mouseEventHandler,
pointermove: mouseEventHandler,
pointerup: mouseEventHandler,
touchstart: touchEventHandler,
touchmove: touchEventHandler,
touchend: touchEventHandler,
wheel: wheelEventHandler,
keydown: filteredKeydownEventHandler,
};
const proxy = new ElementProxy(canvas, worker, eventHandlers);
worker.postMessage({
type: 'start',
canvas: offscreen,
canvasId: proxy.id,
}, [offscreen]);
console.log('using OffscreenCanvas'); /* eslint-disable-line no-console */
}
function startMainPage(canvas) {
init({canvas, inputElement: canvas});
console.log('using regular canvas'); /* eslint-disable-line no-console */
}
function main() { /* eslint consistent-return: 0 */
const canvas = document.querySelector('#c');
if (canvas.transferControlToOffscreen) {
startWorker(canvas);
} else {
startMainPage(canvas);
}
}
main();
</script>
</html>