UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

279 lines (231 loc) 8.63 kB
import { m as macro } from '../../../macros2.js'; function vtkViewStream(publicAPI, model) { // Set our className model.classHierarchy.push('vtkViewStream'); // Internal variables model.imageDecodingPool = [new Image(), new Image()]; model.eventPool = []; model.nextPoolImageIndex = 0; model.urlToRevoke = []; model.activeURL = null; model.fps = []; model.lastTime = Date.now(); model.lastImageEvent = null; // -------------------------------------------------------------------------- // Internal methods // -------------------------------------------------------------------------- function imageLoaded(e) { if (model.deleted) return; const id = Number(this.dataset.id); publicAPI.invokeImageReady(model.eventPool[id]); } // -------------------------------------------------------------------------- function prepareDecodingPool(size = 2) { while (model.imageDecodingPool.length < size) { model.imageDecodingPool.push(new Image()); } for (let i = 0; i < model.imageDecodingPool.length; i++) { model.imageDecodingPool[i].dataset.id = i; model.imageDecodingPool[i].onload = imageLoaded; } } // -------------------------------------------------------------------------- function decodeImage(event) { model.eventPool[model.nextPoolImageIndex] = event; event.image = model.imageDecodingPool[model.nextPoolImageIndex++]; model.nextPoolImageIndex %= model.imageDecodingPool.length; event.image.src = event.url; } // -------------------------------------------------------------------------- publicAPI.pushCamera = () => { const focalPoint = model.camera.getReferenceByName('focalPoint'); const viewUp = model.camera.getReferenceByName('viewUp'); const position = model.camera.getReferenceByName('position'); const parallelProjection = model.camera.getParallelProjection(); const viewAngle = model.camera.getViewAngle(); const parallelScale = model.camera.getParallelScale(); let promise = null; if (model.useCameraParameters) { promise = model.protocol.updateCameraParameters(model.viewId, { focalPoint, viewUp, position, parallelProjection, viewAngle, parallelScale }, false); } else { promise = model.protocol.updateCamera(model.viewId, focalPoint, viewUp, position, false); } if (model.isAnimating) { setTimeout(publicAPI.pushCamera, 1000 / model.cameraUpdateRate); } return promise; }; // -------------------------------------------------------------------------- publicAPI.invalidateCache = () => model.protocol.invalidateCache(model.viewId); // -------------------------------------------------------------------------- // PublicAPI // -------------------------------------------------------------------------- publicAPI.render = () => model.protocol.render({ view: model.viewId, size: model.size }); // -------------------------------------------------------------------------- publicAPI.resetCamera = () => model.protocol.resetCamera(model.viewId); // -------------------------------------------------------------------------- publicAPI.startAnimation = () => model.protocol.startAnimation(model.viewId); // -------------------------------------------------------------------------- publicAPI.stopAnimation = () => model.protocol.stopAnimation(model.viewId); // -------------------------------------------------------------------------- publicAPI.setSize = (width, height) => { let changeDetected = false; if (model.size[0] !== width || model.size[1] !== height) { model.size = [width, height]; changeDetected = true; } if (changeDetected) { publicAPI.modified(); if (model.protocol) { return model.protocol.setSize(model.viewId, width, height); } } return Promise.resolve(false); }; // -------------------------------------------------------------------------- publicAPI.startInteraction = () => { const promises = [model.protocol.setQuality(model.viewId, model.interactiveQuality, model.interactiveRatio)]; if (model.camera) { promises.push(publicAPI.startAnimation()); model.isAnimating = true; promises.push(publicAPI.pushCamera()); } return Promise.all(promises); }; // -------------------------------------------------------------------------- publicAPI.endInteraction = () => { const promises = []; promises.push(model.protocol.setQuality(model.viewId, model.stillQuality, model.stillRatio)); if (model.camera) { promises.push(publicAPI.stopAnimation()); model.isAnimating = false; promises.push(publicAPI.pushCamera()); } else { promises.push(publicAPI.render()); } return Promise.all(promises); }; // -------------------------------------------------------------------------- publicAPI.setViewId = id => { if (model.viewId === id || !model.protocol) { return false; } if (model.viewId) { model.protocol.unregisterView(model.viewId); } model.viewId = id; if (model.viewId) { model.protocol.registerView(model.viewId).then(({ viewId }) => { model.viewId = viewId; }); } return true; }; // -------------------------------------------------------------------------- publicAPI.processMessage = msg => { /* eslint-disable eqeqeq */ if (msg.id != model.viewId) { return; } /* eslint-enable eqeqeq */ const imgBlob = new Blob([msg.image], { type: model.mimeType }); if (model.activeURL) { model.urlToRevoke.push(model.activeURL); model.activeURL = null; while (model.urlToRevoke.length > 60) { const url = model.urlToRevoke.shift(); window.URL.revokeObjectURL(url); } } model.activeURL = URL.createObjectURL(imgBlob); const time = Date.now(); const fps = Math.floor(10000 / (time - model.lastTime)) / 10; model.fps.push(fps); model.lastTime = time; model.lastImageEvent = { url: model.activeURL, fps, metadata: { size: msg.size, id: msg.id, memory: msg.memsize, workTime: msg.workTime } }; if (model.decodeImage) { decodeImage(model.lastImageEvent); } else { publicAPI.invokeImageReady(model.lastImageEvent); } // GC fps while (model.fps.length > model.fpsWindowSize) { model.fps.shift(); } }; // -------------------------------------------------------------------------- publicAPI.delete = macro.chain(() => { model.unregisterViewStream(publicAPI); publicAPI.setViewId(null); while (model.urlToRevoke.length) { window.URL.revokeObjectURL(model.urlToRevoke.pop()); } }, publicAPI.delete); // -------------------------------------------------------------------------- // Initialize object // -------------------------------------------------------------------------- prepareDecodingPool(); } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { // protocol: null, // api: null, cameraUpdateRate: 30, decodeImage: true, fpsWindowSize: 250, interactiveQuality: 80, interactiveRatio: 1, isAnimating: false, mimeType: 'image/jpeg', size: [-1, -1], stillQuality: 100, stillRatio: 1, useCameraParameters: false, viewId: null }; // ---------------------------------------------------------------------------- function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); // Object methods macro.obj(publicAPI, model); macro.event(publicAPI, model, 'ImageReady'); macro.get(publicAPI, model, ['viewId', 'size', 'fps', 'lastImageEvent']); macro.setGet(publicAPI, model, ['camera', 'cameraUpdateRate', 'decodeImage', 'fpsWindowSize', 'interactiveQuality', 'interactiveRatio', 'stillQuality', 'stillRatio', 'useCameraParameters']); // Object specific methods vtkViewStream(publicAPI, model); // Blend APIs Object.assign(publicAPI, model.sharedAPI); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkViewStream'); // ---------------------------------------------------------------------------- var ViewStream = { newInstance, extend }; export { ViewStream as default, extend, newInstance };