UNPKG

@acransac/vtk.js

Version:

Visualization Toolkit for the Web

190 lines (161 loc) 6.38 kB
import macro from 'vtk.js/Sources/macro'; import vtkAbstractWidget from 'vtk.js/Sources/Widgets/Core/AbstractWidget'; import { extractRenderingComponents } from 'vtk.js/Sources/Widgets/Core/WidgetManager'; function NoOp() {} // ---------------------------------------------------------------------------- function vtkAbstractWidgetFactory(publicAPI, model) { model.classHierarchy.push('vtkAbstractWidgetFactory'); // DO NOT share on the model ------------------------------------------------ const viewToWidget = {}; // DO NOT share on the model ------------------------------------------------ // Can be called with just ViewId after the widget has been registered publicAPI.getWidgetForView = ({ viewId, renderer, viewType, initialValues, }) => { if (!viewToWidget[viewId]) { if (!renderer) { return null; } const { interactor, openGLRenderWindow, camera, } = extractRenderingComponents(renderer); const widgetModel = {}; const widgetPublicAPI = { onWidgetChange: publicAPI.onWidgetChange, }; Object.assign(widgetModel, model, { viewType, renderer, camera, openGLRenderWindow, factory: publicAPI, }); macro.safeArrays(widgetModel); vtkAbstractWidget.extend(widgetPublicAPI, widgetModel, initialValues); // Create representations for that view /* eslint-disable no-shadow */ const widgetInitialValues = initialValues; // Avoid shadowing widgetModel.representations = publicAPI .getRepresentationsForViewType(viewType) .map(({ builder, labels, initialValues }) => builder.newInstance({ labels, ...initialValues, ...widgetInitialValues, }) ); /* eslint-enable no-shadow */ widgetModel.representations.forEach((r) => { r.setInputData(widgetModel.widgetState); r.getActors().forEach((actor) => { widgetModel.actorToRepresentationMap.set(actor, r); }); }); model.behavior(widgetPublicAPI, widgetModel); // Forward representation methods ['coincidentTopologyParameters', ...(model.methodsToLink || [])].forEach( (methodName) => { const set = `set${macro.capitalize(methodName)}`; const get = `get${macro.capitalize(methodName)}`; const methods = { [methodName]: [], [set]: [], [get]: [], }; widgetModel.representations.forEach((representation) => { if (representation[methodName]) { methods[methodName].push(representation[methodName]); } if (representation[set]) { methods[set].push(representation[set]); } if (representation[get]) { methods[get].push(representation[get]); } }); Object.keys(methods).forEach((name) => { const calls = methods[name]; if (calls.length === 1) { widgetPublicAPI[name] = calls[0]; } else if (calls.length > 1) { widgetPublicAPI[name] = macro.chain(...calls); } }); } ); // Custom delete to detach from parent widgetPublicAPI.delete = macro.chain(() => { delete viewToWidget[viewId]; }, widgetPublicAPI.delete); widgetPublicAPI.setInteractor(interactor); const viewWidget = Object.freeze(widgetPublicAPI); viewToWidget[viewId] = viewWidget; return viewWidget; } return viewToWidget[viewId]; }; // List of all the views the widget has been registered to. publicAPI.getViewIds = () => Object.keys(viewToWidget); // -------------------------------------------------------------------------- // Widget visibility / enable // -------------------------------------------------------------------------- // Call methods on all its view widgets publicAPI.setVisibility = (value) => { const viewIds = Object.keys(viewToWidget); for (let i = 0; i < viewIds.length; i++) { viewToWidget[viewIds[i]].setVisibility(value); } }; publicAPI.setPickable = (value) => { const viewIds = Object.keys(viewToWidget); for (let i = 0; i < viewIds.length; i++) { viewToWidget[viewIds[i]].setPickable(value); } }; publicAPI.setContextVisibility = (value) => { const viewIds = Object.keys(viewToWidget); for (let i = 0; i < viewIds.length; i++) { viewToWidget[viewIds[i]].setContextVisibility(value); } }; publicAPI.setHandleVisibility = (value) => { const viewIds = Object.keys(viewToWidget); for (let i = 0; i < viewIds.length; i++) { viewToWidget[viewIds[i]].setHandleVisibility(value); } }; // -------------------------------------------------------------------------- // Place Widget API // -------------------------------------------------------------------------- publicAPI.placeWidget = (bounds) => model.widgetState.placeWidget(bounds); publicAPI.getPlaceFactor = () => model.widgetState.getPlaceFactor(); publicAPI.setPlaceFactor = (factor) => model.widgetState.setPlaceFactor(factor); // -------------------------------------------------------------------------- // Event Widget API // -------------------------------------------------------------------------- let unsubscribe = NoOp; publicAPI.delete = macro.chain(publicAPI.delete, () => unsubscribe()); // Defer after object instantiation so model.widgetState actually exist setTimeout(() => { unsubscribe = model.widgetState.onModified(() => publicAPI.invokeWidgetChange(model.widgetState) ).unsubscribe; }, 0); } // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { macro.obj(publicAPI, model); macro.get(publicAPI, model, ['widgetState']); macro.event(publicAPI, model, 'WidgetChange'); vtkAbstractWidgetFactory(publicAPI, model); } // ---------------------------------------------------------------------------- export const newInstance = macro.newInstance(extend, 'vtkAbstractWidget'); // ---------------------------------------------------------------------------- export default { newInstance, extend };