From 50a4ead1dcda69bba501e4cbe7afa3b92628bd46 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 28 Jan 2018 20:46:07 -0500 Subject: [PATCH] feat(Viewer): Use ViewProxy and ProxyManager to create 3D view --- src/createViewer.js | 59 +++++++++++++++++++++++++++++ src/index.js | 38 +++++++++++-------- src/processFiles.js | 6 +-- src/proxyManagerConfiguration.js | 65 ++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 src/createViewer.js create mode 100644 src/proxyManagerConfiguration.js diff --git a/src/createViewer.js b/src/createViewer.js new file mode 100644 index 00000000..89972653 --- /dev/null +++ b/src/createViewer.js @@ -0,0 +1,59 @@ +import vtkProxyManager from 'vtk.js/Sources/Proxy/Core/ProxyManager'; + +import proxyConfiguration from './proxyManagerConfiguration'; +import userInterface from './userInterface'; + +const STYLE_CONTAINER = { + position: 'relative', + width: '100%', + height: '100%', + minHeight: '200px', + minWidth: '200px', + margin: '0', + padding: '0', + top: '0', + left: '0', + overflow: 'hidden', +}; + +function applyStyle(el, style) { + Object.keys(style).forEach((key) => { + el.style[key] = style[key]; + }); +} + +const proxyManager = vtkProxyManager.newInstance({ proxyConfiguration }); +window.addEventListener('resize', proxyManager.resizeAllViews); + +const createViewer = (rootContainer, { image, use2D, viewerState, config }) => { + userInterface.emptyContainer(rootContainer); + + const container = document.createElement('div'); + const defaultConfig = { + background: [0, 0, 0], + containerStyle: STYLE_CONTAINER, + }; + const renderWindowConfiguration = config || defaultConfig; + userInterface.emptyContainer(container); + applyStyle( + container, + renderWindowConfiguration.containerStyle || STYLE_CONTAINER + ); + rootContainer.appendChild(container); + + const view = proxyManager.createProxy('Views', 'ItkVtkView'); + view.setContainer(container); + view.resize(); + + const imageSource = proxyManager.createProxy('Sources', 'TrivialProducer'); + imageSource.setInputData(image); + imageSource.setName('Image'); + + proxyManager.createRepresentationInAllViews(imageSource); + + proxyManager.renderAllViews(); + + return { view, imageSource }; +}; + +export default createViewer; diff --git a/src/index.js b/src/index.js index 378d88b0..0a984faf 100644 --- a/src/index.js +++ b/src/index.js @@ -46,23 +46,25 @@ export function initializeEmbeddedViewers() { el.style.height = Number.isFinite(Number(height)) ? `${height}px` : height; - createViewerFromUrl(el, el.dataset.url, !!el.dataset.slice).then((viewer) => { - // Background color handling - if (el.dataset.backgroundColor && viewer.renderWindow) { - const color = el.dataset.backgroundColor; - const bgColor = [ - color.slice(0, 2), - color.slice(2, 4), - color.slice(4, 6), - ].map((v) => parseInt(v, 16) / 255); - viewer.renderer.setBackground(bgColor); - } + createViewerFromUrl(el, el.dataset.url, !!el.dataset.slice).then( + (viewer) => { + // Background color handling + if (el.dataset.backgroundColor && viewer.renderWindow) { + const color = el.dataset.backgroundColor; + const bgColor = [ + color.slice(0, 2), + color.slice(2, 4), + color.slice(4, 6), + ].map((v) => parseInt(v, 16) / 255); + viewer.renderer.setBackground(bgColor); + } - // Render - if (viewer.renderWindow && viewer.renderWindow.render) { - viewer.renderWindow.render(); + // Render + if (viewer.renderWindow && viewer.renderWindow.render) { + viewer.renderWindow.render(); + } } - }); + ); } } } @@ -84,7 +86,11 @@ export function processParameters( } if (userParams[keyName]) { - return createViewerFromUrl(myContainer, userParams[keyName], !!userParams.use2D); + return createViewerFromUrl( + myContainer, + userParams[keyName], + !!userParams.use2D + ); } return null; } diff --git a/src/processFiles.js b/src/processFiles.js index 21df79fc..a5634bcb 100644 --- a/src/processFiles.js +++ b/src/processFiles.js @@ -1,9 +1,9 @@ import itkreadImageFile from 'itk/readImageFile'; import itkreadImageDICOMFileSeries from 'itk/readImageDICOMFileSeries'; -import viewers from './viewers'; import userInterface from './userInterface'; import convertItkImageToVtkImage from './convertItkImageToVtkImage'; +import createViewer from './createViewer'; const processFiles = (container, { files, use2D }) => { userInterface.emptyContainer(container); @@ -24,9 +24,9 @@ const processFiles = (container, { files, use2D }) => { const is3D = itkImage.imageType.dimension === 3 && !use2D; resolve( - viewers.createViewer(container, { - type: is3D ? 'volumeRendering' : 'imageRendering', + createViewer(container, { image: imageData, + use2D: !is3D, }) ); }); diff --git a/src/proxyManagerConfiguration.js b/src/proxyManagerConfiguration.js new file mode 100644 index 00000000..a3615bda --- /dev/null +++ b/src/proxyManagerConfiguration.js @@ -0,0 +1,65 @@ +import vtkView from 'vtk.js/Sources/Proxy/Core/ViewProxy'; +import vtkProxySource from 'vtk.js/Sources/Proxy/Core/SourceProxy'; +import vtkGeometryRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/GeometryRepresentationProxy'; +import vtkMoleculeRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/MoleculeRepresentationProxy'; +import vtkVolumeRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/VolumeRepresentationProxy'; +import vtkSliceRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/SliceRepresentationProxy'; +import vtkPiecewiseFunctionProxy from 'vtk.js/Sources/Proxy/Core/PiecewiseFunctionProxy'; +import vtkLookupTableProxy from 'vtk.js/Sources/Proxy/Core/LookupTableProxy'; + +const proxyManagerConfiguration = { + definitions: { + Proxy: { + LookupTable: { + class: vtkLookupTableProxy, + }, + PiecewiseFunction: { + class: vtkPiecewiseFunctionProxy, + }, + }, + Sources: { + TrivialProducer: { + class: vtkProxySource, + options: {}, + }, + }, + Representations: { + Geometry: { + class: vtkGeometryRepresentationProxy, + options: {}, + }, + Slice: { + class: vtkSliceRepresentationProxy, + options: {}, + }, + Volume: { + class: vtkVolumeRepresentationProxy, + options: {}, + }, + Molecule: { + class: vtkMoleculeRepresentationProxy, + options: {}, + }, + }, + Views: { + ItkVtkView: { + class: vtkView, + options: { + axis: 1, // Y + orientation: -1, // Y- (A) + viewUp: [0, 0, 1], // Z+ (S) + useParallelRendering: false, + }, + }, + }, + }, + representations: { + ItkVtkView: { + vtkPolyData: { name: 'Geometry' }, + vtkImageData: { name: 'Volume' }, + vtkMolecule: { name: 'Molecule' }, + }, + }, +}; + +export default proxyManagerConfiguration;