UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

275 lines (251 loc) 8.1 kB
import { m as macro } from '../../macros2.js'; const { vtkErrorMacro } = macro; const PASS_TYPES = ['Build', 'Render']; // ---------------------------------------------------------------------------- // vtkViewNode methods // ---------------------------------------------------------------------------- function vtkViewNode(publicAPI, model) { // Set our className model.classHierarchy.push('vtkViewNode'); /** * Convenient method to move a child to a specific index. * @param {*} child the child to move * @param {*} toIndex the index to move the child to * @returns true if the child was moved, false otherwise */ function moveChild(child, toIndex) { for (let i = 0; i < model.children.length; ++i) { // Start browsing from toIndex + 1 const childIndex = (toIndex + 1 + i) % model.children.length; if (model.children[childIndex] === child) { model.children[childIndex] = model.children[toIndex]; model.children[toIndex] = child; return true; } } return false; } // Builds myself. publicAPI.build = prepass => {}; // Renders myself publicAPI.render = prepass => {}; publicAPI.traverse = renderPass => { // we can choose to do special // traversal here based on pass const passTraversal = renderPass.getTraverseOperation(); const fn = publicAPI[passTraversal]; if (fn) { fn(renderPass); return; } // default traversal publicAPI.apply(renderPass, true); for (let index = 0; index < model.children.length; index++) { model.children[index].traverse(renderPass); } publicAPI.apply(renderPass, false); }; publicAPI.apply = (renderPass, prepass) => { const customRenderPass = publicAPI[renderPass.getOperation()]; if (customRenderPass) { customRenderPass(prepass, renderPass); } }; publicAPI.getViewNodeFor = (dataObject, hint = null) => { if (hint && hint.renderable === dataObject) { return hint; } if (model.renderable === dataObject) { return publicAPI; } for (let index = 0; index < model.children.length; ++index) { const child = model.children[index]; const vn = child.getViewNodeFor(dataObject); if (vn) { return vn; } } return undefined; }; publicAPI.getFirstAncestorOfType = type => { if (!model._parent) { return null; } if (model._parent.isA(type)) { return model._parent; } return model._parent.getFirstAncestorOfType(type); }; publicAPI.getLastAncestorOfType = type => { if (!model._parent) { return null; } const lastAncestor = model._parent.getLastAncestorOfType(type); if (lastAncestor) { return lastAncestor; } if (model._parent.isA(type)) { return model._parent; } return null; }; // add a missing node/child for the passed in renderables. This should // be called only in between prepareNodes and removeUnusedNodes publicAPI.addMissingNode = dobj => { if (!dobj) { return undefined; } // if found just mark as visited const result = model._renderableChildMap.get(dobj); if (result !== undefined) { result.setVisited(true); return result; } // otherwise create a node const newNode = publicAPI.createViewNode(dobj); if (newNode) { newNode.setParent(publicAPI); newNode.setVisited(true); model._renderableChildMap.set(dobj, newNode); model.children.push(newNode); return newNode; } return undefined; }; // add missing nodes/children for the passed in renderables. This should // be called only in between prepareNodes and removeUnusedNodes publicAPI.addMissingNodes = (dataObjs, enforceOrder = false) => { if (!dataObjs || !dataObjs.length) { return; } let nextIndex; for (let index = 0; index < dataObjs.length; ++index) { const dobj = dataObjs[index]; const node = publicAPI.addMissingNode(dobj); if (enforceOrder && node !== undefined) { if (nextIndex === undefined) { // First node can be anywhere nextIndex = model.children.lastIndexOf(node); // node is likely the list child } else if (model.children[nextIndex] !== node) { moveChild(model.children, node); } // Next node must follow current node nextIndex++; } } }; // ability to add children that have no renderable use in the same manner // as addMissingNodes This case is when a normal viewnode wants to // delegate passes to a helper or child that doeasn't map to a clear // renderable or any renderable publicAPI.addMissingChildren = children => { if (!children || !children.length) { return; } for (let index = 0; index < children.length; ++index) { const child = children[index]; const cindex = model.children.indexOf(child); if (cindex === -1) { child.setParent(publicAPI); model.children.push(child); const childRenderable = child.getRenderable(); if (childRenderable) { model._renderableChildMap.set(childRenderable, child); } } child.setVisited(true); } }; publicAPI.removeNode = child => { const childIdx = model.children.findIndex(x => x === child); if (childIdx < 0) { return false; } const renderable = child.getRenderable(); if (renderable) { model._renderableChildMap.delete(renderable); } child.delete(); model.children.splice(childIdx, 1); return true; }; publicAPI.prepareNodes = () => { for (let index = 0; index < model.children.length; ++index) { model.children[index].setVisited(false); } }; publicAPI.setVisited = val => { model.visited = val; }; publicAPI.removeUnusedNodes = () => { let visitedCount = 0; for (let index = 0; index < model.children.length; ++index) { const child = model.children[index]; const visited = child.getVisited(); if (visited) { model.children[visitedCount++] = child; child.setVisited(false); } else { const renderable = child.getRenderable(); if (renderable) { model._renderableChildMap.delete(renderable); } child.delete(); } } model.children.length = visitedCount; }; publicAPI.createViewNode = dataObj => { if (!model.myFactory) { vtkErrorMacro('Cannot create view nodes without my own factory'); return null; } const ret = model.myFactory.createNode(dataObj); if (ret) { ret.setRenderable(dataObj); } return ret; }; const parentDelete = publicAPI.delete; publicAPI.delete = () => { for (let i = 0; i < model.children.length; i++) { model.children[i].delete(); } parentDelete(); }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { // _parent: null, renderable: null, myFactory: null, children: [], visited: false }; // ---------------------------------------------------------------------------- function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API macro.obj(publicAPI, model); macro.event(publicAPI, model, 'event'); model._renderableChildMap = new Map(); macro.get(publicAPI, model, ['visited']); macro.setGet(publicAPI, model, ['_parent', 'renderable', 'myFactory']); macro.getArray(publicAPI, model, ['children']); macro.moveToProtected(publicAPI, model, ['parent']); // Object methods vtkViewNode(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkViewNode'); // ---------------------------------------------------------------------------- var vtkViewNode$1 = { newInstance, extend, PASS_TYPES }; export { vtkViewNode$1 as default };