import {
- _fetchBulkdata,
- getContentItemNameCodedConcept
-} from './utils.js'
+ import { _fetchBulkdata } from './utils.js'
const _attrs = Symbol('attrs')
@@ -242,11 +239,13 @@ Source: annotation.js
)
} else {
if ('PointCoordinatesData' in bulkdataItem) {
+ console.info(`fetch point coordinate data of annotation group "${uid}"`)
return await _fetchBulkdata({
client,
reference: bulkdataItem.PointCoordinatesData
})
} else if ('DoublePointCoordinatesData' in bulkdataItem) {
+ console.info(`fetch point coordinate data of annotation group "${uid}"`)
return await _fetchBulkdata({
client,
reference: bulkdataItem.DoublePointCoordinatesData
@@ -294,6 +293,7 @@ Source: annotation.js
}
} else {
if ('LongPrimitivePointIndexList' in bulkdataItem) {
+ console.info(`fetch point index list of annotation group "${uid}"`)
return await _fetchBulkdata({
client,
reference: bulkdataItem.LongPrimitivePointIndexList
@@ -352,6 +352,11 @@ Source: annotation.js
measurementBulkdataItem.MeasurementValuesSequence[0]
)
if ('FloatingPointValues' in valuesBulkdataItem) {
+ const nameItem = measurementMetadataItem.ConceptNameCodeSequence[0]
+ const name = nameItem.CodeMeaning
+ console.info(
+ `fetch measurement values for measurement #${index} "${name}"`
+ )
return await _fetchBulkdata({
client,
reference: valuesBulkdataItem.FloatingPointValues
@@ -408,6 +413,11 @@ Source: annotation.js
.MeasurementValuesSequence[0]
)
if ('AnnotationIndexList' in valuesBulkdataItem) {
+ const nameItem = measurementMetadataItem.ConceptNameCodeSequence[0]
+ const name = nameItem.CodeMeaning
+ console.info(
+ `fetch measurement indices for measurement #${index} "${name}"`
+ )
return await _fetchBulkdata({
client,
reference: valuesBulkdataItem.AnnotationIndexList
@@ -420,7 +430,7 @@ Source: annotation.js
}
/**
- * Fetch measurements of an annotation group.
+ * Fetch all measurements of an annotation group.
*
* @param {object} options
* @param {object} options.metadataItem - Metadata of Annotation Group Sequence item
@@ -440,7 +450,8 @@ Source: annotation.js
if (metadataItem.MeasurementsSequence !== undefined) {
for (let i = 0; i < metadataItem.MeasurementsSequence.length; i++) {
const item = metadataItem.MeasurementsSequence[i]
- const name = getContentItemNameCodedConcept(item)
+ const name = item.ConceptNameCodeSequence[0]
+ const unit = item.MeasurementUnitsCodeSequence[0]
const values = await _fetchMeasurementValues({
metadataItem,
bulkdataItem,
@@ -455,6 +466,7 @@ Source: annotation.js
})
measurements.push({
name,
+ unit,
values,
indices
})
@@ -463,6 +475,58 @@ Source: annotation.js
return measurements
}
+/**
+ * Fetch an individual measurement of an annotation group.
+ *
+ * @param {object} options
+ * @param {object} options.metadataItem - Metadata of Annotation Group Sequence item
+ * @param {object} options.bulkdataItem - Bulkdata of Annotation Group Sequence item
+ * @param {object} options.index - Index of the Measurements Sequence item
+ * @param {object} options.client - DICOMweb client
+ *
+ * @returns {Promise<Array<object>>} Name, values, and indices of measurements
+ *
+ * @private
+ */
+async function _fetchMeasurement ({
+ metadataItem,
+ bulkdataItem,
+ index,
+ client
+}) {
+ if (metadataItem.MeasurementsSequence == null) {
+ throw new Error(
+ 'Measurements Sequence element is not contained in metadata.'
+ )
+ }
+ if (metadataItem.MeasurementsSequence.length === 0) {
+ throw new Error(
+ 'Measurements Sequence element in empty.'
+ )
+ }
+ const item = metadataItem.MeasurementsSequence[index]
+ if (item == null) {
+ throw new Error(
+ `Measurements Sequence does not contain an item #${index}.`
+ )
+ }
+ const name = item.ConceptNameCodeSequence[0]
+ const unit = item.MeasurementUnitsCodeSequence[0]
+ const values = await _fetchMeasurementValues({
+ metadataItem,
+ bulkdataItem,
+ index,
+ client
+ })
+ const indices = await _fetchMeasurementIndices({
+ metadataItem,
+ bulkdataItem,
+ index,
+ client
+ })
+ return { name, unit, values, indices }
+}
+
/**
* Get dimensionality of coordinates.
*
@@ -753,6 +817,7 @@ Source: annotation.js
_fetchGraphicData,
_fetchGraphicIndex,
_fetchMeasurements,
+ _fetchMeasurement,
_getCentroid,
_getCommonZCoordinate,
_getCoordinateDimensionality
@@ -773,7 +838,7 @@ Home
Namespaces
-
diff --git a/docs/annotations__AnnotationManager.js.html b/docs/annotations__AnnotationManager.js.html
index 1df980b6..c18783b4 100644
--- a/docs/annotations__AnnotationManager.js.html
+++ b/docs/annotations__AnnotationManager.js.html
@@ -230,7 +230,7 @@
Home
Namespaces
-
diff --git a/docs/annotations_markups__MarkupManager.js.html b/docs/annotations_markups__MarkupManager.js.html
index 43c952f1..fb07ed23 100644
--- a/docs/annotations_markups__MarkupManager.js.html
+++ b/docs/annotations_markups__MarkupManager.js.html
@@ -567,7 +567,7 @@
Home
Namespaces
-
diff --git a/docs/api.html b/docs/api.html
index fc34eadc..02c72ee1 100644
--- a/docs/api.html
+++ b/docs/api.html
@@ -125,7 +125,7 @@
Home
Namespaces
-
diff --git a/docs/color.PaletteColorLookupTable.html b/docs/color.PaletteColorLookupTable.html
index a7fe2df9..326777db 100644
--- a/docs/color.PaletteColorLookupTable.html
+++ b/docs/color.PaletteColorLookupTable.html
@@ -707,7 +707,7 @@
Home
Namespaces
-
diff --git a/docs/color.html b/docs/color.html
index 30d50e11..432d166d 100644
--- a/docs/color.html
+++ b/docs/color.html
@@ -662,7 +662,7 @@
Home
Namespaces
-
diff --git a/docs/color.js.html b/docs/color.js.html
index aef92df3..3a07aa8e 100644
--- a/docs/color.js.html
+++ b/docs/color.js.html
@@ -462,7 +462,7 @@
Home
Namespaces
-
diff --git a/docs/dicom-microscopy-viewer.js.html b/docs/dicom-microscopy-viewer.js.html
index 42e4036b..3a8c4337 100644
--- a/docs/dicom-microscopy-viewer.js.html
+++ b/docs/dicom-microscopy-viewer.js.html
@@ -238,7 +238,7 @@
Home
Namespaces
-
diff --git a/docs/events.html b/docs/events.html
index 45c58816..7e8441ac 100644
--- a/docs/events.html
+++ b/docs/events.html
@@ -363,6 +363,29 @@
Properties:
+
+
+ LOADING_ERROR
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+ Triggered when an error occurs during loading of data.
+
+
+
+
FRAME_LOADING_STARTED
@@ -404,6 +427,29 @@ Properties:
+
+
+
+
+
+
+
+ FRAME_LOADING_ERROR
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
@@ -483,7 +529,7 @@ Home
Namespaces
-
diff --git a/docs/events.js.html b/docs/events.js.html
index dd529f11..7bf5c039 100644
--- a/docs/events.js.html
+++ b/docs/events.js.html
@@ -56,10 +56,14 @@
Source: events.js
LOADING_STARTED: `${PROJECT_NAME}_loading_started`,
/** Triggered when a loading of data has ended. */
LOADING_ENDED: `${PROJECT_NAME}_loading_ended`,
+ /** Triggered when an error occurs during loading of data. */
+ LOADING_ERROR: `${PROJECT_NAME}_loading_error`,
/* Triggered when the loading of an image tile has started. */
FRAME_LOADING_STARTED: `${PROJECT_NAME}_frame_loading_started`,
/* Triggered when the loading of an image tile has ended. */
- FRAME_LOADING_ENDED: `${PROJECT_NAME}_frame_loading_ended`
+ FRAME_LOADING_ENDED: `${PROJECT_NAME}_frame_loading_ended`,
+ /* Triggered when the error occurs during loading of an image tile. */
+ FRAME_LOADING_ERROR: `${PROJECT_NAME}_frame_loading_ended`
}
export default EVENTS
@@ -79,7 +83,7 @@ Home
Namespaces
-
diff --git a/docs/global.html b/docs/global.html
index e4c560a4..0abe9661 100644
--- a/docs/global.html
+++ b/docs/global.html
@@ -1796,7 +1796,7 @@
Home
Namespaces
-
diff --git a/docs/index.html b/docs/index.html
index 720eda1d..040d9473 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -177,7 +177,7 @@
Home
Namespaces
-
diff --git a/docs/mapping.ParameterMapping.html b/docs/mapping.ParameterMapping.html
index 409bfe57..1e4b00dd 100644
--- a/docs/mapping.ParameterMapping.html
+++ b/docs/mapping.ParameterMapping.html
@@ -1010,7 +1010,7 @@
Home
Namespaces
-
diff --git a/docs/mapping.Transformation.html b/docs/mapping.Transformation.html
index 3714de3f..67966381 100644
--- a/docs/mapping.Transformation.html
+++ b/docs/mapping.Transformation.html
@@ -378,7 +378,7 @@
Home
Namespaces
-
diff --git a/docs/mapping.html b/docs/mapping.html
index b6085245..ef5d9f31 100644
--- a/docs/mapping.html
+++ b/docs/mapping.html
@@ -133,7 +133,7 @@
Home
Namespaces
-
diff --git a/docs/mapping.js.html b/docs/mapping.js.html
index c23260cf..0659bbd4 100644
--- a/docs/mapping.js.html
+++ b/docs/mapping.js.html
@@ -319,7 +319,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.Comprehensive3DSR.html b/docs/metadata.Comprehensive3DSR.html
index 09079be1..3f3dd69d 100644
--- a/docs/metadata.Comprehensive3DSR.html
+++ b/docs/metadata.Comprehensive3DSR.html
@@ -411,7 +411,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.MicroscopyBulkSimpleAnnotations.html b/docs/metadata.MicroscopyBulkSimpleAnnotations.html
index 9535dc31..c21c64ac 100644
--- a/docs/metadata.MicroscopyBulkSimpleAnnotations.html
+++ b/docs/metadata.MicroscopyBulkSimpleAnnotations.html
@@ -411,7 +411,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.ParametricMap.html b/docs/metadata.ParametricMap.html
index 644bf645..705767c3 100644
--- a/docs/metadata.ParametricMap.html
+++ b/docs/metadata.ParametricMap.html
@@ -411,7 +411,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.SOPClass.html b/docs/metadata.SOPClass.html
index 11cb55f3..53a639d9 100644
--- a/docs/metadata.SOPClass.html
+++ b/docs/metadata.SOPClass.html
@@ -390,7 +390,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.Segmentation.html b/docs/metadata.Segmentation.html
index d3e728c1..ca3ed80f 100644
--- a/docs/metadata.Segmentation.html
+++ b/docs/metadata.Segmentation.html
@@ -411,7 +411,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.VLWholeSlideMicroscopyImage.html b/docs/metadata.VLWholeSlideMicroscopyImage.html
index 2d57c28e..32c75a55 100644
--- a/docs/metadata.VLWholeSlideMicroscopyImage.html
+++ b/docs/metadata.VLWholeSlideMicroscopyImage.html
@@ -411,7 +411,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.html b/docs/metadata.html
index 3afd723c..3613c51b 100644
--- a/docs/metadata.html
+++ b/docs/metadata.html
@@ -633,7 +633,7 @@
Home
Namespaces
-
diff --git a/docs/metadata.js.html b/docs/metadata.js.html
index 2163e990..6aa1a919 100644
--- a/docs/metadata.js.html
+++ b/docs/metadata.js.html
@@ -622,7 +622,7 @@
Home
Namespaces
-
diff --git a/docs/module.exports_module.exports.html b/docs/module.exports_module.exports.html
index 8a60bc59..3654e68f 100644
--- a/docs/module.exports_module.exports.html
+++ b/docs/module.exports_module.exports.html
@@ -234,7 +234,7 @@
Home
Namespaces
-
diff --git a/docs/opticalPath.OpticalPath.html b/docs/opticalPath.OpticalPath.html
index 2153499e..f4f31968 100644
--- a/docs/opticalPath.OpticalPath.html
+++ b/docs/opticalPath.OpticalPath.html
@@ -1299,7 +1299,7 @@
Home
Namespaces
-
diff --git a/docs/opticalPath.html b/docs/opticalPath.html
index 50faf3ee..0ab123c3 100644
--- a/docs/opticalPath.html
+++ b/docs/opticalPath.html
@@ -130,7 +130,7 @@
Home
Namespaces
-
diff --git a/docs/opticalPath.js.html b/docs/opticalPath.js.html
index 74324cd0..1f445532 100644
--- a/docs/opticalPath.js.html
+++ b/docs/opticalPath.js.html
@@ -242,7 +242,7 @@
Home
Namespaces
-
diff --git a/docs/pyramid.js.html b/docs/pyramid.js.html
index a89652a4..9b8297c6 100644
--- a/docs/pyramid.js.html
+++ b/docs/pyramid.js.html
@@ -397,6 +397,8 @@
Source: pyramid.js
)
}
+ const studyInstanceUID = pyramid.metadata[z].StudyInstanceUID
+ const seriesInstanceUID = pyramid.metadata[z].SeriesInstanceUID
const path = pyramid.frameMappings[z][index]
let src
if (path != null) {
@@ -405,8 +407,8 @@ Source: pyramid.js
src += client.wadoURL
}
src += (
- '/studies/' + pyramid.metadata[z].StudyInstanceUID +
- '/series/' + pyramid.metadata[z].SeriesInstanceUID +
+ '/studies/' + studyInstanceUID +
+ '/series/' + seriesInstanceUID +
'/instances/' + path
)
}
@@ -421,8 +423,6 @@ Source: pyramid.js
const sopClassUID = refImage.SOPClassUID
if (src != null) {
- const studyInstanceUID = dwc.utils.getStudyInstanceUIDFromUri(src)
- const seriesInstanceUID = dwc.utils.getSeriesInstanceUIDFromUri(src)
const sopInstanceUID = dwc.utils.getSOPInstanceUIDFromUri(src)
const frameNumbers = dwc.utils.getFrameNumbersFromUri(src)
@@ -507,11 +507,7 @@ Source: pyramid.js
frameNumber: frameNumbers[0],
channelIdentifier: String(channel)
}
- publish(
- targetElement,
- EVENT.FRAME_LOADING_STARTED,
- frameInfo
- )
+ publish(targetElement, EVENT.FRAME_LOADING_STARTED, frameInfo)
const retrieveOptions = {
studyInstanceUID,
@@ -559,11 +555,8 @@ Source: pyramid.js
}
).catch(
(error) => {
- publish(
- targetElement,
- EVENT.FRAME_LOADING_ENDED,
- null
- )
+ publish(targetElement, EVENT.FRAME_LOADING_ENDED, frameInfo)
+ publish(targetElement, EVENT.FRAME_LOADING_ERROR, frameInfo)
return Promise.reject(
new Error(
`Failed to load frames ${frameNumbers} ` +
@@ -619,11 +612,11 @@ Source: pyramid.js
// Fit the pyramid levels to the reference image pyramid
const fittedPyramid = {
- extent: refPyramid.extent,
- origins: refPyramid.origins,
- resolutions: refPyramid.resolutions,
- gridSizes: refPyramid.gridSizes,
- tileSizes: refPyramid.tileSizes,
+ extent: [...refPyramid.extent],
+ origins: [...refPyramid.origins],
+ resolutions: [...refPyramid.resolutions],
+ gridSizes: [...refPyramid.gridSizes],
+ tileSizes: [...refPyramid.tileSizes],
pixelSpacings: [],
metadata: [],
frameMappings: []
@@ -632,9 +625,9 @@ Source: pyramid.js
const index = matchingLevelIndices.find(element => element[0] === i)
if (index) {
const j = index[1]
- fittedPyramid.gridSizes[i] = pyramid.gridSizes[j]
- fittedPyramid.tileSizes[i] = pyramid.tileSizes[j]
- fittedPyramid.pixelSpacings.push(pyramid.pixelSpacings[j])
+ fittedPyramid.gridSizes[i] = [...pyramid.gridSizes[j]]
+ fittedPyramid.tileSizes[i] = [...pyramid.tileSizes[j]]
+ fittedPyramid.pixelSpacings.push([...pyramid.pixelSpacings[j]])
fittedPyramid.metadata.push(pyramid.metadata[j])
fittedPyramid.frameMappings.push(pyramid.frameMappings[j])
} else {
@@ -670,7 +663,7 @@ Home
Namespaces
-
diff --git a/docs/roi.ROI.html b/docs/roi.ROI.html
index 5da5e3a8..b5cd95d6 100644
--- a/docs/roi.ROI.html
+++ b/docs/roi.ROI.html
@@ -134,7 +134,7 @@
Properties
-scoord3d.Scoord3D
+scoord3d.scoord3d
@@ -948,7 +948,7 @@ Home
Namespaces
-
diff --git a/docs/roi.html b/docs/roi.html
index c0f78bf0..8c1b09ab 100644
--- a/docs/roi.html
+++ b/docs/roi.html
@@ -130,7 +130,7 @@
Home
Namespaces
-
diff --git a/docs/roi.js.html b/docs/roi.js.html
index 25d13d35..126ff9d9 100644
--- a/docs/roi.js.html
+++ b/docs/roi.js.html
@@ -41,7 +41,7 @@
Source: roi.js
class ROI {
/**
* @param {Object} options - Options for construction of ROI
- * @param {scoord3d.Scoord3D} options.scoord3d - Spatial 3D coordinates
+ * @param {scoord3d.scoord3d} options.scoord3d - Spatial 3D coordinates
* @param {string} options.uid - Unique idenfifier
* @param {Object} options.properties - Properties (name-value pairs)
*/
@@ -113,7 +113,7 @@ Source: roi.js
* @type Object[]
*/
get measurements () {
- return this[_properties].measurements
+ return this[_properties][Enums.InternalProperties.Measurements].slice(0)
}
/**
@@ -122,7 +122,7 @@ Source: roi.js
* @type Object[]
*/
get evaluations () {
- return this[_properties].evaluations
+ return this[_properties][Enums.InternalProperties.Evaluations].slice(0)
}
/**
@@ -161,7 +161,7 @@ Home
Namespaces
-
diff --git a/docs/scoord3d.Ellipse.html b/docs/scoord3d.Ellipse.html
index 0446458e..fdf2f2c8 100644
--- a/docs/scoord3d.Ellipse.html
+++ b/docs/scoord3d.Ellipse.html
@@ -660,7 +660,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Ellipsoid.html b/docs/scoord3d.Ellipsoid.html
index 640e992a..6a0cc178 100644
--- a/docs/scoord3d.Ellipsoid.html
+++ b/docs/scoord3d.Ellipsoid.html
@@ -661,7 +661,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Multipoint.html b/docs/scoord3d.Multipoint.html
index 54526eb1..e6c6ee76 100644
--- a/docs/scoord3d.Multipoint.html
+++ b/docs/scoord3d.Multipoint.html
@@ -658,7 +658,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Point.html b/docs/scoord3d.Point.html
index d46ecba2..a91085d7 100644
--- a/docs/scoord3d.Point.html
+++ b/docs/scoord3d.Point.html
@@ -657,7 +657,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Polygon.html b/docs/scoord3d.Polygon.html
index 65179e8a..79334cf7 100644
--- a/docs/scoord3d.Polygon.html
+++ b/docs/scoord3d.Polygon.html
@@ -659,7 +659,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Polyline.html b/docs/scoord3d.Polyline.html
index 18d0e02e..e2bdf335 100644
--- a/docs/scoord3d.Polyline.html
+++ b/docs/scoord3d.Polyline.html
@@ -658,7 +658,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.Scoord3D.html b/docs/scoord3d.Scoord3D.html
index c0ce1d66..d95a68d4 100644
--- a/docs/scoord3d.Scoord3D.html
+++ b/docs/scoord3d.Scoord3D.html
@@ -599,7 +599,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.html b/docs/scoord3d.html
index f3b15e79..b936ef00 100644
--- a/docs/scoord3d.html
+++ b/docs/scoord3d.html
@@ -148,7 +148,7 @@
Home
Namespaces
-
diff --git a/docs/scoord3d.js.html b/docs/scoord3d.js.html
index e4c208ae..08da8f1c 100644
--- a/docs/scoord3d.js.html
+++ b/docs/scoord3d.js.html
@@ -395,7 +395,7 @@
Source: scoord3d.js
]
}
super({
- coordinates: coordinates,
+ coordinates,
frameOfReferenceUID: options.frameOfReferenceUID,
fiducialUID: options.fiducialUID
})
@@ -424,7 +424,7 @@ Home
Namespaces
-
diff --git a/docs/segment.Segment.html b/docs/segment.Segment.html
index 6c39c4a5..86332ae3 100644
--- a/docs/segment.Segment.html
+++ b/docs/segment.Segment.html
@@ -1295,7 +1295,7 @@
Home
Namespaces
-
diff --git a/docs/segment.html b/docs/segment.html
index fd828b25..2f13d675 100644
--- a/docs/segment.html
+++ b/docs/segment.html
@@ -130,7 +130,7 @@
Home
Namespaces
-
diff --git a/docs/segment.js.html b/docs/segment.js.html
index 65b72eee..62cda71a 100644
--- a/docs/segment.js.html
+++ b/docs/segment.js.html
@@ -242,7 +242,7 @@
Home
Namespaces
-
diff --git a/docs/utils.html b/docs/utils.html
index 1d3e5555..6815d8e4 100644
--- a/docs/utils.html
+++ b/docs/utils.html
@@ -1857,7 +1857,7 @@
(static)
- Computes the rotation of the image with respect to the frame of reference.
+ Compute the rotation of the image with respect to the frame of reference.
@@ -3634,7 +3634,7 @@ Home
Namespaces
-
diff --git a/docs/utils.js.html b/docs/utils.js.html
index 14bc3ad1..d1d9b0b5 100644
--- a/docs/utils.js.html
+++ b/docs/utils.js.html
@@ -130,7 +130,7 @@
Source: utils.js
}
/**
- * Computes the rotation of the image with respect to the frame of reference.
+ * Compute the rotation of the image with respect to the frame of reference.
*
* @param {Object} options - Options
* @param {number[]} options.orientation - Direction cosines along the row and column direction of the Total Pixel Matrix for each of the three axis of the slide coordinate system
@@ -399,7 +399,7 @@ Source: utils.js
offset,
spacing
})
- return applyTransform({ coordinate: point, affine: affine })
+ return applyTransform({ coordinate: point, affine })
}
/**
@@ -432,7 +432,7 @@ Source: utils.js
spacing
})
- return applyInverseTransform({ coordinate: point, affine: affine })
+ return applyInverseTransform({ coordinate: point, affine })
}
/**
@@ -672,6 +672,21 @@ Source: utils.js
})
}
+/**
+ * Convert RGB color triplet into hex code.
+ *
+ * @param {Number[]} values - RGB triplet
+ * @returns {String} Hex code
+ *
+ * @private
+ */
+function rgb2hex (values) {
+ const r = values[0]
+ const g = values[1]
+ const b = values[2]
+ return '#' + (0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1)
+}
+
export {
_getUnitSuffix,
applyInverseTransform,
@@ -679,6 +694,7 @@ Source: utils.js
buildInverseTransform,
buildTransform,
computeRotation,
+ createWindow,
_fetchBulkdata,
_generateUID,
mapPixelCoordToSlideCoord,
@@ -689,8 +705,8 @@ Source: utils.js
doContentItemsMatch,
areCodedConceptsEqual,
getContentItemNameCodedConcept,
- rescale,
- createWindow
+ rgb2hex,
+ rescale
}
@@ -708,7 +724,7 @@ Home
Namespaces
-
diff --git a/docs/viewer.LabelImageViewer.html b/docs/viewer.LabelImageViewer.html
index 07579885..23aa799c 100644
--- a/docs/viewer.LabelImageViewer.html
+++ b/docs/viewer.LabelImageViewer.html
@@ -364,7 +364,7 @@
Properties
- Source:
@@ -432,7 +432,7 @@ Home
Namespaces
-
diff --git a/docs/viewer.OverviewImageViewer.html b/docs/viewer.OverviewImageViewer.html
index 596252db..a07e5de1 100644
--- a/docs/viewer.OverviewImageViewer.html
+++ b/docs/viewer.OverviewImageViewer.html
@@ -365,7 +365,7 @@
Properties
- Source:
@@ -433,7 +433,7 @@ Home
Namespaces
+
+
+
+
+
+
+
+
+
+
+
+
The custom overlay HTML element
@@ -4155,46 +4251,114 @@ Properties
- className
+ coordinates
-string
+Array.<number>
+
+
+
+
+
+
- Class to style the overlay container
+
+
+
+
+
+
+ Offset of the overlay along the X and
+Y axes of the slide coordinate system
- offset
+ coordinates
-Array.<number>
+bool
+
+
+ <optional>
+
+
+
+
+
- Horizontal and vertical offset of the overlay container in pixels
+
+
+
+ false
+
+
+
+
+ Whether the viewer should
+automatically navigate to the element such that it is in focus and fully
+visible
+
+
+
+
+
+
+ className
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Class to style the overlay container
@@ -4242,7 +4406,7 @@ Properties
- Source:
@@ -4332,7 +4496,7 @@ cleanupSource:
@@ -4420,7 +4584,7 @@
- Source:
@@ -4508,7 +4672,7 @@ Source:
@@ -4596,7 +4760,7 @@ Source:
@@ -4684,7 +4848,7 @@ <
- Source:
@@ -4821,7 +4985,7 @@ Parameters:
- Source:
@@ -4909,7 +5073,7 @@ <
- Source:
@@ -4997,7 +5161,7 @@ Source:
@@ -5085,7 +5249,7 @@ Source:
@@ -5191,7 +5355,7 @@ Source:
@@ -5297,7 +5461,7 @@ get
- Source:
@@ -5403,7 +5567,7 @@ Source:
@@ -5509,7 +5673,7 @@ getAllROIs<
- Source:
@@ -5619,7 +5783,7 @@ getAllS
- Source:
@@ -5774,7 +5938,7 @@ Parameters:
- Source:
@@ -5933,7 +6097,7 @@ Parameters:
- Source:
@@ -6093,7 +6257,7 @@ Parameters:
- Source:
@@ -6252,7 +6416,7 @@ Parameters:
- Source:
@@ -6411,7 +6575,7 @@ Parameters:
- Source:
@@ -6571,7 +6735,7 @@ Parameters:
- Source:
@@ -6730,7 +6894,7 @@ Parameters:
- Source:
@@ -6889,7 +7053,7 @@ Parameters:
- Source:
@@ -7049,7 +7213,7 @@ Parameters:
- Source:
@@ -7257,7 +7421,7 @@ Properties
- Source:
@@ -7416,7 +7580,7 @@ Parameters:
- Source:
@@ -7575,7 +7739,7 @@ Parameters:
- Source:
@@ -7734,7 +7898,7 @@ Parameters:
- Source:
@@ -7893,7 +8057,7 @@ Parameters:
- Source:
@@ -8052,7 +8216,7 @@ Parameters:
- Source:
@@ -8211,7 +8375,7 @@ Parameters:
- Source:
@@ -8348,7 +8512,7 @@ Parameters:
- Source:
@@ -8485,7 +8649,7 @@ Parameters:
- Source:
@@ -8573,7 +8737,7 @@ hideROIsSource:
@@ -8710,7 +8874,7 @@ Parameters:
- Source:
@@ -8847,7 +9011,7 @@ Parameters:
- Source:
@@ -8984,7 +9148,7 @@ Parameters:
- Source:
@@ -9143,7 +9307,7 @@ Parameters:
- Source:
@@ -9302,7 +9466,7 @@ Parameters:
- Source:
@@ -9461,7 +9625,7 @@ Parameters:
- Source:
@@ -9616,7 +9780,7 @@ Parameters:
- Source:
@@ -9771,7 +9935,7 @@ Parameters:
- Source:
@@ -9998,7 +10162,7 @@ Properties
- Source:
@@ -10086,7 +10250,7 @@ popROISource:
@@ -10196,7 +10360,7 @@ Source:
@@ -10284,7 +10448,7 @@
- Source:
@@ -10372,7 +10536,7 @@ removeAl
- Source:
@@ -10460,7 +10624,7 @@ remo
- Source:
@@ -10597,7 +10761,7 @@ Parameters:
- Source:
@@ -10734,7 +10898,7 @@ Parameters:
- Source:
@@ -10871,7 +11035,7 @@ Parameters:
- Source:
@@ -11008,7 +11172,193 @@ Parameters:
- Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ removeViewportOverlay(options)
+
+
+
+
+
+
+
+ Remove an existing viewport overlay.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ options
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ Overlay options
+ Properties
+
+
+
+
+
+
+ Name
+
+
+ Type
+
+
+
+
+
+ Description
+
+
+
+
+
+
+
+
+ element
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+
+ The custom overlay HTML element
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
@@ -11197,7 +11547,7 @@ Properties
- Source:
@@ -11285,7 +11635,7 @@ resizeSource:
@@ -11436,6 +11786,8 @@ Properties
Type
+ Attributes
+
@@ -11461,6 +11813,16 @@ Properties
+
+
+ <optional>
+
+
+
+
+
+
+
@@ -11469,6 +11831,39 @@ Properties
+
+
+ color
+
+
+
+
+
+Array.<number>
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ RGB color triplet
+
+
+
+
measurement
@@ -11477,17 +11872,28 @@ Properties
-number
+Object
+
+
+ <optional>
+
+
+
+
+
+
+
- Selected measurement for colorizing annotations
+ Selected measurement for
+colorizing annotations
@@ -11535,7 +11941,7 @@ Properties
- Source:
@@ -11872,7 +12278,7 @@ Properties
- Source:
@@ -12126,7 +12532,7 @@ Properties
- Source:
@@ -12503,7 +12909,7 @@ Properties
- Source:
@@ -12724,7 +13130,7 @@ Properties
- Source:
@@ -12857,6 +13263,8 @@ Properties
Type
+ Attributes
+
@@ -12869,7 +13277,7 @@ Properties
- measurement
+ opacity
@@ -12882,10 +13290,86 @@ Properties
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ Opacity
+
+
+
+
+
+
+ color
+
+
+
+
+
+Array.<number>
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
+
+
+
+ RGB color triplet
+
+
+
+
+
+
+ measurement
+
+
+
+
+
+Object
+
+
+
+
+
+
+
+
+ <optional>
+
+
+
+
+
+
+
- Selected measurement for colorizing annotations
+ Selected measurement
@@ -12933,7 +13417,7 @@ Properties
- Source:
@@ -13275,7 +13759,7 @@ Properties
- Source:
@@ -13549,7 +14033,7 @@ Properties
- Source:
@@ -13637,7 +14121,7 @@ showROIsSource:
@@ -13878,7 +14362,7 @@ Properties
- Source:
@@ -13966,7 +14450,7 @@ togg
- Source:
@@ -14353,7 +14837,7 @@ Properties
- Source:
@@ -14405,7 +14889,7 @@ Home
Namespaces
-
diff --git a/docs/viewer.html b/docs/viewer.html
index 7a83452d..9eef5b4a 100644
--- a/docs/viewer.html
+++ b/docs/viewer.html
@@ -136,7 +136,7 @@
Home
Namespaces
-
diff --git a/docs/viewer.js.html b/docs/viewer.js.html
index 1890a32a..5e292424 100644
--- a/docs/viewer.js.html
+++ b/docs/viewer.js.html
@@ -67,7 +67,6 @@
Source: viewer.js
import { getCenter, getHeight, getWidth } from 'ol/extent'
import { defaults as defaultInteractions } from 'ol/interaction'
import dcmjs from 'dcmjs'
-import { quantileSeq } from 'mathjs'
import {
AnnotationGroup,
@@ -93,14 +92,17 @@ Source: viewer.js
import { ROI } from './roi.js'
import { Segment } from './segment.js'
import {
+ areCodedConceptsEqual,
applyTransform,
buildInverseTransform,
buildTransform,
computeRotation,
+ getContentItemNameCodedConcept,
_generateUID,
_getUnitSuffix,
doContentItemsMatch,
- createWindow
+ createWindow,
+ rgb2hex
} from './utils.js'
import {
_scoord3dCoordinates2geometryCoordinates,
@@ -658,7 +660,7 @@ Source: viewer.js
* @private
*/
function _getColorPaletteStyleForPointLayer ({
- name,
+ key,
minValue,
maxValue,
colormap
@@ -677,7 +679,7 @@ Source: viewer.js
'*',
[
'-',
- ['get', name],
+ ['get', key],
minValue
],
[
@@ -710,6 +712,9 @@ Source: viewer.js
const _affine = Symbol('affine')
const _affineInverse = Symbol('affineInverse')
+const _annotationManager = Symbol('annotationManager')
+const _annotationGroups = Symbol('annotationGroups')
+const _areIccProfilesFetched = Symbol('areIccProfilesFetched')
const _controls = Symbol('controls')
const _drawingLayer = Symbol('drawingLayer')
const _drawingSource = Symbol('drawingSource')
@@ -719,17 +724,15 @@ Source: viewer.js
const _map = Symbol('map')
const _mappings = Symbol('mappings')
const _metadata = Symbol('metadata')
-const _areIccProfilesFetched = Symbol('areIccProfilesFetched')
+const _opticalPaths = Symbol('opticalPaths')
const _options = Symbol('options')
+const _overlays = Symbol('overlays')
+const _overviewMap = Symbol('overviewMap')
+const _projection = Symbol('projection')
const _pyramid = Symbol('pyramid')
const _segments = Symbol('segments')
-const _opticalPaths = Symbol('opticalPaths')
const _rotation = Symbol('rotation')
-const _projection = Symbol('projection')
const _tileGrid = Symbol('tileGrid')
-const _annotationManager = Symbol('annotationManager')
-const _annotationGroups = Symbol('annotationGroups')
-const _overviewMap = Symbol('overviewMap')
const _updateOverviewMapSize = Symbol('updateOverviewMapSize')
/**
@@ -757,6 +760,10 @@ Source: viewer.js
* turned on (e.g., display of tile boundaries)
* @param {number} [options.tilesCacheSize=1000] - Number of tiles that should
* be cached to avoid repeated retrieval for the DICOMweb server
+ * @param {number[]} [options.primaryColor=[0, 126, 163]] - Primary color of
+ * the application
+ * @param {number[]} [options.highlightColor=[140, 184, 198]] - Color that
+ * should be used to highlight things that get selected by the user
*/
constructor (options) {
this[_options] = options
@@ -782,6 +789,13 @@ Source: viewer.js
}
this[_options].controls = new Set(this[_options].controls)
+ if (this[_options].primaryColor == null) {
+ this[_options].primaryColor = [0, 126, 163]
+ }
+ if (this[_options].highlightColor == null) {
+ this[_options].highlightColor = [140, 184, 198]
+ }
+
// Collection of Openlayers "TileLayer" instances
this[_segments] = {}
this[_mappings] = {}
@@ -1033,14 +1047,14 @@ Source: viewer.js
}),
paletteColorLookupTableUID
}),
- pyramid: pyramid,
+ pyramid,
style: { ...defaultOpticalPathStyle },
defaultStyle: defaultOpticalPathStyle,
- bitsAllocated: bitsAllocated,
+ bitsAllocated,
minStoredValue,
maxStoredValue,
loaderParams: {
- pyramid: pyramid,
+ pyramid,
client: this[_options].client,
channel: opticalPathIdentifier
},
@@ -1157,12 +1171,12 @@ Source: viewer.js
}),
style: { ...defaultOpticalPathStyle },
defaultStyle: defaultOpticalPathStyle,
- pyramid: pyramid,
+ pyramid,
bitsAllocated: 8,
minStoredValue: 0,
maxStoredValue: 255,
loaderParams: {
- pyramid: pyramid,
+ pyramid,
client: this[_options].client,
channel: opticalPathIdentifier
},
@@ -1293,10 +1307,10 @@ Source: viewer.js
const map = this[_overviewMap].getOverviewMap()
const overviewElement = this[_overviewMap].element
- const overviewChildren = overviewElement.children
- const overviewmapElement = Object.values(overviewChildren).find(
+ const overviewmapElement = Object.values(overviewElement.children).find(
c => c.className === 'ol-overviewmap-map'
)
+ // TODO: color "ol-overviewmap-map-box" using primary color
overviewmapElement.style.width = `${width}px`
overviewmapElement.style.height = `${height}px`
map.updateSize()
@@ -1413,6 +1427,8 @@ Source: viewer.js
affine: this[_affine],
drawingSource: this[_drawingSource]
})
+
+ this[_overlays] = {}
}
/**
@@ -1499,8 +1515,8 @@ Source: viewer.js
opticalPath.overviewLayer.setStyle(style)
} else {
const styleVariables = {
- windowCenter: windowCenter,
- windowWidth: windowWidth,
+ windowCenter,
+ windowWidth,
red: opticalPath.style.color[0],
green: opticalPath.style.color[1],
blue: opticalPath.style.color[2]
@@ -1509,10 +1525,7 @@ Source: viewer.js
opticalPath.overviewLayer.updateStyleVariables(styleVariables)
}
} else {
- const styleVariables = {
- windowCenter: windowCenter,
- windowWidth: windowWidth
- }
+ const styleVariables = { windowCenter, windowWidth }
opticalPath.layer.updateStyleVariables(styleVariables)
opticalPath.overviewLayer.updateStyleVariables(styleVariables)
}
@@ -2759,7 +2772,20 @@ Source: viewer.js
* @param {number[]} styleOptions.fill.color - RGBA color of the body
*/
addROI (roi, styleOptions = {}) {
- console.info(`add ROI ${roi.uid}`)
+ console.info(`add ROI "${roi.uid}"`)
+
+ // Avoid insertion of duplicates
+ let exists = false
+ for (let i = 0; i < this[_features].getLength(); i++) {
+ const feature = this[_features].item(i)
+ if (feature.getId() === roi.uid) {
+ exists = true
+ break
+ }
+ }
+ if (exists) {
+ console.warn(`ROI "${roi.uid}" not added because it already exists`)
+ }
const frameOfReferenceUID = this[_pyramid].metadata.FrameOfReferenceUID
if (roi.frameOfReferenceUID !== frameOfReferenceUID) {
@@ -2871,21 +2897,51 @@ Source: viewer.js
/**
* Add a new viewport overlay.
*
- * @param {Object} options Overlay options
- * @param {Object} options.element The custom overlay HTML element
- * @param {string} options.className Class to style the overlay container
- * @param {number[]} options.offset Horizontal and vertical offset of the overlay container in pixels
+ * @param {Object} options - Overlay options
+ * @param {Object} options.element - The custom overlay HTML element
+ * @param {number[]} options.coordinates - Offset of the overlay along the X and
+ * Y axes of the slide coordinate system
+ * @param {bool} [options.coordinates=false] - Whether the viewer should
+ * automatically navigate to the element such that it is in focus and fully
+ * visible
+ * @param {string} [options.className] - Class to style the overlay container
*/
- addViewportOverlay ({ element, className, offset }) {
+ addViewportOverlay ({ element, coordinates, navigate, className }) {
+ const offset = _scoord3dCoordinates2geometryCoordinates(
+ coordinates,
+ this[_pyramid],
+ this[_affineInverse]
+ )
const overlay = new Overlay({
element,
- className,
+ className: (
+ className != null
+ ? `ol-overlay-container ol-selectable ${className}`
+ : 'ol-overlay-container ol-selectable'
+ ),
offset,
+ autoPan: navigate != null ? navigate : false,
stopEvent: false
})
+ this[_overlays][element.id] = overlay
this[_map].addOverlay(overlay)
}
+ /**
+ * Remove an existing viewport overlay.
+ *
+ * @param {Object} options - Overlay options
+ * @param {Object} options.element - The custom overlay HTML element
+ */
+ removeViewportOverlay ({ element }) {
+ const id = element.id
+ if (id in this[_overlays]) {
+ const overlay = this[_overlays][id]
+ this[_map].removeOverlay(overlay)
+ delete this[_overlays][id]
+ }
+ }
+
/**
* Remove an individual regions of interest.
*
@@ -2963,7 +3019,108 @@ Source: viewer.js
const defaultAnnotationGroupStyle = {
opacity: 1.0,
- color: '#027ea3'
+ color: this[_options].primaryColor
+ }
+
+ // We need to bind those variables to constants for the loader function
+ const client = this[_options].client
+ const pyramid = this[_pyramid].metadata
+ const affineInverse = this[_affineInverse]
+ const container = this[_map].getTargetElement()
+ const _getROIFromFeature = (feature) => {
+ const roi = this._getROIFromFeature(
+ feature,
+ this[_pyramid].metadata,
+ this[_affine]
+ )
+ const annotationGroupUID = feature.get('annotationGroupUID')
+ const annotationGroupMetadata = metadata.AnnotationGroupSequence.find(
+ item => item.AnnotationGroupUID === annotationGroupUID
+ )
+
+ const findingCategory = (
+ annotationGroupMetadata
+ .AnnotationPropertyCategoryCodeSequence[0]
+ )
+ roi.addEvaluation(
+ new dcmjs.sr.valueTypes.CodeContentItem({
+ name: new dcmjs.sr.coding.CodedConcept({
+ value: '276214006',
+ meaning: 'Finding category',
+ schemeDesignator: 'SCT'
+ }),
+ value: new dcmjs.sr.coding.CodedConcept({
+ value: findingCategory.CodeValue,
+ meaning: findingCategory.CodeMeaning,
+ schemeDesignator: findingCategory.CodingSchemeDesignator
+ }),
+ relationshipType: dcmjs.sr.valueTypes.RelationshipTypes.HAS_CONCEPT_MOD
+ })
+ )
+ const findingType = (
+ annotationGroupMetadata
+ .AnnotationPropertyTypeCodeSequence[0]
+ )
+ roi.addEvaluation(
+ new dcmjs.sr.valueTypes.CodeContentItem({
+ name: new dcmjs.sr.coding.CodedConcept({
+ value: '121071',
+ meaning: 'Finding',
+ schemeDesignator: 'DCM'
+ }),
+ value: new dcmjs.sr.coding.CodedConcept({
+ value: findingType.CodeValue,
+ meaning: findingType.CodeMeaning,
+ schemeDesignator: findingType.CodingSchemeDesignator
+ }),
+ relationshipType: dcmjs.sr.valueTypes.RelationshipTypes.HAS_CONCEPT_MOD
+ })
+ )
+
+ annotationGroupMetadata.MeasurementsSequence.forEach(
+ (measurementItem, measurementIndex) => {
+ const key = `measurementValue${measurementIndex.toString()}`
+ const value = feature.get(key)
+ const name = measurementItem.ConceptNameCodeSequence[0]
+ const unit = measurementItem.MeasurementUnitsCodeSequence[0]
+
+ const measurement = new dcmjs.sr.valueTypes.NumContentItem({
+ value: Number(value),
+ name: new dcmjs.sr.coding.CodedConcept({
+ value: name.CodeValue,
+ meaning: name.CodeMeaning,
+ schemeDesignator: name.CodingSchemeDesignator
+ }),
+ unit: new dcmjs.sr.coding.CodedConcept({
+ value: unit.CodeValue,
+ meaning: unit.CodeMeaning,
+ schemeDesignator: unit.CodingSchemeDesignator
+ }),
+ relationshipType: dcmjs.sr.valueTypes.RelationshipTypes.CONTAINS
+ })
+ if (measurementItem.ReferencedImageSequence != null) {
+ const ref = measurementItem.ReferencedImageSequence[0]
+ const image = new dcmjs.sr.valueTypes.ImageContentItem({
+ name: new dcmjs.sr.coding.CodedConcept({
+ value: '121112',
+ meaning: 'Source of Measurement',
+ schemeDesignator: 'DCM'
+ }),
+ referencedSOPClassUID: ref.ReferencedSOPClassUID,
+ referencedSOPInstanceUID: ref.ReferencedSOPInstanceUID
+ })
+ if (ref.ReferencedOpticalPathIdentifier != null) {
+ image.ReferencedSOPSequence[0].ReferencedOpticalPathIdentifier = (
+ ref.ReferencedOpticalPathIdentifier
+ )
+ }
+ measurement.ContentSequence = [image]
+ }
+ roi.addMeasurement(measurement)
+ }
+ )
+
+ return roi
}
metadata.AnnotationGroupSequence.forEach((item, index) => {
@@ -2984,7 +3141,7 @@ Source: viewer.js
}),
style: { ...defaultAnnotationGroupStyle },
defaultStyle: defaultAnnotationGroupStyle,
- metadata: metadata
+ metadata
}
if (item.GraphicType === 'POLYLINE') {
@@ -2999,11 +3156,6 @@ Source: viewer.js
return
}
- // We need to bind those variables to constants for the loader function
- const client = this[_options].client
- const pyramid = this[_pyramid].metadata
- const affineInverse = this[_affineInverse]
-
/**
* In the loader function "this" is bound to the vector source.
*/
@@ -3047,6 +3199,7 @@ Source: viewer.js
const graphicIndex = retrievedBulkdata[1]
const measurements = retrievedBulkdata[2]
+ console.log('process annotations')
for (let i = 0; i < numberOfAnnotations; i++) {
const point = _getCentroid(
graphicType,
@@ -3065,15 +3218,16 @@ Source: viewer.js
const feature = new Feature({
geometry: new PointGeometry(coordinates)
})
- const properties = {}
- measurements.forEach(item => {
- const name = item.name
- const key = `${name.CodingSchemeDesignator}${name.CodeValue}`
- const value = item.values[i]
- properties[key] = value
+
+ feature.set('annotationGroupUID', annotationGroupUID, true)
+ measurements.forEach((measurementItem, measurementIndex) => {
+ const key = `measurementValue${measurementIndex.toString()}`
+ const value = measurementItem.values[i]
+ // Needed for the WebGL renderer
+ feature.set(key, value, true)
})
- feature.setProperties(properties)
- feature.setId(i + 1)
+ const uid = _generateUID({ value: `${annotationGroupUID}-${i}` })
+ feature.setId(uid)
features.push(feature)
}
@@ -3082,17 +3236,28 @@ Source: viewer.js
`for annotation group "${annotationGroupUID}"`
)
this.addFeatures(features)
+ console.info(
+ 'compute statistics for measurement values ' +
+ `of annotation group "${annotationGroupUID}"`
+ )
const properties = {}
- measurements.forEach(item => {
- const name = item.name
- const key = `${name.CodingSchemeDesignator}${name.CodeValue}`
- const value = quantileSeq(
- [...item.values],
- [0, 0.015, 0.25, 0.5, 0.75, 0.95, 1]
+ measurements.forEach((measurementItem, measurementIndex) => {
+ /*
+ * Ideally, we would compute quantiles, but that is an expensive
+ * operation. For now, just compute mininum and maximum.
+ */
+ const min = measurementItem.values.reduce(
+ (a, b) => Math.min(a, b),
+ Infinity
+ )
+ const max = measurementItem.values.reduce(
+ (a, b) => Math.max(a, b),
+ -Infinity
)
- properties[key] = value
+ const key = `measurementValue${measurementIndex.toString()}`
+ properties[key] = { min, max }
})
- this.setProperties(properties)
+ this.setProperties(properties, true)
success(features)
}).catch(error => {
console.error(error)
@@ -3117,6 +3282,7 @@ Source: viewer.js
source.on('featuresloaderror', (event) => {
const container = this[_map].getTargetElement()
publish(container, EVENT.LOADING_ENDED)
+ publish(container, EVENT.LOADING_ERROR)
})
/*
@@ -3143,13 +3309,39 @@ Source: viewer.js
annotationGroup.layer = new PointsLayer({
source,
style,
- disableHitDetection: true
+ disableHitDetection: false
})
annotationGroup.layer.setVisible(false)
this[_map].addLayer(annotationGroup.layer)
this[_annotationGroups][annotationGroupUID] = annotationGroup
})
+
+ let selectedAnnotation = null
+ this[_map].on('singleclick', (e) => {
+ if (selectedAnnotation !== null) {
+ selectedAnnotation.set('selected', 0)
+ selectedAnnotation = null
+ }
+
+ this[_map].forEachFeatureAtPixel(
+ e.pixel,
+ (feature) => {
+ feature.set('selected', 1)
+ selectedAnnotation = feature
+ publish(
+ container,
+ EVENT.ROI_SELECTED,
+ _getROIFromFeature(feature)
+ )
+ return true
+ },
+ {
+ hitTolerance: 1,
+ layerFilter: (layer) => (layer instanceof PointsLayer)
+ }
+ )
+ })
}
/**
@@ -3185,7 +3377,9 @@ Source: viewer.js
*
* @param {string} annotationGroupUID - Unique identifier of an annotation group
* @param {Object} styleOptions
- * @param {number} styleOptions.measurement - Selected measurement for colorizing annotations
+ * @param {number} [styleOptions.opacity] - Opacity
+ * @param {number[]} [styleOptions.color] - RGB color triplet
+ * @param {Object} [styleOptions.measurement] - Selected measurement
*/
showAnnotationGroup (annotationGroupUID, styleOptions = {}) {
if (!(annotationGroupUID in this[_annotationGroups])) {
@@ -3238,8 +3432,10 @@ Source: viewer.js
*
* @param {string} annotationGroupUID - Unique identifier of an annotation group
* @param {Object} styleOptions - Style options
- * @param {number} styleOptions.opacity - Opacity
- * @param {number} styleOptions.measurement - Selected measurement for colorizing annotations
+ * @param {number} [styleOptions.opacity] - Opacity
+ * @param {number[]} [styleOptions.color] - RGB color triplet
+ * @param {Object} [styleOptions.measurement] - Selected measurement for
+ * colorizing annotations
*/
setAnnotationGroupStyle (annotationGroupUID, styleOptions = {}) {
if (!(annotationGroupUID in this[_annotationGroups])) {
@@ -3253,17 +3449,41 @@ Source: viewer.js
annotationGroup.style.opacity = styleOptions.opacity
annotationGroup.layer.setOpacity(styleOptions.opacity)
}
+ if (styleOptions.color != null) {
+ annotationGroup.style.color = styleOptions.color
+ }
+ console.info(
+ `set style for annotation group "${annotationGroupUID}"`,
+ styleOptions
+ )
+ const metadata = annotationGroup.metadata
const source = annotationGroup.layer.getSource()
+ const groupItem = metadata.AnnotationGroupSequence.find(item => {
+ return item.AnnotationGroupUID === annotationGroupUID
+ })
+ if (groupItem == null) {
+ throw new Error(
+ 'Cannot set style of annotation group. ' +
+ `Could not find metadata of annotation group "${annotationGroupUID}".`
+ )
+ }
+
const name = styleOptions.measurement
if (name) {
- const key = `${name.CodingSchemeDesignator}${name.CodeValue}`
+ const measurementIndex = groupItem.MeasurementsSequence.findIndex(item => {
+ return areCodedConceptsEqual(name, getContentItemNameCodedConcept(item))
+ })
+ if (measurementIndex == null) {
+ throw new Error(
+ 'Cannot set style of annotation group. ' +
+ `Could not find measurement "${name.CodeMeaning}" ` +
+ `of annotation group "${annotationGroupUID}".`
+ )
+ }
const properties = source.getProperties()
+ const key = `measurementValue${measurementIndex.toString()}`
if (properties[key]) {
- const colormap = createColormap({
- name: ColormapNames.VIRIDIS,
- bins: 50
- })
const style = {
symbol: {
symbolType: 'circle',
@@ -3279,19 +3499,24 @@ Source: viewer.js
opacity: annotationGroup.style.opacity
}
}
+ const colormap = createColormap({
+ name: ColormapNames.VIRIDIS,
+ bins: 50
+ })
Object.assign(
- style,
+ style.symbol,
_getColorPaletteStyleForPointLayer({
- name: key,
- minValue: properties[key][0],
- maxValue: properties[key][properties[key].length - 2],
+ key,
+ minValue: properties[key].min,
+ maxValue: properties[key].max,
colormap
})
)
const newLayer = new PointsLayer({
source,
style,
- disableHitDetection: true
+ disableHitDetection: false,
+ visible: false
})
this[_map].addLayer(newLayer)
this[_map].removeLayer(annotationGroup.layer)
@@ -3311,20 +3536,28 @@ Source: viewer.js
this[_pyramid].metadata.length,
15
],
- color: annotationGroup.style.color,
+ color: [
+ 'match',
+ ['get', 'selected'],
+ 1,
+ rgb2hex(this[_options].highlightColor),
+ rgb2hex(annotationGroup.style.color)
+ ],
opacity: annotationGroup.style.opacity
}
}
const newLayer = new PointsLayer({
source,
style,
- disableHitDetection: true
+ disableHitDetection: false,
+ visible: false
})
this[_map].addLayer(newLayer)
this[_map].removeLayer(annotationGroup.layer)
annotationGroup.layer.dispose()
annotationGroup.layer = newLayer
}
+ annotationGroup.layer.setVisible(true)
}
/**
@@ -3544,7 +3777,7 @@ Source: viewer.js
}
const source = new DataTileSource({
- tileGrid: tileGrid,
+ tileGrid,
projection: this[_projection],
wrapX: false,
bandCount: 1,
@@ -4013,7 +4246,7 @@ Source: viewer.js
return element.SOPInstanceUID
})
}),
- pyramid: pyramid,
+ pyramid,
overlay: new Overlay({
element: document.createElement('div'),
offset: [5 + 100 * index + 2, 5]
@@ -4033,7 +4266,7 @@ Source: viewer.js
}
const source = new DataTileSource({
- tileGrid: tileGrid,
+ tileGrid,
projection: this[_projection],
wrapX: false,
bandCount: 1,
@@ -4389,7 +4622,7 @@ Source: viewer.js
seriesInstanceUID: this[_metadata].SeriesInstanceUID,
sopInstanceUID: this[_metadata].SOPInstanceUID,
mediaTypes: [{ mediaType }],
- queryParams: queryParams
+ queryParams
}
options.client.retrieveInstanceRendered(retrieveOptions).then(
(thumbnail) => {
@@ -4402,7 +4635,7 @@ Source: viewer.js
const projection = new Projection({
code: 'DICOM',
units: 'metric',
- extent: extent,
+ extent,
getPointResolution: (pixelRes, point) => {
/*
* DICOM Pixel Spacing has millimeter unit while the projection has
@@ -4416,12 +4649,12 @@ Source: viewer.js
const source = new Static({
imageExtent: extent,
- projection: projection,
- imageLoadFunction: imageLoadFunction,
+ projection,
+ imageLoadFunction,
url: '' // will be set by imageLoadFunction()
})
- this[_imageLayer] = new ImageLayer({ source: source })
+ this[_imageLayer] = new ImageLayer({ source })
// The default rotation is 'horizontal' with the slide label on the right
let rotation = _getRotation(this[_metadata])
@@ -4432,9 +4665,9 @@ Source: viewer.js
const view = new View({
center: getCenter(extent),
- rotation: rotation,
- projection: projection,
- extent: extent,
+ rotation,
+ projection,
+ extent,
smoothExtentConstraint: true,
smoothResolutionConstraint: true,
showFullExtent: true
@@ -4443,7 +4676,7 @@ Source: viewer.js
// Creates the map with the defined layers and view and renders it.
this[_map] = new Map({
layers: [this[_imageLayer]],
- view: view,
+ view,
controls: [],
keyboardEventTarget: document
})
@@ -4594,7 +4827,7 @@ Home
Namespaces
-
diff --git a/docs/webWorker_decoders_decoderAbstract.js.html b/docs/webWorker_decoders_decoderAbstract.js.html
index 16618b3e..3c067428 100644
--- a/docs/webWorker_decoders_decoderAbstract.js.html
+++ b/docs/webWorker_decoders_decoderAbstract.js.html
@@ -73,7 +73,7 @@
Home
Namespaces