feat(resize): Optimize resizing process and maintain zoom level (#3889)
This commit is contained in:
parent
a2a0090eeb
commit
b3a0faf5f5
@ -24,6 +24,8 @@
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-seg": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-seg": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -116,7 +116,6 @@ function OHIFCornerstoneSEGViewport(props) {
|
||||
}}
|
||||
onElementEnabled={onElementEnabled}
|
||||
onElementDisabled={onElementDisabled}
|
||||
// initialImageIndex={initialImageIndex}
|
||||
></Component>
|
||||
);
|
||||
}, [viewportId, segDisplaySet, toolGroupId]);
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-extension"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --progress --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -21,6 +21,7 @@ import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/
|
||||
import CornerstoneServices from '../types/CornerstoneServices';
|
||||
import CinePlayer from '../components/CinePlayer';
|
||||
import { Types } from '@ohif/core';
|
||||
import { LutPresentation, PositionPresentation } from '../types/Presentation';
|
||||
|
||||
const STACK = 'stack';
|
||||
|
||||
@ -101,7 +102,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
viewportOptions,
|
||||
displaySetOptions,
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
onElementEnabled,
|
||||
onElementDisabled,
|
||||
isJumpToMeasurementDisabled,
|
||||
@ -277,7 +277,10 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
// The presentation state will have been stored previously by closing
|
||||
// a viewport. Otherwise, this viewport will be unchanged and the
|
||||
// presentation information will be directly carried over.
|
||||
const { lutPresentationStore, positionPresentationStore } = stateSyncService.getState();
|
||||
const state = stateSyncService.getState();
|
||||
const lutPresentationStore = state.lutPresentationStore as LutPresentation;
|
||||
const positionPresentationStore = state.positionPresentationStore as PositionPresentation;
|
||||
|
||||
const { presentationIds } = viewportOptions;
|
||||
const presentations = {
|
||||
positionPresentation: positionPresentationStore[presentationIds?.positionPresentationId],
|
||||
@ -360,8 +363,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
||||
<React.Fragment>
|
||||
<div className="viewport-wrapper">
|
||||
<ReactResizeDetector
|
||||
refreshMode="debounce"
|
||||
refreshRate={50} // Wait 50 ms after last move to render
|
||||
onResize={onResize}
|
||||
targetRef={elementRef.current}
|
||||
/>
|
||||
|
||||
@ -204,6 +204,16 @@ export default async function init({
|
||||
}
|
||||
);
|
||||
|
||||
// resize the cornerstone viewport service when the grid size changes
|
||||
// IMPORTANT: this should happen outside of the OHIFCornerstoneViewport
|
||||
// since it will trigger a rerender of each viewport and each resizing
|
||||
// the offscreen canvas which would result in a performance hit, this should
|
||||
// done only once per grid resize here. Doing it once here, allows us to reduce
|
||||
// the refreshRage(in ms) to 10 from 50. I tried with even 1 or 5 ms it worked fine
|
||||
viewportGridService.subscribe(viewportGridService.EVENTS.GRID_SIZE_CHANGED, () => {
|
||||
cornerstoneViewportService.resize(true);
|
||||
});
|
||||
|
||||
initContextMenu({
|
||||
cornerstoneViewportService,
|
||||
customizationService,
|
||||
|
||||
@ -67,4 +67,4 @@ type SegmentationRepresentationData = {
|
||||
LABELMAP?: LabelmapSegmentationData;
|
||||
};
|
||||
|
||||
export { SegmentationConfig, Segment, Segmentation };
|
||||
export type { SegmentationConfig, Segment, Segmentation };
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
VolumeViewport3D,
|
||||
cache,
|
||||
Enums as csEnums,
|
||||
BaseVolumeViewport,
|
||||
} from '@cornerstonejs/core';
|
||||
|
||||
import { utilities as csToolsUtils, Enums as csToolsEnums } from '@cornerstonejs/tools';
|
||||
@ -17,7 +18,7 @@ import { IViewportService } from './IViewportService';
|
||||
import { RENDERING_ENGINE_ID } from './constants';
|
||||
import ViewportInfo, { DisplaySetOptions, PublicViewportOptions } from './Viewport';
|
||||
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
|
||||
import { Presentation, Presentations } from '../../types/Presentation';
|
||||
import { LutPresentation, PositionPresentation, Presentations } from '../../types/Presentation';
|
||||
|
||||
import JumpPresets from '../../utils/JumpPresets';
|
||||
|
||||
@ -44,6 +45,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewportsById: Map<string, ViewportInfo> = new Map();
|
||||
viewportGridResizeObserver: ResizeObserver | null;
|
||||
viewportsDisplaySets: Map<string, string[]> = new Map();
|
||||
beforeResizePositionPresentations: Map<string, PositionPresentation> = new Map();
|
||||
|
||||
// Some configs
|
||||
enableResizeDetector: true;
|
||||
@ -51,6 +53,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
resizeRefreshMode: 'debounce';
|
||||
servicesManager = null;
|
||||
|
||||
resizeQueue = [];
|
||||
viewportResizeTimer = null;
|
||||
gridResizeDelay = 50;
|
||||
gridResizeTimeOut = null;
|
||||
|
||||
constructor(servicesManager: ServicesManager) {
|
||||
super(EVENTS);
|
||||
this.renderingEngine = null;
|
||||
@ -94,14 +101,28 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
}
|
||||
|
||||
/**
|
||||
* It triggers the resize on the rendering engine.
|
||||
* It triggers the resize on the rendering engine, and renders the viewports
|
||||
*
|
||||
* @param isGridResize - if the resize is triggered by a grid resize
|
||||
* this is used to avoid double resize of the viewports since if the
|
||||
* grid is resized, all viewports will be resized so there is no need
|
||||
* to resize them individually which will get triggered by their
|
||||
* individual resize observers
|
||||
*/
|
||||
public resize() {
|
||||
const immediate = true;
|
||||
const keepCamera = true;
|
||||
|
||||
this.renderingEngine.resize(immediate, keepCamera);
|
||||
this.renderingEngine.render();
|
||||
public resize(isGridResize = false) {
|
||||
// if there is a grid resize happening, it means the viewport grid
|
||||
// has been manipulated (e.g., panels closed, added, etc.) and we need
|
||||
// to resize all viewports, so we will add a timeout here to make sure
|
||||
// we don't double resize the viewports when viewports in the grid are
|
||||
// resized individually
|
||||
if (isGridResize) {
|
||||
this.performResize();
|
||||
this.resetGridResizeTimeout();
|
||||
this.resizeQueue = [];
|
||||
clearTimeout(this.viewportResizeTimer);
|
||||
} else {
|
||||
this.enqueueViewportResizeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,97 +159,239 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
this.viewportsDisplaySets.delete(viewportId);
|
||||
}
|
||||
|
||||
public setPresentations(viewport, presentations?: Presentations): void {
|
||||
const properties = presentations?.lutPresentation?.properties;
|
||||
if (properties) {
|
||||
viewport.setProperties(properties);
|
||||
/**
|
||||
* Sets the presentations for a given viewport. Presentations is an object
|
||||
* that can define the lut or position for a viewport.
|
||||
*
|
||||
* @param viewportId - The ID of the viewport.
|
||||
* @param presentations - The presentations to apply to the viewport.
|
||||
*/
|
||||
public setPresentations(viewportId: string, presentations?: Presentations): void {
|
||||
const viewport = this.getCornerstoneViewport(viewportId) as
|
||||
| Types.IStackViewport
|
||||
| Types.IVolumeViewport;
|
||||
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
const camera = presentations?.positionPresentation?.camera;
|
||||
if (camera) {
|
||||
viewport.setCamera(camera);
|
||||
|
||||
if (!presentations) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { lutPresentation, positionPresentation } = presentations;
|
||||
if (lutPresentation) {
|
||||
const { presentation } = lutPresentation;
|
||||
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
Object.entries(presentation).forEach(
|
||||
([volumeId, properties]: [string, Types.ViewportProperties]) => {
|
||||
viewport.setProperties(properties, volumeId);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
viewport.setProperties(presentation);
|
||||
}
|
||||
}
|
||||
|
||||
if (positionPresentation) {
|
||||
const { viewPlaneNormal, viewUp, zoom, pan } = positionPresentation.presentation;
|
||||
viewport.setCamera({ viewPlaneNormal, viewUp });
|
||||
|
||||
if (zoom !== undefined) {
|
||||
viewport.setZoom(zoom);
|
||||
}
|
||||
|
||||
if (pan !== undefined) {
|
||||
viewport.setPan(pan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getPresentation(viewportId: string): Presentation {
|
||||
/**
|
||||
* Retrieves the position presentation information for a given viewport.
|
||||
* @param viewportId The ID of the viewport.
|
||||
* @returns The position presentation object containing various properties
|
||||
* such as ID, viewport type, initial image index, view plane normal, view up, zoom, and pan.
|
||||
*/
|
||||
public getPositionPresentation(viewportId: string): PositionPresentation {
|
||||
const viewportInfo = this.viewportsById.get(viewportId);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
const { viewportType, presentationIds } = viewportInfo.getViewportOptions();
|
||||
|
||||
const presentationIds = viewportInfo.getPresentationIds();
|
||||
|
||||
if (!presentationIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { positionPresentationId } = presentationIds;
|
||||
|
||||
const csViewport = this.getCornerstoneViewport(viewportId);
|
||||
if (!csViewport) {
|
||||
return;
|
||||
}
|
||||
|
||||
const properties = csViewport.getProperties();
|
||||
if (properties.isComputedVOI) {
|
||||
delete properties.voiRange;
|
||||
delete properties.VOILUTFunction;
|
||||
}
|
||||
const { viewPlaneNormal, viewUp } = csViewport.getCamera();
|
||||
const initialImageIndex = csViewport.getCurrentImageIdIndex();
|
||||
const camera = csViewport.getCamera();
|
||||
const zoom = csViewport.getZoom();
|
||||
const pan = csViewport.getPan();
|
||||
|
||||
return {
|
||||
presentationIds,
|
||||
viewportType: !viewportType || viewportType === 'stack' ? 'stack' : 'volume',
|
||||
properties,
|
||||
initialImageIndex,
|
||||
camera,
|
||||
id: positionPresentationId,
|
||||
viewportType: viewportInfo.getViewportType(),
|
||||
presentation: {
|
||||
initialImageIndex,
|
||||
viewUp,
|
||||
viewPlaneNormal,
|
||||
zoom,
|
||||
pan,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public storePresentation({ viewportId }) {
|
||||
const { stateSyncService, syncGroupService } = this.servicesManager.services;
|
||||
let presentation;
|
||||
try {
|
||||
presentation = this.getPresentation(viewportId);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
|
||||
if (!presentation || !presentation.presentationIds) {
|
||||
/**
|
||||
* Retrieves the LUT (Lookup Table) presentation for a given viewport.
|
||||
* @param viewportId The ID of the viewport.
|
||||
* @returns The LUT presentation object, or undefined if the viewport does not exist.
|
||||
*/
|
||||
public getLutPresentation(viewportId: string): LutPresentation {
|
||||
const viewportInfo = this.viewportsById.get(viewportId);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const presentationIds = viewportInfo.getPresentationIds();
|
||||
|
||||
if (!presentationIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { lutPresentationId } = presentationIds;
|
||||
|
||||
const csViewport = this.getCornerstoneViewport(viewportId) as
|
||||
| Types.IStackViewport
|
||||
| Types.IVolumeViewport;
|
||||
|
||||
if (!csViewport) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanProperties = properties => {
|
||||
if (properties.isComputedVOI) {
|
||||
delete properties.voiRange;
|
||||
delete properties.VOILUTFunction;
|
||||
}
|
||||
return properties;
|
||||
};
|
||||
|
||||
const presentation =
|
||||
csViewport instanceof BaseVolumeViewport
|
||||
? new Map()
|
||||
: cleanProperties(csViewport.getProperties());
|
||||
|
||||
if (presentation instanceof Map) {
|
||||
csViewport.getActors().forEach(({ uid: volumeId }) => {
|
||||
const properties = cleanProperties(csViewport.getProperties(volumeId));
|
||||
presentation.set(volumeId, properties);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
id: lutPresentationId,
|
||||
viewportType: viewportInfo.getViewportType(),
|
||||
presentation,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presentations for a given viewport.
|
||||
* @param viewportId - The ID of the viewport.
|
||||
* @returns The presentations for the viewport.
|
||||
*/
|
||||
public getPresentations(viewportId: string): Presentations {
|
||||
const viewportInfo = this.viewportsById.get(viewportId);
|
||||
if (!viewportInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const positionPresentation = this.getPositionPresentation(viewportId);
|
||||
const lutPresentation = this.getLutPresentation(viewportId);
|
||||
|
||||
return {
|
||||
positionPresentation,
|
||||
lutPresentation,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the presentation state for a given viewport inside the
|
||||
* stateSyncService. This is used to persist the presentation state
|
||||
* across different scenarios e.g., when the viewport is changing the
|
||||
* display set, or when the viewport is moving to a different layout.
|
||||
*
|
||||
* @param viewportId The ID of the viewport.
|
||||
*/
|
||||
public storePresentation({ viewportId }) {
|
||||
let presentations = null as Presentations;
|
||||
try {
|
||||
presentations = this.getPresentations(viewportId);
|
||||
if (!presentations?.positionPresentation && !presentations?.lutPresentation) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const { stateSyncService, syncGroupService } = this.servicesManager.services;
|
||||
|
||||
const synchronizers = syncGroupService.getSynchronizersForViewport(
|
||||
viewportId,
|
||||
this.renderingEngine.id
|
||||
);
|
||||
|
||||
const { lutPresentationStore, positionPresentationStore, synchronizersStore } =
|
||||
const { positionPresentationStore, synchronizersStore, lutPresentationStore } =
|
||||
stateSyncService.getState();
|
||||
const { presentationIds } = presentation;
|
||||
const { lutPresentationId, positionPresentationId } = presentationIds || {};
|
||||
const storeState = {};
|
||||
|
||||
const { lutPresentation, positionPresentation } = presentations;
|
||||
const { id: positionPresentationId } = positionPresentation;
|
||||
const { id: lutPresentationId } = lutPresentation;
|
||||
|
||||
const updateStore = (store, id, value) => ({ ...store, [id]: value });
|
||||
|
||||
const newState = {} as { [key: string]: any };
|
||||
|
||||
if (lutPresentationId) {
|
||||
storeState.lutPresentationStore = {
|
||||
...lutPresentationStore,
|
||||
[lutPresentationId]: presentation,
|
||||
};
|
||||
newState.lutPresentationStore = updateStore(
|
||||
lutPresentationStore,
|
||||
lutPresentationId,
|
||||
lutPresentation
|
||||
);
|
||||
}
|
||||
|
||||
if (positionPresentationId) {
|
||||
storeState.positionPresentationStore = {
|
||||
...positionPresentationStore,
|
||||
[positionPresentationId]: presentation,
|
||||
};
|
||||
newState.positionPresentationStore = updateStore(
|
||||
positionPresentationStore,
|
||||
positionPresentationId,
|
||||
positionPresentation
|
||||
);
|
||||
}
|
||||
|
||||
if (synchronizers?.length) {
|
||||
storeState.synchronizersStore = {
|
||||
...synchronizersStore,
|
||||
[viewportId]: synchronizers.map(synchronizer => {
|
||||
const sourceViewports = synchronizer.getSourceViewports();
|
||||
const targetViewports = synchronizer.getTargetViewports();
|
||||
return {
|
||||
id: synchronizer.id,
|
||||
sourceViewports: [...sourceViewports],
|
||||
targetViewports: [...targetViewports],
|
||||
};
|
||||
}),
|
||||
};
|
||||
newState.synchronizersStore = updateStore(
|
||||
synchronizersStore,
|
||||
viewportId,
|
||||
synchronizers.map(synchronizer => ({
|
||||
id: synchronizer.id,
|
||||
sourceViewports: [...synchronizer.getSourceViewports()],
|
||||
targetViewports: [...synchronizer.getTargetViewports()],
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
stateSyncService.store(storeState);
|
||||
stateSyncService.store(newState);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -324,9 +487,13 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
});
|
||||
}
|
||||
|
||||
public getCornerstoneViewport(
|
||||
viewportId: string
|
||||
): Types.IStackViewport | Types.IVolumeViewport | null {
|
||||
/**
|
||||
* Retrieves the Cornerstone viewport with the specified ID.
|
||||
*
|
||||
* @param viewportId - The ID of the viewport.
|
||||
* @returns The Cornerstone viewport object if found, otherwise null.
|
||||
*/
|
||||
public getCornerstoneViewport(viewportId: string): Types.IViewport | null {
|
||||
const viewportInfo = this.getViewportInfo(viewportId);
|
||||
|
||||
if (!viewportInfo || !this.renderingEngine || this.renderingEngine.hasBeenDestroyed) {
|
||||
@ -338,15 +505,51 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
return viewport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the viewport information for a given viewport ID. The viewport information
|
||||
* is the OHIF construct that holds different options and data for a given viewport and
|
||||
* is different from the cornerstone viewport.
|
||||
*
|
||||
* @param viewportId The ID of the viewport.
|
||||
* @returns The viewport information.
|
||||
*/
|
||||
public getViewportInfo(viewportId: string): ViewportInfo {
|
||||
return this.viewportsById.get(viewportId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the viewports to see if the specified measurement can be
|
||||
* displayed in one of the viewports.
|
||||
*
|
||||
* @param measurement
|
||||
* The measurement that is desired to view.
|
||||
* @param activeViewportId - the index that was active at the time the jump
|
||||
* was initiated.
|
||||
* @return the viewportId that the measurement should be displayed in.
|
||||
*/
|
||||
public getViewportIdToJump(
|
||||
activeViewportId: string,
|
||||
displaySetInstanceUID: string,
|
||||
cameraProps: unknown
|
||||
): string {
|
||||
const viewportInfo = this.getViewportInfo(activeViewportId);
|
||||
const { referencedImageId } = cameraProps;
|
||||
if (viewportInfo?.contains(displaySetInstanceUID, referencedImageId)) {
|
||||
return activeViewportId;
|
||||
}
|
||||
|
||||
return (
|
||||
[...this.viewportsById.values()].find(viewportInfo =>
|
||||
viewportInfo.contains(displaySetInstanceUID, referencedImageId)
|
||||
)?.viewportId ?? null
|
||||
);
|
||||
}
|
||||
|
||||
private async _setStackViewport(
|
||||
viewport: Types.IStackViewport,
|
||||
viewportData: StackViewportData,
|
||||
viewportInfo: ViewportInfo,
|
||||
presentations: Presentations
|
||||
presentations: Presentations = {}
|
||||
): Promise<void> {
|
||||
const displaySetOptions = viewportInfo.getDisplaySetOptions();
|
||||
|
||||
@ -383,10 +586,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
|
||||
return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
||||
viewport.setProperties({ ...properties });
|
||||
const camera = presentations.positionPresentation?.camera;
|
||||
if (camera) {
|
||||
viewport.setCamera(camera);
|
||||
}
|
||||
this.setPresentations(viewport.id, presentations);
|
||||
});
|
||||
}
|
||||
|
||||
@ -454,7 +654,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewport: Types.IVolumeViewport,
|
||||
viewportData: VolumeViewportData,
|
||||
viewportInfo: ViewportInfo,
|
||||
presentations: Presentations
|
||||
presentations: Presentations = {}
|
||||
): Promise<void> {
|
||||
// TODO: We need to overhaul the way data sources work so requests can be made
|
||||
// async. I think we should follow the image loader pattern which is async and
|
||||
@ -558,7 +758,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewport.setProperties(properties, volumeId);
|
||||
});
|
||||
|
||||
this.setPresentations(viewport, presentations);
|
||||
this.setPresentations(viewport.id, presentations);
|
||||
|
||||
// load any secondary displaySets
|
||||
const displaySetInstanceUIDs = this.viewportsDisplaySets.get(viewport.id);
|
||||
@ -712,7 +912,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
}
|
||||
|
||||
_setDisplaySets(
|
||||
viewport: StackViewport | VolumeViewport,
|
||||
viewport: Types.IViewport,
|
||||
viewportData: StackViewportData | VolumeViewportData,
|
||||
viewportInfo: ViewportInfo,
|
||||
presentations: Presentations = {}
|
||||
@ -724,16 +924,18 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewportInfo,
|
||||
presentations
|
||||
);
|
||||
} else if (viewport instanceof VolumeViewport || viewport instanceof VolumeViewport3D) {
|
||||
}
|
||||
|
||||
if ([VolumeViewport, VolumeViewport3D].some(type => viewport instanceof type)) {
|
||||
return this._setVolumeViewport(
|
||||
viewport,
|
||||
viewport as Types.IVolumeViewport,
|
||||
viewportData as VolumeViewportData,
|
||||
viewportInfo,
|
||||
presentations
|
||||
);
|
||||
} else {
|
||||
throw new Error('Unknown viewport type');
|
||||
}
|
||||
|
||||
throw new Error('Unknown viewport type');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -763,8 +965,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
const { dimensions } = imageVolume;
|
||||
const slabThickness = Math.sqrt(
|
||||
dimensions[0] * dimensions[0] +
|
||||
dimensions[1] * dimensions[1] +
|
||||
dimensions[2] * dimensions[2]
|
||||
dimensions[1] * dimensions[1] +
|
||||
dimensions[2] * dimensions[2]
|
||||
);
|
||||
|
||||
return slabThickness;
|
||||
@ -799,32 +1001,57 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the viewports to see if the specified measurement can be
|
||||
* displayed in one of the viewports.
|
||||
*
|
||||
* @param measurement
|
||||
* The measurement that is desired to view.
|
||||
* @param activeViewportId - the index that was active at the time the jump
|
||||
* was initiated.
|
||||
* @return the viewportId that the measurement should be displayed in.
|
||||
*/
|
||||
public getViewportIdToJump(
|
||||
activeViewportId: string,
|
||||
displaySetInstanceUID: string,
|
||||
cameraProps: unknown
|
||||
): string {
|
||||
const viewportInfo = this.getViewportInfo(activeViewportId);
|
||||
const { referencedImageId } = cameraProps;
|
||||
if (viewportInfo?.contains(displaySetInstanceUID, referencedImageId)) {
|
||||
return activeViewportId;
|
||||
private enqueueViewportResizeRequest() {
|
||||
this.resizeQueue.push(false); // false indicates viewport resize
|
||||
|
||||
clearTimeout(this.viewportResizeTimer);
|
||||
this.viewportResizeTimer = setTimeout(() => {
|
||||
this.processViewportResizeQueue();
|
||||
}, this.gridResizeDelay);
|
||||
}
|
||||
|
||||
private processViewportResizeQueue() {
|
||||
const isGridResizeInQueue = this.resizeQueue.some(isGridResize => isGridResize);
|
||||
if (this.resizeQueue.length > 0 && !isGridResizeInQueue && !this.gridResizeTimeOut) {
|
||||
this.performResize();
|
||||
}
|
||||
|
||||
return (
|
||||
[...this.viewportsById.values()].find(viewportInfo =>
|
||||
viewportInfo.contains(displaySetInstanceUID, referencedImageId)
|
||||
)?.viewportId ?? null
|
||||
);
|
||||
// Clear the queue after processing viewport resizes
|
||||
this.resizeQueue = [];
|
||||
}
|
||||
|
||||
private performResize() {
|
||||
const isImmediate = false;
|
||||
|
||||
const viewports = this.getRenderingEngine().getViewports();
|
||||
|
||||
// Store the current position presentations for each viewport.
|
||||
viewports.forEach(({ id }) => {
|
||||
const presentation = this.getPositionPresentation(id);
|
||||
this.beforeResizePositionPresentations.set(id, presentation);
|
||||
});
|
||||
|
||||
// Resize the rendering engine and render.
|
||||
const renderingEngine = this.renderingEngine;
|
||||
renderingEngine.resize(isImmediate);
|
||||
renderingEngine.render();
|
||||
|
||||
// Reset the camera for viewports that should reset their camera on resize,
|
||||
// which means only those viewports that have a zoom level of 1.
|
||||
this.beforeResizePositionPresentations.forEach((positionPresentation, viewportId) => {
|
||||
this.setPresentations(viewportId, { positionPresentation });
|
||||
});
|
||||
|
||||
// Resize and render the rendering engine again.
|
||||
renderingEngine.resize(isImmediate);
|
||||
renderingEngine.render();
|
||||
}
|
||||
|
||||
private resetGridResizeTimeout() {
|
||||
clearTimeout(this.gridResizeTimeOut);
|
||||
this.gridResizeTimeOut = setTimeout(() => {
|
||||
this.gridResizeTimeOut = null;
|
||||
}, this.gridResizeDelay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Types } from '@cornerstonejs/core';
|
||||
import { StackData, VolumeData } from '../../types/CornerstoneCacheService';
|
||||
import { DisplaySetOptions, PublicViewportOptions, ViewportOptions } from './Viewport';
|
||||
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
|
||||
import { DisplaySetOptions, PublicViewportOptions } from './Viewport';
|
||||
import { Presentations } from '../../types/Presentation';
|
||||
|
||||
/**
|
||||
* Handles cornerstone viewport logic including enabling, disabling, and
|
||||
@ -36,7 +37,7 @@ export interface IViewportService {
|
||||
* the element for resizing events
|
||||
* @param {*} elementRef
|
||||
*/
|
||||
resize(element: HTMLDivElement): void;
|
||||
resize(isGridResize: boolean): void;
|
||||
/**
|
||||
* Removes the viewport from cornerstone, and destroys the rendering engine
|
||||
*/
|
||||
@ -55,8 +56,10 @@ export interface IViewportService {
|
||||
* @returns
|
||||
*/
|
||||
setViewportData(
|
||||
viewportData: StackData | VolumeData,
|
||||
viewportId: string,
|
||||
viewportData: StackViewportData | VolumeViewportData,
|
||||
publicViewportOptions: PublicViewportOptions,
|
||||
publicDisplaySetOptions: DisplaySetOptions[]
|
||||
publicDisplaySetOptions: DisplaySetOptions[],
|
||||
presentations?: Presentations
|
||||
): void;
|
||||
}
|
||||
|
||||
@ -238,6 +238,11 @@ class ViewportInfo {
|
||||
return this.viewportOptions;
|
||||
}
|
||||
|
||||
public getPresentationIds(): CoreTypes.PresentationIds {
|
||||
const { presentationIds } = this.viewportOptions;
|
||||
return presentationIds;
|
||||
}
|
||||
|
||||
public setDisplaySetOptions(displaySetOptions: Array<DisplaySetOptions>): void {
|
||||
this.displaySetOptions = displaySetOptions;
|
||||
}
|
||||
|
||||
@ -1,23 +1,45 @@
|
||||
/** Store presentation data for either stack viewports or volume viewports */
|
||||
import { Types } from '@cornerstonejs/core';
|
||||
import { Types as CoreTypes } from '@ohif/core';
|
||||
import type { Types } from '@cornerstonejs/core';
|
||||
|
||||
/**
|
||||
* Has information on the presentation of the viewport.
|
||||
* Represents a position presentation in a viewport. This is basically
|
||||
* viewport specific camera position and zoom, and not the display set
|
||||
*/
|
||||
export interface Presentation extends Types.StackViewportProperties {
|
||||
presentationIds: CoreTypes.PresentationIds;
|
||||
export type PositionPresentation = {
|
||||
id: string;
|
||||
viewportType: string;
|
||||
initialImageIndex: number;
|
||||
camera: Types.ICamera;
|
||||
properties: Types.StackViewportProperties | Types.VolumeViewportProperties;
|
||||
zoom?: number;
|
||||
pan?: [number, number];
|
||||
presentation: {
|
||||
initialImageIndex: number;
|
||||
viewUp: Types.Point3;
|
||||
viewPlaneNormal: Types.Point3;
|
||||
zoom?: number;
|
||||
pan?: Types.Point2;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a LUT presentation in a viewport, and is really related
|
||||
* to displaySets and not the viewport itself. So that is why it can
|
||||
* be an object with volumeId keys, or a single object with the properties
|
||||
* itself
|
||||
*/
|
||||
export interface LutPresentation {
|
||||
id: string;
|
||||
viewportType: string;
|
||||
presentation: Record<string, Types.ViewportProperties> | Types.ViewportProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Presentation can be a PositionPresentation or a LutPresentation.
|
||||
*/
|
||||
type Presentation = PositionPresentation | LutPresentation;
|
||||
|
||||
/**
|
||||
* Viewport presentations object that can contain a positionPresentation
|
||||
* and or a lutPresentation.
|
||||
*/
|
||||
export type Presentations = {
|
||||
positionPresentation?: Presentation;
|
||||
lutPresentation?: Presentation;
|
||||
positionPresentation?: PositionPresentation;
|
||||
lutPresentation?: LutPresentation;
|
||||
};
|
||||
|
||||
export default Presentation;
|
||||
|
||||
@ -93,6 +93,7 @@ const CornerstoneViewportDownloadForm = ({
|
||||
renderingEngine.resize();
|
||||
|
||||
// Trigger the render on the viewport to update the on screen
|
||||
downloadViewport.resetCamera();
|
||||
downloadViewport.render();
|
||||
|
||||
downloadViewportElement.addEventListener(
|
||||
@ -223,7 +224,6 @@ const CornerstoneViewportDownloadForm = ({
|
||||
minimumSize={MINIMUM_SIZE}
|
||||
maximumSize={MAX_TEXTURE_SIZE}
|
||||
defaultSize={DEFAULT_SIZE}
|
||||
canvasClass={'cornerstone-canvas'}
|
||||
activeViewportElement={activeViewportElement}
|
||||
enableViewport={enableViewport}
|
||||
disableViewport={disableViewport}
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-extension"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-pdf": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-pdf": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-extension"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-pdf": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-mode"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-mode"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
"yarn": ">=1.16.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
"yarn": ">=1.16.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
"ohif-mode"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
"build:dev": "lerna run build:dev --stream",
|
||||
"build:ci": "lerna run build:viewer:ci --stream",
|
||||
"build:qa": "lerna run build:viewer:qa --stream",
|
||||
"clean": "npx lerna run clean --stream",
|
||||
"clean:deep": "npx lerna run clean:deep --stream",
|
||||
"cli": "node ./platform/cli/src/index.js",
|
||||
"build:ui:deploy-preview": "lerna run build:ui:deploy-preview --stream",
|
||||
"build:demo": "lerna run build:viewer:demo --stream",
|
||||
@ -127,6 +129,7 @@
|
||||
"semver": "^7.5.1",
|
||||
"serve": "^14.2.0",
|
||||
"shader-loader": "^1.3.1",
|
||||
"shx": "^0.3.3",
|
||||
"source-map-loader": "^4.0.1",
|
||||
"start-server-and-test": "^1.10.0",
|
||||
"style-loader": "^1.0.0",
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
"build:viewer:qa": "cross-env NODE_ENV=production APP_CONFIG=config/google.js yarn run build",
|
||||
"build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html QUICK_BUILD=false yarn run build",
|
||||
"build": "node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js",
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack serve --config .webpack/webpack.pwa.js",
|
||||
"dev:no:cache": "cross-env NODE_ENV=development webpack serve --no-cache --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack serve --config .webpack/webpack.pwa.js",
|
||||
@ -52,6 +54,7 @@
|
||||
"@cornerstonejs/codec-openjpeg": "^1.2.2",
|
||||
"@cornerstonejs/codec-openjph": "^2.4.5",
|
||||
"@cornerstonejs/dicom-image-loader": "^1.44.1",
|
||||
"@emotion/serialize": "^1.1.3",
|
||||
"@ohif/core": "3.8.0-beta.54",
|
||||
"@ohif/extension-cornerstone": "3.8.0-beta.54",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.8.0-beta.54",
|
||||
@ -88,7 +91,7 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dropzone": "^10.1.7",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-resize-detector": "^6.7.6",
|
||||
"react-resize-detector": "^9.1.0",
|
||||
"react-router": "^6.8.1",
|
||||
"react-router-dom": "^6.8.1"
|
||||
},
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import React, { useEffect, useCallback, useRef } from 'react';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ServicesManager, Types, MeasurementService } from '@ohif/core';
|
||||
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
|
||||
@ -13,6 +14,7 @@ function ViewerViewportGrid(props) {
|
||||
|
||||
const { layout, activeViewportId, viewports } = viewportGrid;
|
||||
const { numCols, numRows } = layout;
|
||||
const elementRef = useRef(null);
|
||||
|
||||
// TODO -> Need some way of selecting which displaySets hit the viewports.
|
||||
const { displaySetService, measurementService, hangingProtocolService, uiNotificationService } = (
|
||||
@ -342,13 +344,26 @@ function ViewerViewportGrid(props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<ViewportGrid
|
||||
numRows={numRows}
|
||||
numCols={numCols}
|
||||
<div
|
||||
ref={elementRef}
|
||||
className="h-full w-full"
|
||||
>
|
||||
{/* {ViewportPanes} */}
|
||||
{getViewportPanes()}
|
||||
</ViewportGrid>
|
||||
<ViewportGrid
|
||||
numRows={numRows}
|
||||
numCols={numCols}
|
||||
>
|
||||
<ReactResizeDetector
|
||||
refreshMode="debounce"
|
||||
refreshRate={7} // ms seems to be fine for 10 viewports
|
||||
onResize={() => {
|
||||
viewportGridService.setViewportGridSizeChanged();
|
||||
}}
|
||||
targetRef={elementRef.current}
|
||||
/>
|
||||
{/* {ViewportPanes} */}
|
||||
{getViewportPanes()}
|
||||
</ViewportGrid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
"ohif-cli": "src/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
"yarn": ">=1.16.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "jest --watchAll",
|
||||
"dev:core": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -6,6 +6,7 @@ class ViewportGridService extends PubSubService {
|
||||
ACTIVE_VIEWPORT_ID_CHANGED: 'event::activeviewportidchanged',
|
||||
LAYOUT_CHANGED: 'event::layoutChanged',
|
||||
GRID_STATE_CHANGED: 'event::gridStateChanged',
|
||||
GRID_SIZE_CHANGED: 'event::gridSizeChanged',
|
||||
};
|
||||
|
||||
public static REGISTRATION = {
|
||||
@ -64,7 +65,6 @@ class ViewportGridService extends PubSubService {
|
||||
|
||||
public setActiveViewportId(id: string) {
|
||||
this.serviceImplementation._setActiveViewport(id);
|
||||
const state = this.getState();
|
||||
this._broadcastEvent(this.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED, {
|
||||
viewportId: id,
|
||||
});
|
||||
@ -79,6 +79,13 @@ class ViewportGridService extends PubSubService {
|
||||
return state.activeViewportId;
|
||||
}
|
||||
|
||||
public setViewportGridSizeChanged() {
|
||||
const state = this.getState();
|
||||
this._broadcastEvent(this.EVENTS.GRID_SIZE_CHANGED, {
|
||||
state,
|
||||
});
|
||||
}
|
||||
|
||||
public setDisplaySetsForViewport(props) {
|
||||
// Just update a single viewport, but use the multi-viewport update for it.
|
||||
this.setDisplaySetsForViewports([props]);
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"start": "docusaurus start --port 8001",
|
||||
"dev": "docusaurus start --port 8001",
|
||||
"docs": "docusaurus start --port 8001",
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:i18n": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
|
||||
@ -19,11 +19,12 @@
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rm -rf node_modules/.cache/storybook && shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"start": "yarn run build --watch",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"clean": "rm -rf node_modules/.cache/storybook",
|
||||
"dev": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
|
||||
@ -406,6 +406,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
set: gridLayoutState => service.setState(gridLayoutState), // run it through the service itself since we want to publish events
|
||||
getNumViewportPanes,
|
||||
getActiveViewportOptionByKey,
|
||||
setViewportGridSizeChanged: props => service.setViewportGridSizeChanged(props),
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user