@cornerstonejs/core 0.36.2 → 0.36.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/loaders/volumeLoader.d.ts +1 -0
- package/dist/cjs/loaders/volumeLoader.js +5 -1
- package/dist/cjs/loaders/volumeLoader.js.map +1 -1
- package/dist/cjs/utilities/getSliceRange.js +3 -1
- package/dist/cjs/utilities/getSliceRange.js.map +1 -1
- package/dist/cjs/utilities/getTargetVolumeAndSpacingInNormalDir.js +7 -0
- package/dist/cjs/utilities/getTargetVolumeAndSpacingInNormalDir.js.map +1 -1
- package/dist/esm/loaders/volumeLoader.d.ts +1 -0
- package/dist/esm/loaders/volumeLoader.js +3 -0
- package/dist/esm/loaders/volumeLoader.js.map +1 -1
- package/dist/esm/utilities/getSliceRange.js +3 -1
- package/dist/esm/utilities/getSliceRange.js.map +1 -1
- package/dist/esm/utilities/getTargetVolumeAndSpacingInNormalDir.js +7 -0
- package/dist/esm/utilities/getTargetVolumeAndSpacingInNormalDir.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +4 -3
- package/src/RenderingEngine/BaseVolumeViewport.ts +847 -0
- package/src/RenderingEngine/RenderingEngine.ts +1364 -0
- package/src/RenderingEngine/StackViewport.ts +2690 -0
- package/src/RenderingEngine/Viewport.ts +1244 -0
- package/src/RenderingEngine/VolumeViewport.ts +420 -0
- package/src/RenderingEngine/VolumeViewport3D.ts +42 -0
- package/src/RenderingEngine/getRenderingEngine.ts +34 -0
- package/src/RenderingEngine/helpers/addVolumesToViewports.ts +52 -0
- package/src/RenderingEngine/helpers/cpuFallback/colors/colormap.ts +343 -0
- package/src/RenderingEngine/helpers/cpuFallback/colors/index.ts +4 -0
- package/src/RenderingEngine/helpers/cpuFallback/colors/lookupTable.ts +469 -0
- package/src/RenderingEngine/helpers/cpuFallback/drawImageSync.ts +58 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/calculateTransform.ts +136 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/canvasToPixel.ts +25 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/computeAutoVoi.ts +47 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/correctShift.ts +38 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/createViewport.ts +64 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/doesImageNeedToBeRendered.ts +36 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/fitToWindow.ts +22 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/generateColorLUT.ts +60 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/generateLut.ts +83 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getDefaultViewport.ts +88 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getImageFitScale.ts +52 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getImageSize.ts +55 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getLut.ts +53 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getModalityLut.ts +55 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getTransform.ts +17 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.ts +74 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/initializeRenderCanvas.ts +37 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/lutMatches.ts +21 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/now.ts +13 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/pixelToCanvas.ts +22 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.ts +193 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/renderGrayscaleImage.ts +166 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/renderPseudoColorImage.ts +203 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/resetCamera.ts +32 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/resize.ts +109 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/saveLastRendered.ts +36 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/setDefaultViewport.ts +17 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/setToPixelCoordinateSystem.ts +32 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedColorPixelDataToCanvasImageData.ts +58 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageData.ts +76 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageDataColorLUT.ts +60 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageDataPET.ts +50 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageDataPseudocolorLUT.ts +66 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageDataPseudocolorLUTPET.ts +68 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedPixelDataToCanvasImageDataRGBA.ts +81 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/storedRGBAPixelDataToCanvasImageData.ts +56 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/transform.ts +126 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/validator.ts +31 -0
- package/src/RenderingEngine/helpers/createVolumeActor.ts +103 -0
- package/src/RenderingEngine/helpers/createVolumeMapper.ts +37 -0
- package/src/RenderingEngine/helpers/getOrCreateCanvas.ts +58 -0
- package/src/RenderingEngine/helpers/index.ts +15 -0
- package/src/RenderingEngine/helpers/isRgbaSourceRgbDest.ts +1 -0
- package/src/RenderingEngine/helpers/setDefaultVolumeVOI.ts +227 -0
- package/src/RenderingEngine/helpers/setVolumesForViewports.ts +52 -0
- package/src/RenderingEngine/helpers/viewportTypeToViewportClass.ts +14 -0
- package/src/RenderingEngine/helpers/viewportTypeUsesCustomRenderingPipeline.ts +7 -0
- package/src/RenderingEngine/helpers/volumeNewImageEventDispatcher.ts +75 -0
- package/src/RenderingEngine/index.ts +23 -0
- package/src/RenderingEngine/renderingEngineCache.ts +43 -0
- package/src/RenderingEngine/vtkClasses/index.js +11 -0
- package/src/RenderingEngine/vtkClasses/vtkOffscreenMultiRenderWindow.js +149 -0
- package/src/RenderingEngine/vtkClasses/vtkSharedVolumeMapper.js +52 -0
- package/src/RenderingEngine/vtkClasses/vtkSlabCamera.d.ts +781 -0
- package/src/RenderingEngine/vtkClasses/vtkSlabCamera.js +155 -0
- package/src/RenderingEngine/vtkClasses/vtkStreamingOpenGLRenderWindow.js +47 -0
- package/src/RenderingEngine/vtkClasses/vtkStreamingOpenGLTexture.js +272 -0
- package/src/RenderingEngine/vtkClasses/vtkStreamingOpenGLViewNodeFactory.js +159 -0
- package/src/RenderingEngine/vtkClasses/vtkStreamingOpenGLVolumeMapper.js +319 -0
- package/src/Settings.ts +294 -0
- package/src/cache/cache.ts +854 -0
- package/src/cache/classes/Contour.ts +70 -0
- package/src/cache/classes/ContourSet.ts +151 -0
- package/src/cache/classes/ImageVolume.ts +155 -0
- package/src/cache/index.ts +5 -0
- package/src/constants/cpuColormaps.ts +1537 -0
- package/src/constants/epsilon.ts +3 -0
- package/src/constants/index.ts +13 -0
- package/src/constants/mprCameraValues.ts +20 -0
- package/src/constants/rendering.ts +8 -0
- package/src/constants/viewportPresets.ts +357 -0
- package/src/enums/BlendModes.ts +23 -0
- package/src/enums/ContourType.ts +6 -0
- package/src/enums/Events.ts +196 -0
- package/src/enums/GeometryType.ts +5 -0
- package/src/enums/InterpolationType.ts +13 -0
- package/src/enums/OrientationAxis.ts +8 -0
- package/src/enums/RequestType.ts +13 -0
- package/src/enums/SharedArrayBufferModes.ts +11 -0
- package/src/enums/VOILUTFunctionType.ts +10 -0
- package/src/enums/ViewportType.ts +21 -0
- package/src/enums/index.ts +23 -0
- package/src/eventTarget.ts +67 -0
- package/src/getEnabledElement.ts +105 -0
- package/src/global.ts +8 -0
- package/src/index.ts +123 -0
- package/src/init.ts +247 -0
- package/src/loaders/geometryLoader.ts +108 -0
- package/src/loaders/imageLoader.ts +298 -0
- package/src/loaders/volumeLoader.ts +477 -0
- package/src/metaData.ts +84 -0
- package/src/requestPool/imageLoadPoolManager.ts +43 -0
- package/src/requestPool/imageRetrievalPoolManager.ts +25 -0
- package/src/requestPool/requestPoolManager.ts +329 -0
- package/src/types/ActorSliceRange.ts +17 -0
- package/src/types/CPUFallbackColormap.ts +23 -0
- package/src/types/CPUFallbackColormapData.ts +12 -0
- package/src/types/CPUFallbackColormapsData.ts +7 -0
- package/src/types/CPUFallbackEnabledElement.ts +71 -0
- package/src/types/CPUFallbackLUT.ts +5 -0
- package/src/types/CPUFallbackLookupTable.ts +17 -0
- package/src/types/CPUFallbackRenderingTools.ts +25 -0
- package/src/types/CPUFallbackTransform.ts +16 -0
- package/src/types/CPUFallbackViewport.ts +29 -0
- package/src/types/CPUFallbackViewportDisplayedArea.ts +15 -0
- package/src/types/CPUIImageData.ts +47 -0
- package/src/types/ContourData.ts +19 -0
- package/src/types/Cornerstone3DConfig.ts +31 -0
- package/src/types/CustomEventType.ts +14 -0
- package/src/types/EventTypes.ts +403 -0
- package/src/types/FlipDirection.ts +9 -0
- package/src/types/IActor.ts +23 -0
- package/src/types/ICache.ts +28 -0
- package/src/types/ICachedGeometry.ts +13 -0
- package/src/types/ICachedImage.ts +13 -0
- package/src/types/ICachedVolume.ts +12 -0
- package/src/types/ICamera.ts +36 -0
- package/src/types/IContour.ts +18 -0
- package/src/types/IContourSet.ts +56 -0
- package/src/types/IDynamicImageVolume.ts +18 -0
- package/src/types/IEnabledElement.ts +21 -0
- package/src/types/IGeometry.ts +12 -0
- package/src/types/IImage.ts +113 -0
- package/src/types/IImageData.ts +45 -0
- package/src/types/IImageVolume.ts +78 -0
- package/src/types/ILoadObject.ts +36 -0
- package/src/types/IRegisterImageLoader.ts +10 -0
- package/src/types/IRenderingEngine.ts +28 -0
- package/src/types/IStackViewport.ts +138 -0
- package/src/types/IStreamingImageVolume.ts +13 -0
- package/src/types/IStreamingVolumeProperties.ts +14 -0
- package/src/types/IViewport.ts +149 -0
- package/src/types/IViewportId.ts +9 -0
- package/src/types/IVolume.ts +45 -0
- package/src/types/IVolumeInput.ts +36 -0
- package/src/types/IVolumeViewport.ts +141 -0
- package/src/types/ImageLoaderFn.ts +16 -0
- package/src/types/ImageSliceData.ts +6 -0
- package/src/types/Mat3.ts +16 -0
- package/src/types/Metadata.ts +39 -0
- package/src/types/OrientationVectors.ts +36 -0
- package/src/types/Plane.ts +6 -0
- package/src/types/Point2.ts +6 -0
- package/src/types/Point3.ts +6 -0
- package/src/types/Point4.ts +6 -0
- package/src/types/ScalingParameters.ts +27 -0
- package/src/types/StackViewportProperties.ts +25 -0
- package/src/types/TransformMatrix2D.ts +4 -0
- package/src/types/ViewportInputOptions.ts +21 -0
- package/src/types/ViewportPreset.ts +14 -0
- package/src/types/VolumeLoaderFn.ts +18 -0
- package/src/types/VolumeViewportProperties.ts +14 -0
- package/src/types/index.ts +157 -0
- package/src/types/voi.ts +15 -0
- package/src/utilities/actorCheck.ts +24 -0
- package/src/utilities/applyPreset.ts +132 -0
- package/src/utilities/calculateViewportsSpatialRegistration.ts +74 -0
- package/src/utilities/calibratedPixelSpacingMetadataProvider.ts +38 -0
- package/src/utilities/createFloat32SharedArray.ts +45 -0
- package/src/utilities/createInt16SharedArray.ts +43 -0
- package/src/utilities/createLinearRGBTransferFunction.ts +22 -0
- package/src/utilities/createSigmoidRGBTransferFunction.ts +63 -0
- package/src/utilities/createUInt16SharedArray.ts +43 -0
- package/src/utilities/createUint8SharedArray.ts +45 -0
- package/src/utilities/deepFreeze.ts +19 -0
- package/src/utilities/deepMerge.ts +81 -0
- package/src/utilities/getClosestImageId.ts +80 -0
- package/src/utilities/getClosestStackImageIndexForPoint.ts +116 -0
- package/src/utilities/getImageSliceDataForVolumeViewport.ts +61 -0
- package/src/utilities/getMinMax.ts +31 -0
- package/src/utilities/getRuntimeId.ts +54 -0
- package/src/utilities/getScalarDataType.ts +31 -0
- package/src/utilities/getScalingParameters.ts +35 -0
- package/src/utilities/getSliceRange.ts +86 -0
- package/src/utilities/getSpacingInNormalDirection.ts +44 -0
- package/src/utilities/getTargetVolumeAndSpacingInNormalDir.ts +126 -0
- package/src/utilities/getViewportImageCornersInWorld.ts +102 -0
- package/src/utilities/getViewportsWithImageURI.ts +46 -0
- package/src/utilities/getViewportsWithVolumeId.ts +38 -0
- package/src/utilities/getVoiFromSigmoidRGBTransferFunction.ts +23 -0
- package/src/utilities/getVolumeActorCorners.ts +24 -0
- package/src/utilities/getVolumeSliceRangeInfo.ts +52 -0
- package/src/utilities/getVolumeViewportScrollInfo.ts +32 -0
- package/src/utilities/getVolumeViewportsContainingSameVolumes.ts +58 -0
- package/src/utilities/hasNaNValues.ts +12 -0
- package/src/utilities/imageIdToURI.ts +10 -0
- package/src/utilities/imageToWorldCoords.ts +54 -0
- package/src/utilities/index.ts +100 -0
- package/src/utilities/indexWithinDimensions.ts +27 -0
- package/src/utilities/invertRgbTransferFunction.ts +36 -0
- package/src/utilities/isEqual.ts +27 -0
- package/src/utilities/isOpposite.ts +23 -0
- package/src/utilities/isTypedArray.ts +20 -0
- package/src/utilities/loadImageToCanvas.ts +80 -0
- package/src/utilities/planar.ts +91 -0
- package/src/utilities/renderToCanvas.ts +32 -0
- package/src/utilities/scaleRgbTransferFunction.ts +37 -0
- package/src/utilities/snapFocalPointToSlice.ts +78 -0
- package/src/utilities/spatialRegistrationMetadataProvider.ts +50 -0
- package/src/utilities/transformWorldToIndex.ts +16 -0
- package/src/utilities/triggerEvent.ts +38 -0
- package/src/utilities/uuidv4.ts +13 -0
- package/src/utilities/windowLevel.ts +39 -0
- package/src/utilities/worldToImageCoords.ts +64 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
|
|
2
|
+
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
|
|
3
|
+
import { ViewportPreset } from '../types';
|
|
4
|
+
import { VolumeActor } from '../types/IActor';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Applies a preset to a volume actor.
|
|
8
|
+
*
|
|
9
|
+
* @param actor - The volume actor to apply the preset to.
|
|
10
|
+
* @param preset - The preset to apply.
|
|
11
|
+
*/
|
|
12
|
+
export default function applyPreset(actor: VolumeActor, preset: ViewportPreset) {
|
|
13
|
+
// Create color transfer function
|
|
14
|
+
const colorTransferArray = preset.colorTransfer
|
|
15
|
+
.split(' ')
|
|
16
|
+
.splice(1)
|
|
17
|
+
.map(parseFloat);
|
|
18
|
+
|
|
19
|
+
const { shiftRange } = getShiftRange(colorTransferArray);
|
|
20
|
+
const min = shiftRange[0];
|
|
21
|
+
const width = shiftRange[1] - shiftRange[0];
|
|
22
|
+
const cfun = vtkColorTransferFunction.newInstance();
|
|
23
|
+
const normColorTransferValuePoints = [];
|
|
24
|
+
for (let i = 0; i < colorTransferArray.length; i += 4) {
|
|
25
|
+
let value = colorTransferArray[i];
|
|
26
|
+
const r = colorTransferArray[i + 1];
|
|
27
|
+
const g = colorTransferArray[i + 2];
|
|
28
|
+
const b = colorTransferArray[i + 3];
|
|
29
|
+
|
|
30
|
+
value = (value - min) / width;
|
|
31
|
+
normColorTransferValuePoints.push([value, r, g, b]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
applyPointsToRGBFunction(normColorTransferValuePoints, shiftRange, cfun);
|
|
35
|
+
|
|
36
|
+
actor.getProperty().setRGBTransferFunction(0, cfun);
|
|
37
|
+
|
|
38
|
+
// Create scalar opacity function
|
|
39
|
+
const scalarOpacityArray = preset.scalarOpacity
|
|
40
|
+
.split(' ')
|
|
41
|
+
.splice(1)
|
|
42
|
+
.map(parseFloat);
|
|
43
|
+
|
|
44
|
+
const ofun = vtkPiecewiseFunction.newInstance();
|
|
45
|
+
const normPoints = [];
|
|
46
|
+
for (let i = 0; i < scalarOpacityArray.length; i += 2) {
|
|
47
|
+
let value = scalarOpacityArray[i];
|
|
48
|
+
const opacity = scalarOpacityArray[i + 1];
|
|
49
|
+
|
|
50
|
+
value = (value - min) / width;
|
|
51
|
+
|
|
52
|
+
normPoints.push([value, opacity]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
applyPointsToPiecewiseFunction(normPoints, shiftRange, ofun);
|
|
56
|
+
|
|
57
|
+
actor.getProperty().setScalarOpacity(0, ofun);
|
|
58
|
+
|
|
59
|
+
const [
|
|
60
|
+
gradientMinValue,
|
|
61
|
+
gradientMinOpacity,
|
|
62
|
+
gradientMaxValue,
|
|
63
|
+
gradientMaxOpacity,
|
|
64
|
+
] = preset.gradientOpacity.split(' ').splice(1).map(parseFloat);
|
|
65
|
+
|
|
66
|
+
actor.getProperty().setUseGradientOpacity(0, true);
|
|
67
|
+
actor.getProperty().setGradientOpacityMinimumValue(0, gradientMinValue);
|
|
68
|
+
actor.getProperty().setGradientOpacityMinimumOpacity(0, gradientMinOpacity);
|
|
69
|
+
actor.getProperty().setGradientOpacityMaximumValue(0, gradientMaxValue);
|
|
70
|
+
actor.getProperty().setGradientOpacityMaximumOpacity(0, gradientMaxOpacity);
|
|
71
|
+
|
|
72
|
+
if (preset.interpolation === '1') {
|
|
73
|
+
actor.getProperty().setInterpolationTypeToFastLinear();
|
|
74
|
+
//actor.getProperty().setInterpolationTypeToLinear()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const ambient = parseFloat(preset.ambient);
|
|
78
|
+
const diffuse = parseFloat(preset.diffuse);
|
|
79
|
+
const specular = parseFloat(preset.specular);
|
|
80
|
+
const specularPower = parseFloat(preset.specularPower);
|
|
81
|
+
|
|
82
|
+
actor.getProperty().setAmbient(ambient);
|
|
83
|
+
actor.getProperty().setDiffuse(diffuse);
|
|
84
|
+
actor.getProperty().setSpecular(specular);
|
|
85
|
+
actor.getProperty().setSpecularPower(specularPower);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getShiftRange(colorTransferArray) {
|
|
89
|
+
// Credit to paraview-glance
|
|
90
|
+
// https://github.com/Kitware/paraview-glance/blob/3fec8eeff31e9c19ad5b6bff8e7159bd745e2ba9/src/components/controls/ColorBy/script.js#L133
|
|
91
|
+
|
|
92
|
+
// shift range is original rgb/opacity range centered around 0
|
|
93
|
+
let min = Infinity;
|
|
94
|
+
let max = -Infinity;
|
|
95
|
+
for (let i = 0; i < colorTransferArray.length; i += 4) {
|
|
96
|
+
min = Math.min(min, colorTransferArray[i]);
|
|
97
|
+
max = Math.max(max, colorTransferArray[i]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const center = (max - min) / 2;
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
shiftRange: [-center, center],
|
|
104
|
+
min,
|
|
105
|
+
max,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function applyPointsToRGBFunction(points, range, cfun) {
|
|
110
|
+
const width = range[1] - range[0];
|
|
111
|
+
const rescaled = points.map(([x, r, g, b]) => [
|
|
112
|
+
x * width + range[0],
|
|
113
|
+
r,
|
|
114
|
+
g,
|
|
115
|
+
b,
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
cfun.removeAllPoints();
|
|
119
|
+
rescaled.forEach(([x, r, g, b]) => cfun.addRGBPoint(x, r, g, b));
|
|
120
|
+
|
|
121
|
+
return rescaled;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function applyPointsToPiecewiseFunction(points, range, pwf) {
|
|
125
|
+
const width = range[1] - range[0];
|
|
126
|
+
const rescaled = points.map(([x, y]) => [x * width + range[0], y]);
|
|
127
|
+
|
|
128
|
+
pwf.removeAllPoints();
|
|
129
|
+
rescaled.forEach(([x, y]) => pwf.addPoint(x, y));
|
|
130
|
+
|
|
131
|
+
return rescaled;
|
|
132
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { vec3, mat4 } from 'gl-matrix';
|
|
2
|
+
import { IStackViewport } from '../types';
|
|
3
|
+
import { StackViewport } from '../RenderingEngine';
|
|
4
|
+
import spatialRegistrationMetadataProvider from './spatialRegistrationMetadataProvider';
|
|
5
|
+
import { metaData } from '..';
|
|
6
|
+
import isEqual from './isEqual';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* It calculates the registration matrix between two viewports (currently only
|
|
10
|
+
* translation is supported)
|
|
11
|
+
* If the viewports are in the same frame of reference, it will return early,
|
|
12
|
+
* but otherwise it will use the current image's metadata to calculate the
|
|
13
|
+
* translation between the two viewports and adds it to the spatialRegistrationModule
|
|
14
|
+
* metadata provider
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
|
+
* @param viewport1 - The first stack viewport
|
|
18
|
+
* @param viewport2 - The second stack viewport
|
|
19
|
+
*/
|
|
20
|
+
function calculateViewportsSpatialRegistration(
|
|
21
|
+
viewport1: IStackViewport,
|
|
22
|
+
viewport2: IStackViewport
|
|
23
|
+
): void {
|
|
24
|
+
if (
|
|
25
|
+
!(viewport1 instanceof StackViewport) ||
|
|
26
|
+
!(viewport2 instanceof StackViewport)
|
|
27
|
+
) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'calculateViewportsSpatialRegistration: Both viewports must be StackViewports, volume viewports are not supported yet'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const isSameFrameOfReference =
|
|
34
|
+
viewport1.getFrameOfReferenceUID() === viewport2.getFrameOfReferenceUID();
|
|
35
|
+
|
|
36
|
+
if (isSameFrameOfReference) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const imageId1 = viewport1.getCurrentImageId();
|
|
41
|
+
const imageId2 = viewport2.getCurrentImageId();
|
|
42
|
+
|
|
43
|
+
const imagePlaneModule1 = metaData.get('imagePlaneModule', imageId1);
|
|
44
|
+
const imagePlaneModule2 = metaData.get('imagePlaneModule', imageId2);
|
|
45
|
+
|
|
46
|
+
const isSameImagePlane =
|
|
47
|
+
imagePlaneModule1 &&
|
|
48
|
+
imagePlaneModule2 &&
|
|
49
|
+
isEqual(
|
|
50
|
+
imagePlaneModule1.imageOrientationPatient,
|
|
51
|
+
imagePlaneModule2.imageOrientationPatient
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (!isSameImagePlane) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'Viewport spatial registration only supported for same orientation (hence translation only) for now'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const imagePositionPatient1 = imagePlaneModule1.imagePositionPatient;
|
|
61
|
+
const imagePositionPatient2 = imagePlaneModule2.imagePositionPatient;
|
|
62
|
+
|
|
63
|
+
const translation = vec3.subtract(
|
|
64
|
+
vec3.create(),
|
|
65
|
+
imagePositionPatient1,
|
|
66
|
+
imagePositionPatient2
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const mat = mat4.fromTranslation(mat4.create(), translation);
|
|
70
|
+
|
|
71
|
+
spatialRegistrationMetadataProvider.add([viewport1.id, viewport2.id], mat);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default calculateViewportsSpatialRegistration;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import imageIdToURI from './imageIdToURI';
|
|
2
|
+
|
|
3
|
+
const state = {}; // Calibrated pixel spacing per imageId
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Simple metadataProvider object to store metadata for calibrated spacings.
|
|
7
|
+
* This can be added via cornerstone.metaData.addProvider(...) in order to store
|
|
8
|
+
* and return calibrated pixel spacings when metaData type is "calibratedPixelSpacing".
|
|
9
|
+
*/
|
|
10
|
+
const metadataProvider = {
|
|
11
|
+
/**
|
|
12
|
+
* Adds metadata for an imageId.
|
|
13
|
+
* @param imageId - the imageId for the metadata to store
|
|
14
|
+
* @param payload - the payload composed of new calibrated pixel spacings
|
|
15
|
+
*/
|
|
16
|
+
add: (imageId: string, payload: [number, number]): void => {
|
|
17
|
+
const imageURI = imageIdToURI(imageId);
|
|
18
|
+
if (!state[imageURI]) {
|
|
19
|
+
state[imageURI] = {};
|
|
20
|
+
}
|
|
21
|
+
state[imageURI] = payload;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the metadata for an imageId if it exists.
|
|
26
|
+
* @param type - the type of metadata to enquire about
|
|
27
|
+
* @param imageId - the imageId to enquire about
|
|
28
|
+
* @returns the calibrated pixel spacings for the imageId if it exists, otherwise undefined
|
|
29
|
+
*/
|
|
30
|
+
get: (type: string, imageId: string): [number, number] => {
|
|
31
|
+
if (type === 'calibratedPixelSpacing') {
|
|
32
|
+
const imageURI = imageIdToURI(imageId);
|
|
33
|
+
return state[imageURI];
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default metadataProvider;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import global from '../global';
|
|
2
|
+
import { getShouldUseSharedArrayBuffer } from '../init';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A helper function that creates a new Float32Array that utilized a shared
|
|
6
|
+
* array buffer. This allows the array to be updated simultaneously in
|
|
7
|
+
* workers or the main thread. Depending on the system (the CPU, the OS, the Browser)
|
|
8
|
+
* it can take a while until the change is propagated to all contexts.
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer|MDN: SharedArrayBuffer}
|
|
11
|
+
* @remarks
|
|
12
|
+
* We use SharedArrayBuffers in our ImageCache class. It's what allows us to
|
|
13
|
+
* stream data to build a volume. It's important to note that SharedArrayBuffer
|
|
14
|
+
* does not work out of the box for all web browsers. In some, it is disabled
|
|
15
|
+
* behind a flag; in others, it has been removed entirely.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* Creating an array for a Volume with known dimensions:
|
|
19
|
+
* ```
|
|
20
|
+
* const dimensions = [512, 512, 25];
|
|
21
|
+
* const scalarData = createFloat32SharedArray(dimensions[0] * dimensions[1] * dimensions[2]);
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param length - frame size * number of frames
|
|
25
|
+
* @returns a Float32Array with an underlying SharedArrayBuffer
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
function createFloat32SharedArray(length: number): Float32Array {
|
|
29
|
+
if (!getShouldUseSharedArrayBuffer()) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'Your page is NOT cross-origin isolated, see https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (window.SharedArrayBuffer === undefined) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'SharedArrayBuffer is NOT supported in your browser see https://developer.chrome.com/blog/enabling-shared-array-buffer/'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const sharedArrayBuffer = new SharedArrayBuffer(length * 4);
|
|
41
|
+
|
|
42
|
+
return new Float32Array(sharedArrayBuffer);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default createFloat32SharedArray;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import global from '../global';
|
|
2
|
+
/**
|
|
3
|
+
* A helper function that creates a new Int16 that utilized a shared
|
|
4
|
+
* array buffer. This allows the array to be updated simultaneously in
|
|
5
|
+
* workers or the main thread. Depending on the system (the CPU, the OS, the Browser)
|
|
6
|
+
* it can take a while until the change is propagated to all contexts.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer|MDN: SharedArrayBuffer}
|
|
9
|
+
* @remarks
|
|
10
|
+
* We use SharedArrayBuffers in our ImageCache class. It's what allows us to
|
|
11
|
+
* stream data to build a volume. It's important to note that SharedArrayBuffer
|
|
12
|
+
* does not work out of the box for all web browsers. In some, it is disabled
|
|
13
|
+
* behind a flag; in others, it has been removed entirely.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* Creating an array for a Volume with known dimensions:
|
|
17
|
+
* ```
|
|
18
|
+
* const dimensions = [512, 512, 25];
|
|
19
|
+
* const scalarData = createInt16SharedArray(dimensions[0] * dimensions[1] * dimensions[2]);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @param length - frame size * number of frames
|
|
23
|
+
* @returns a Int8Array with an underlying SharedArrayBuffer
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
function createInt16SharedArray(length: number): Int16Array {
|
|
27
|
+
if (!window.crossOriginIsolated) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'Your page is NOT cross-origin isolated, see https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (window.SharedArrayBuffer === undefined) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'SharedArrayBuffer is NOT supported in your browser see https://developer.chrome.com/blog/enabling-shared-array-buffer/'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sharedArrayBuffer = new SharedArrayBuffer(length * 2);
|
|
39
|
+
|
|
40
|
+
return new Int16Array(sharedArrayBuffer);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default createInt16SharedArray;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
|
|
2
|
+
import { VOIRange } from '../types';
|
|
3
|
+
|
|
4
|
+
export default function createLinearRGBTransferFunction(
|
|
5
|
+
voiRange: VOIRange
|
|
6
|
+
): vtkColorTransferFunction {
|
|
7
|
+
const cfun = vtkColorTransferFunction.newInstance();
|
|
8
|
+
let lower = 0;
|
|
9
|
+
let upper = 1024;
|
|
10
|
+
if (
|
|
11
|
+
voiRange &&
|
|
12
|
+
voiRange.lower !== undefined &&
|
|
13
|
+
voiRange.upper !== undefined
|
|
14
|
+
) {
|
|
15
|
+
lower = voiRange.lower;
|
|
16
|
+
upper = voiRange.upper;
|
|
17
|
+
}
|
|
18
|
+
cfun.addRGBPoint(lower, 0.0, 0.0, 0.0);
|
|
19
|
+
cfun.addRGBPoint(upper, 1.0, 1.0, 1.0);
|
|
20
|
+
|
|
21
|
+
return cfun;
|
|
22
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
|
|
2
|
+
import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
|
|
3
|
+
import { VOIRange } from '../types';
|
|
4
|
+
import { windowLevel as windowLevelUtil } from '.';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A utility that can be used to generate an Sigmoid RgbTransferFunction.
|
|
8
|
+
* Sigmoid transfer functions are used in the dicom specification:
|
|
9
|
+
* https://dicom.nema.org/medical/dicom/2018b/output/chtml/part03/sect_C.11.2.html
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* Setting an RGB Transfer function from the viewport:
|
|
13
|
+
* ```
|
|
14
|
+
* const sigmoidRGBTransferFunction = createSigmoidRGBTransferFunction(0, 255, { lower: 0, upper: 255} );
|
|
15
|
+
* viewport
|
|
16
|
+
* .getActor()
|
|
17
|
+
* .getProperty()
|
|
18
|
+
* .setRGBTransferFunction(0, sigmoidRGBTransferFunction);
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @see {@link https://kitware.github.io/vtk-js/api/Rendering_Core_ColorTransferFunction.html|VTK.js: ColorTransferFunction}
|
|
22
|
+
* @param rgbTransferFunction
|
|
23
|
+
*/
|
|
24
|
+
export default function createSigmoidRGBTransferFunction(
|
|
25
|
+
voiRange: VOIRange,
|
|
26
|
+
approximationNodes = 1024 // humans can precieve no more than 900 shades of gray doi: 10.1007/s10278-006-1052-3
|
|
27
|
+
): vtkColorTransferFunction {
|
|
28
|
+
const { windowWidth, windowCenter } = windowLevelUtil.toWindowLevel(
|
|
29
|
+
voiRange.lower,
|
|
30
|
+
voiRange.upper
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Function is defined by dicom spec
|
|
34
|
+
// https://dicom.nema.org/medical/dicom/2018b/output/chtml/part03/sect_C.11.2.html
|
|
35
|
+
const sigmoid = (x: number, wc: number, ww: number) => {
|
|
36
|
+
return 1 / (1 + Math.exp((-4 * (x - wc)) / ww));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// This function is the analytical inverse of the dicom spec sigmoid function
|
|
40
|
+
// for values y = [0, 1] exclusive. We use this to perform better sampling of
|
|
41
|
+
// points for the LUT as some images can have 2^16 unique values. This method
|
|
42
|
+
// can be deprecated if vtk supports LUTFunctions rather than look up tables
|
|
43
|
+
// or if vtk supports logistic scale. It currently only supports linear and
|
|
44
|
+
// log10 scaling which can be set on the vtkColorTransferFunction
|
|
45
|
+
const logit = (y: number, wc: number, ww: number) => {
|
|
46
|
+
return wc - (ww / 4) * Math.log((1 - y) / y);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// we slice out the first and last value to avoid 0 and 1 Infinity values
|
|
50
|
+
const range = [...Array(approximationNodes + 2).keys()]
|
|
51
|
+
.map((v) => v / (approximationNodes + 2))
|
|
52
|
+
.slice(1, -1);
|
|
53
|
+
const table = range.reduce((res, y) => {
|
|
54
|
+
const x = logit(y, windowCenter, windowWidth);
|
|
55
|
+
return res.concat(x, y, y, y, 0.5, 0.0);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const cfun = vtkColorTransferFunction.newInstance();
|
|
59
|
+
cfun.buildFunctionFromArray(
|
|
60
|
+
vtkDataArray.newInstance({ values: table, numberOfComponents: 6 })
|
|
61
|
+
);
|
|
62
|
+
return cfun;
|
|
63
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import global from '../global';
|
|
2
|
+
/**
|
|
3
|
+
* A helper function that creates a new Uint16 that utilized a shared
|
|
4
|
+
* array buffer. This allows the array to be updated simultaneously in
|
|
5
|
+
* workers or the main thread. Depending on the system (the CPU, the OS, the Browser)
|
|
6
|
+
* it can take a while until the change is propagated to all contexts.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer|MDN: SharedArrayBuffer}
|
|
9
|
+
* @remarks
|
|
10
|
+
* We use SharedArrayBuffers in our ImageCache class. It's what allows us to
|
|
11
|
+
* stream data to build a volume. It's important to note that SharedArrayBuffer
|
|
12
|
+
* does not work out of the box for all web browsers. In some, it is disabled
|
|
13
|
+
* behind a flag; in others, it has been removed entirely.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* Creating an array for a Volume with known dimensions:
|
|
17
|
+
* ```
|
|
18
|
+
* const dimensions = [512, 512, 25];
|
|
19
|
+
* const scalarData = createUint16SharedArray(dimensions[0] * dimensions[1] * dimensions[2]);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @param length - frame size * number of frames
|
|
23
|
+
* @returns a Uint8Array with an underlying SharedArrayBuffer
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
function createUint16SharedArray(length: number): Uint16Array {
|
|
27
|
+
if (!window.crossOriginIsolated) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'Your page is NOT cross-origin isolated, see https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if (window.SharedArrayBuffer === undefined) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'SharedArrayBuffer is NOT supported in your browser see https://developer.chrome.com/blog/enabling-shared-array-buffer/'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sharedArrayBuffer = new SharedArrayBuffer(length * 2);
|
|
39
|
+
|
|
40
|
+
return new Uint16Array(sharedArrayBuffer);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default createUint16SharedArray;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import global from '../global';
|
|
2
|
+
import { getShouldUseSharedArrayBuffer } from '../init';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A helper function that creates a new Float32Array that utilized a shared
|
|
6
|
+
* array buffer. This allows the array to be updated simultaneously in
|
|
7
|
+
* workers or the main thread. Depending on the system (the CPU, the OS, the Browser)
|
|
8
|
+
* it can take a while until the change is propagated to all contexts.
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer|MDN: SharedArrayBuffer}
|
|
11
|
+
* @remarks
|
|
12
|
+
* We use SharedArrayBuffers in our ImageCache class. It's what allows us to
|
|
13
|
+
* stream data to build a volume. It's important to note that SharedArrayBuffer
|
|
14
|
+
* does not work out of the box for all web browsers. In some, it is disabled
|
|
15
|
+
* behind a flag; in others, it has been removed entirely.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* Creating an array for a Volume with known dimensions:
|
|
19
|
+
* ```
|
|
20
|
+
* const dimensions = [512, 512, 25];
|
|
21
|
+
* const scalarData = createUint8SharedArray(dimensions[0] * dimensions[1] * dimensions[2]);
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param length - frame size * number of frames
|
|
25
|
+
* @returns a Uint8Array with an underlying SharedArrayBuffer
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
function createUint8SharedArray(length: number): Uint8Array {
|
|
29
|
+
if (!getShouldUseSharedArrayBuffer()) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'Your page is NOT cross-origin isolated, see https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (window.SharedArrayBuffer === undefined) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'SharedArrayBuffer is NOT supported in your browser see https://developer.chrome.com/blog/enabling-shared-array-buffer/'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const sharedArrayBuffer = new SharedArrayBuffer(length);
|
|
41
|
+
|
|
42
|
+
return new Uint8Array(sharedArrayBuffer);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default createUint8SharedArray;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#examples
|
|
2
|
+
function deepFreeze(object) {
|
|
3
|
+
// Retrieve the property names defined on object
|
|
4
|
+
const propNames = Object.getOwnPropertyNames(object);
|
|
5
|
+
|
|
6
|
+
// Freeze properties before freezing self
|
|
7
|
+
|
|
8
|
+
for (const name of propNames) {
|
|
9
|
+
const value = object[name];
|
|
10
|
+
|
|
11
|
+
if (value && typeof value === 'object') {
|
|
12
|
+
deepFreeze(value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return Object.freeze(object);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default deepFreeze;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const isMergeableObject = (val) => {
|
|
2
|
+
const nonNullObject = val && typeof val === 'object';
|
|
3
|
+
|
|
4
|
+
return (
|
|
5
|
+
nonNullObject &&
|
|
6
|
+
Object.prototype.toString.call(val) !== '[object RegExp]' &&
|
|
7
|
+
Object.prototype.toString.call(val) !== '[object Date]'
|
|
8
|
+
);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const emptyTarget = (val) => {
|
|
12
|
+
const isEmpty = Array.isArray(val) ? [] : {};
|
|
13
|
+
|
|
14
|
+
return isEmpty;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const cloneIfNecessary = (value, optionsArgument) => {
|
|
18
|
+
const clone = optionsArgument && optionsArgument.clone === true;
|
|
19
|
+
|
|
20
|
+
return clone && isMergeableObject(value)
|
|
21
|
+
? deepMerge(emptyTarget(value), value, optionsArgument)
|
|
22
|
+
: value;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defaultArrayMerge = (target, source, optionsArgument) => {
|
|
26
|
+
const destination = target.slice();
|
|
27
|
+
|
|
28
|
+
source.forEach(function (e, i) {
|
|
29
|
+
if (typeof destination[i] === 'undefined') {
|
|
30
|
+
destination[i] = cloneIfNecessary(e, optionsArgument);
|
|
31
|
+
} else if (isMergeableObject(e)) {
|
|
32
|
+
destination[i] = deepMerge(target[i], e, optionsArgument);
|
|
33
|
+
} else if (target.indexOf(e) === -1) {
|
|
34
|
+
destination.push(cloneIfNecessary(e, optionsArgument));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return destination;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const mergeObject = (target, source, optionsArgument) => {
|
|
42
|
+
const destination = {};
|
|
43
|
+
|
|
44
|
+
if (isMergeableObject(target)) {
|
|
45
|
+
Object.keys(target).forEach(function (key) {
|
|
46
|
+
destination[key] = cloneIfNecessary(target[key], optionsArgument);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
Object.keys(source).forEach(function (key) {
|
|
50
|
+
if (!isMergeableObject(source[key]) || !target[key]) {
|
|
51
|
+
destination[key] = cloneIfNecessary(source[key], optionsArgument);
|
|
52
|
+
} else {
|
|
53
|
+
destination[key] = deepMerge(target[key], source[key], optionsArgument);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return destination;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Merge two objects, recursively merging any objects that are arrays
|
|
62
|
+
* @param target - The target object.
|
|
63
|
+
* @param source - The source object to merge into the target object.
|
|
64
|
+
* @param optionsArgument - The options object.
|
|
65
|
+
* @returns The merged object.
|
|
66
|
+
*/
|
|
67
|
+
const deepMerge = (target = {}, source = {}, optionsArgument = undefined) => {
|
|
68
|
+
const array = Array.isArray(source);
|
|
69
|
+
const options = optionsArgument || { arrayMerge: defaultArrayMerge };
|
|
70
|
+
const arrayMerge = options.arrayMerge || defaultArrayMerge;
|
|
71
|
+
|
|
72
|
+
if (array) {
|
|
73
|
+
return Array.isArray(target)
|
|
74
|
+
? arrayMerge(target, source, optionsArgument)
|
|
75
|
+
: cloneIfNecessary(source, optionsArgument);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return mergeObject(target, source, optionsArgument);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default deepMerge;
|