Skip to content

Commit 1ead560

Browse files
committed
Merge branch 'master' of github:mghcomputationalpathology/dicom-microscopy-viewer
2 parents 0862326 + b65ecfe commit 1ead560

File tree

1 file changed

+47
-36
lines changed

1 file changed

+47
-36
lines changed

src/viewer.js

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import publish from "./eventPublisher";
1414
import ScaleLine from 'ol/control/ScaleLine';
1515
import Select from 'ol/interaction/Select';
1616
import Static from 'ol/source/ImageStatic';
17+
import Overlay from 'ol/Overlay';
1718
import TileLayer from 'ol/layer/Tile';
1819
import TileImage from 'ol/source/TileImage';
1920
import TileGrid from 'ol/tilegrid/TileGrid';
@@ -34,9 +35,9 @@ import { toStringXY, rotate } from 'ol/coordinate';
3435
import { VLWholeSlideMicroscopyImage, getFrameMapping } from './metadata.js';
3536
import { ROI } from './roi.js';
3637
import {
37-
generateUID,
38-
mapPixelCoordToSlideCoord,
39-
mapSlideCoordToPixelCoord
38+
generateUID,
39+
mapPixelCoordToSlideCoord,
40+
mapSlideCoordToPixelCoord
4041
} from './utils.js';
4142
import {
4243
Point,
@@ -47,8 +48,7 @@ import {
4748
Ellipse
4849
} from './scoord3d.js';
4950

50-
import DICOMwebClient from 'dicomweb-client/build/dicomweb-client.js'
51-
51+
import * as DICOMwebClient from 'dicomweb-client';
5252

5353
/** Extracts value of Pixel Spacing attribute from metadata.
5454
*
@@ -173,7 +173,7 @@ function _getRotation(metadata) {
173173
*/
174174
function _geometry2Scoord3d(geometry, pyramid) {
175175
console.info('map coordinates from pixel matrix to slide coordinate system')
176-
const frameOfReferenceUID = pyramid[pyramid.length-1].FrameOfReferenceUID;
176+
const frameOfReferenceUID = pyramid[pyramid.length - 1].FrameOfReferenceUID;
177177
const type = geometry.getType();
178178
if (type === 'Point') {
179179
let coordinates = geometry.getCoordinates();
@@ -213,7 +213,7 @@ function _geometry2Scoord3d(geometry, pyramid) {
213213
[center[0], center[1] + radius, 0],
214214
];
215215
coordinates = coordinates.map(c => {
216-
return _geometryCoordinates2scoord3dCoordinates(c, pyramid);
216+
return _geometryCoordinates2scoord3dCoordinates(c, pyramid);
217217
})
218218

219219
// const metadata = pyramid[pyramid.length-1];
@@ -250,7 +250,7 @@ function _scoord3d2Geometry(scoord3d, pyramid) {
250250
return _scoord3dCoordinates2geometryCoordinates(d, pyramid);
251251
});
252252
return new LineStringGeometry(coordinates);
253-
} else if(type === 'POLYGON'){
253+
} else if (type === 'POLYGON') {
254254
const coordinates = data.map(d => {
255255
return _scoord3dCoordinates2geometryCoordinates(d, pyramid);
256256
});
@@ -276,7 +276,7 @@ function _scoord3d2Geometry(scoord3d, pyramid) {
276276
return _scoord3dCoordinates2geometryCoordinates(d, pyramid);
277277
});
278278
// to flat coordinates
279-
coordinates = [...coordinates[0].slice(0,2), ...coordinates[1].slice(0,2)];
279+
coordinates = [...coordinates[0].slice(0, 2), ...coordinates[1].slice(0, 2)];
280280

281281
// flat coordinates in combination with opt_layout and no opt_radius are also accepted
282282
// and internaly it calculates the Radius
@@ -304,11 +304,11 @@ function _scoord3dCoordinates2geometryCoordinates(coordinates, pyramid) {
304304
*/
305305
function _coordinateFormatGeometry2Scoord3d(coordinates, pyramid) {
306306
let transform = false;
307-
if(!Array.isArray(coordinates[0])) {
307+
if (!Array.isArray(coordinates[0])) {
308308
coordinates = [coordinates];
309309
transform = true;
310310
}
311-
const metadata = pyramid[pyramid.length-1];
311+
const metadata = pyramid[pyramid.length - 1];
312312
const origin = metadata.TotalPixelMatrixOriginSequence[0];
313313
const orientation = metadata.ImageOrientationSlide;
314314
const spacing = _getPixelSpacing(metadata);
@@ -344,11 +344,11 @@ function _coordinateFormatGeometry2Scoord3d(coordinates, pyramid) {
344344
*/
345345
function _coordinateFormatScoord3d2Geometry(coordinates, pyramid) {
346346
let transform = false;
347-
if(!Array.isArray(coordinates[0])) {
347+
if (!Array.isArray(coordinates[0])) {
348348
coordinates = [coordinates];
349349
transform = true;
350350
}
351-
const metadata = pyramid[pyramid.length-1];
351+
const metadata = pyramid[pyramid.length - 1];
352352
const orientation = metadata.ImageOrientationSlide;
353353
const spacing = _getPixelSpacing(metadata);
354354
const origin = metadata.TotalPixelMatrixOriginSequence[0];
@@ -357,7 +357,7 @@ function _coordinateFormatScoord3d2Geometry(coordinates, pyramid) {
357357
Number(origin.YOffsetInSlideCoordinateSystem),
358358
];
359359

360-
coordinates = coordinates.map(c =>{
360+
coordinates = coordinates.map(c => {
361361
const slideCoord = [c[0], c[1]];
362362
const pixelCoord = mapSlideCoordToPixelCoord({
363363
offset,
@@ -381,7 +381,7 @@ function _coordinateFormatScoord3d2Geometry(coordinates, pyramid) {
381381
* @returns {ROI} Region of interest
382382
* @private
383383
*/
384-
function _getROIFromFeature(feature, pyramid){
384+
function _getROIFromFeature(feature, pyramid) {
385385
let roi = {}
386386
if (feature !== undefined) {
387387
const geometry = feature.getGeometry();
@@ -391,7 +391,7 @@ function _getROIFromFeature(feature, pyramid){
391391
const geometryName = feature.getGeometryName();
392392
delete properties[geometryName];
393393
const uid = feature.getId();
394-
roi = new ROI({scoord3d, properties, uid});
394+
roi = new ROI({ scoord3d, properties, uid });
395395
}
396396
return roi;
397397
}
@@ -453,7 +453,7 @@ class VolumeImageViewer {
453453
this[_segmentations] = {};
454454

455455
// Collection of Openlayers "Feature" instances
456-
this[_features] = new Collection([], {unique: true});
456+
this[_features] = new Collection([], { unique: true });
457457
// Add unique identifier to each created "Feature" instance
458458
this[_features].on('add', (e) => {
459459
// The ID may have already been set when drawn. However, features could
@@ -470,7 +470,7 @@ class VolumeImageViewer {
470470
*/
471471
this[_metadata] = [];
472472
options.metadata.forEach(m => {
473-
const image = new VLWholeSlideMicroscopyImage({metadata: m});
473+
const image = new VLWholeSlideMicroscopyImage({ metadata: m });
474474
if (image.ImageType[2] === 'VOLUME') {
475475
this[_metadata].push(image);
476476
}
@@ -504,9 +504,9 @@ class VolumeImageViewer {
504504
let index = null;
505505
for (let j = 0; j < this[_pyramidMetadata].length; j++) {
506506
if (
507-
(this[_pyramidMetadata][j].TotalPixelMatrixColumns === cols) &&
508-
(this[_pyramidMetadata][j].TotalPixelMatrixRows === rows)
509-
) {
507+
(this[_pyramidMetadata][j].TotalPixelMatrixColumns === cols) &&
508+
(this[_pyramidMetadata][j].TotalPixelMatrixRows === rows)
509+
) {
510510
alreadyExists = true;
511511
index = j;
512512
}
@@ -618,7 +618,7 @@ class VolumeImageViewer {
618618
const path = pyramidFrameMappings[z][index];
619619
if (path === undefined) {
620620
console.warn("tile " + index + " not found at level " + z);
621-
return(null);
621+
return (null);
622622
}
623623
let url = options.client.wadoURL +
624624
"/studies/" + pyramid[z].StudyInstanceUID +
@@ -627,7 +627,7 @@ class VolumeImageViewer {
627627
if (options.retrieveRendered) {
628628
url = url + '/rendered';
629629
}
630-
return(url);
630+
return (url);
631631
}
632632

633633
/*
@@ -714,7 +714,7 @@ class VolumeImageViewer {
714714
/** DICOM Pixel Spacing has millimeter unit while the projection has
715715
* has meter unit.
716716
*/
717-
const spacing = _getPixelSpacing(pyramid[nLevels-1])[0] / 10**3;
717+
const spacing = _getPixelSpacing(pyramid[nLevels - 1])[0] / 10 ** 3;
718718
return pixelRes * spacing;
719719
}
720720
});
@@ -825,6 +825,7 @@ class VolumeImageViewer {
825825
controls: [],
826826
keyboardEventTarget: document,
827827
});
828+
828829
this[_map].addInteraction(new MouseWheelZoom());
829830

830831
for (let control in this[_controls]) {
@@ -834,15 +835,15 @@ class VolumeImageViewer {
834835
}
835836

836837
/** Resizes the viewer to fit the viewport. */
837-
resize(){
838+
resize() {
838839
this[_map].updateSize();
839840
}
840841

841842
/** Gets the size of the viewport.
842843
*
843844
* @type {number[]}
844845
*/
845-
get size(){
846+
get size() {
846847
return this[_map].getSize();
847848
}
848849

@@ -903,9 +904,9 @@ class VolumeImageViewer {
903904
const layout = geometry.getLayout();
904905
const coordinates = geometry.getCoordinates();
905906
const firstPoint = coordinates[0][0];
906-
const lastPoint = coordinates[0][coordinates[0].length-1];
907+
const lastPoint = coordinates[0][coordinates[0].length - 1];
907908
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
908-
coordinates[0][coordinates[0].length-1] = firstPoint;
909+
coordinates[0][coordinates[0].length - 1] = firstPoint;
909910
geometry.setCoordinates(coordinates, layout);
910911
e.feature.setGeometry(geometry);
911912
}
@@ -969,7 +970,7 @@ class VolumeImageViewer {
969970
console.error(`unsupported geometry type "${options.geometryType}"`)
970971
}
971972

972-
const defaultDrawOptions = {source: this[_drawingSource]};
973+
const defaultDrawOptions = { source: this[_drawingSource] };
973974
const customDrawOptions = customOptionsMapping[options.geometryType];
974975
if ('style' in options) {
975976
customDrawOptions.style = options.style;
@@ -1010,7 +1011,7 @@ class VolumeImageViewer {
10101011
*
10111012
* @param {object} options - Selection options.
10121013
*/
1013-
activateSelectInteraction(options={}) {
1014+
activateSelectInteraction(options = {}) {
10141015
this.deactivateSelectInteraction();
10151016
console.info('activate "select" interaction')
10161017
this[_interactions].select = new Select({
@@ -1047,7 +1048,7 @@ class VolumeImageViewer {
10471048
*
10481049
* @param {object} options - Modification options.
10491050
*/
1050-
activateModifyInteraction(options={}) {
1051+
activateModifyInteraction(options = {}) {
10511052
this.deactivateModifyInteraction();
10521053
console.info('activate "modify" interaction')
10531054
this[_interactions].modify = new Modify({
@@ -1081,7 +1082,7 @@ class VolumeImageViewer {
10811082
console.info('get all ROIs')
10821083
let rois = [];
10831084
this[_features].forEach((item) => {
1084-
rois.push(this.getROI(item.getId()));
1085+
rois.push(this.getROI(item.getId()));
10851086
});
10861087
return rois;
10871088
}
@@ -1128,6 +1129,16 @@ class VolumeImageViewer {
11281129
this[_features].push(feature);
11291130
}
11301131

1132+
/** Adds a new viewport overlay.
1133+
*
1134+
* @param {object} options Overlay options
1135+
* @param {object} options.element The custom overlay html element
1136+
* @param {object} options.className Class to style the OpenLayer's overlay container
1137+
*/
1138+
addViewportOverlay({ element, className }) {
1139+
this[_map].addOverlay(new Overlay({ element, className }));
1140+
}
1141+
11311142
/** Removes an individual regions of interest.
11321143
*
11331144
* @param {string} uid - Unique identifier of the region of interest
@@ -1242,7 +1253,7 @@ class _NonVolumeImageViewer {
12421253
queryParams: queryParams
12431254
};
12441255
options.client.retrieveInstanceRendered(retrieveOptions).then((thumbnail) => {
1245-
const blob = new Blob([thumbnail], {type: mediaType});
1256+
const blob = new Blob([thumbnail], { type: mediaType });
12461257
image.getImage().src = window.URL.createObjectURL(blob);
12471258
});
12481259
}
@@ -1256,7 +1267,7 @@ class _NonVolumeImageViewer {
12561267
* has meter unit.
12571268
*/
12581269
const mmSpacing = _getPixelSpacing(this[_metadata])[0];
1259-
const spacing = (mmSpacing / resizeFactor) / 10**3;
1270+
const spacing = (mmSpacing / resizeFactor) / 10 ** 3;
12601271
return pixelRes * spacing;
12611272
}
12621273
});
@@ -1320,15 +1331,15 @@ class _NonVolumeImageViewer {
13201331
}
13211332

13221333
/** Resizes the viewer to fit the viewport. */
1323-
resize(){
1334+
resize() {
13241335
this[_map].updateSize();
13251336
}
13261337

13271338
/** Gets the size of the viewport.
13281339
*
13291340
* @type {number[]}
13301341
*/
1331-
get size(){
1342+
get size() {
13321343
return this[_map].getSize();
13331344
}
13341345

0 commit comments

Comments
 (0)