Skip to content

Commit

Permalink
[IDC-2049] Sort Tags in Tag browser split items in sequences, add ind…
Browse files Browse the repository at this point in the history
…ent after space. (#2053)

* Sort tag browser, add items, add indent.

* Remove debugger.
  • Loading branch information
JamesAPetts authored Sep 24, 2020
1 parent 6cf72d1 commit ccdfcd4
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const dicomBrowserSelectStyles = {
}),
option: (base, state) => ({
...base,
width: '100%',
cursor: 'pointer',
'&:first-of-type': {
borderTopLeftRadius: 5,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
display: flex;
justify-content: start;
margin: 0;
width: 100%;
}

.dcmseg-segmentation-item .segmentation-meta {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
margin-left: auto;
}

.dicom-tag-browser-table td {
.dicom-tag-browser-table tr {
padding-left: 10px;
padding-right: 10px;
color: var(--table-text-primary-color);
Expand Down
263 changes: 185 additions & 78 deletions extensions/dicom-tag-browser/src/components/DicomTagBrowser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { classes } from '@ohif/core';
import dcmjs from 'dcmjs';
import DicomBrowserSelect from './DicomBrowserSelect';
Expand All @@ -16,94 +16,111 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
setActiveDisplaySetInstanceUID,
] = useState(displaySetInstanceUID);
const [activeInstance, setActiveInstance] = useState(0);
const [tags, setTags] = useState([]);
const [instanceList, setInstanceList] = useState([]);
const [displaySetList, setDisplaySetList] = useState([]);
const [isImageStack, setIsImageStack] = useState(false);

useEffect(() => {
const activeDisplaySet = displaySets.find(
ds => ds.displaySetInstanceUID === activeDisplaySetInstanceUID
);

const newDisplaySetList = displaySets.map(displaySet => {
const {
displaySetInstanceUID,
SeriesDate,
SeriesTime,
SeriesNumber,
SeriesDescription,
Modality,
} = displaySet;

/* Map to display representation */
const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0];
const date = moment(dateStr, 'YYYYMMDD:HHmmss');
const displayDate = date.format('ddd, MMM Do YYYY');

const activeDisplaySet = displaySets.find(
ds => ds.displaySetInstanceUID === activeDisplaySetInstanceUID
);
return {
value: displaySetInstanceUID,
title: `${SeriesNumber} (${Modality}): ${SeriesDescription}`,
description: displayDate,
onClick: () => {
setActiveDisplaySetInstanceUID(displaySetInstanceUID);
setActiveInstance(0);
},
};
});

const displaySetList = displaySets.map(displaySet => {
const {
displaySetInstanceUID,
SeriesDate,
SeriesTime,
SeriesNumber,
SeriesDescription,
Modality,
} = displaySet;

/* Map to display representation */
const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0];
const date = moment(dateStr, 'YYYYMMDD:HHmmss');
const displayDate = date.format('ddd, MMM Do YYYY');

return {
value: displaySetInstanceUID,
title: `${SeriesNumber} (${Modality}): ${SeriesDescription}`,
description: displayDate,
onClick: () => {
setActiveDisplaySetInstanceUID(displaySetInstanceUID);
setActiveInstance(0);
},
};
});
let metadata;
const isImageStack = activeDisplaySet instanceof ImageSet;

let metadata;
const isImageStack = activeDisplaySet instanceof ImageSet;
let selectedInstanceValue;
let instanceList;

let selectedInstanceValue;
let instanceList;
if (isImageStack) {
const { images } = activeDisplaySet;
const image = images[activeInstance];

if (isImageStack) {
const { images } = activeDisplaySet;
const image = images[activeInstance];
instanceList = images.map((image, index) => {
const metadata = image.getData().metadata;

instanceList = images.map((image, index) => {
const metadata = image.getData().metadata;
const { InstanceNumber } = metadata;

const { InstanceNumber } = metadata;

return {
value: index,
title: `Instance Number: ${InstanceNumber}`,
description: '',
onClick: () => {
setActiveInstance(index);
},
};
});
return {
value: index,
title: `Instance Number: ${InstanceNumber}`,
description: '',
onClick: () => {
setActiveInstance(index);
},
};
});

selectedInstanceValue = instanceList[activeInstance];
metadata = image.getData().metadata;
} else {
metadata = activeDisplaySet.metadata;
}

metadata = image.getData().metadata;
} else {
metadata = activeDisplaySet.metadata;
}
setTags(getSortedTags(metadata));
setInstanceList(instanceList);
setDisplaySetList(newDisplaySetList);
setIsImageStack(isImageStack);
}, [activeDisplaySetInstanceUID, activeInstance]);

const selectedDisplaySetValue = displaySetList.find(
ds => ds.value === activeDisplaySetInstanceUID
);

let instanceSelectList = null;

if (isImageStack) {
const selectedInstanceValue = instanceList[activeInstance];

instanceSelectList = (
<DicomBrowserSelect
value={selectedInstanceValue}
formatOptionLabel={DicomBrowserSelectItem}
options={instanceList}
/>
);
}

return (
<div>
<DicomBrowserSelect
value={selectedDisplaySetValue}
formatOptionLabel={DicomBrowserSelectItem}
options={displaySetList}
/>
{isImageStack ? (
<DicomBrowserSelect
value={selectedInstanceValue}
formatOptionLabel={DicomBrowserSelectItem}
options={instanceList}
/>
) : null}
<DicomTagTable instanceMetadata={metadata}></DicomTagTable>
{instanceSelectList}
<DicomTagTable tags={tags}></DicomTagTable>
</div>
);
};

function DicomTagTable({ instanceMetadata }) {
const rows = getRows(instanceMetadata);
function DicomTagTable({ tags }) {
const rows = getFormattedRowsFromTags(tags);

return (
<div>
Expand All @@ -114,19 +131,71 @@ function DicomTagTable({ instanceMetadata }) {
<th className="dicom-tag-browser-table-left">Keyword</th>
<th className="dicom-tag-browser-table-left">Value</th>
</tr>
{rows.map(row => (
<tr>
<td>{row[0]}</td>
<td>{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
))}
{rows.map(row => {
const className = row.className ? row.className : null;

return (
<tr className={className}>
<td>{row[0]}</td>
<td className="dicom-tag-browser-table-center">{row[1]}</td>
<td>{row[2]}</td>
<td>{row[3]}</td>
</tr>
);
})}
</table>
</div>
);
}

function getFormattedRowsFromTags(tags) {
const rows = [];

tags.forEach(tagInfo => {
if (tagInfo.vr === 'SQ') {
rows.push([
`${tagInfo.tagIndent}${tagInfo.tag}`,
tagInfo.vr,
tagInfo.keyword,
'',
]);

const { values } = tagInfo;

values.forEach((item, index) => {
const formatedRowsFromTags = getFormattedRowsFromTags(item);

rows.push([
`${item[0].tagIndent}(FFFE,E000)`,
'',
`Item #${index}`,
'',
]);

rows.push(...formatedRowsFromTags);
});
} else {
rows.push([
`${tagInfo.tagIndent}${tagInfo.tag}`,
tagInfo.vr,
tagInfo.keyword,
tagInfo.value,
]);
}
});

return rows;
}

function getSortedTags(metadata) {
const tagList = getRows(metadata);

// Sort top level tags, sequence groups are sorted when created.
_sortTagList(tagList);

return tagList;
}

function getRows(metadata, depth = 0) {
// Tag, Type, Value, Keyword

Expand All @@ -138,6 +207,10 @@ function getRows(metadata, depth = 0) {
tagIndent += '>';
}

if (depth > 0) {
tagIndent += ' '; // If indented, add a space after the indents.
}

const rows = [];

for (let i = 0; i < keywords.length; i++) {
Expand All @@ -155,7 +228,16 @@ function getRows(metadata, depth = 0) {
const sequenceAsArray = toArray(value);

// Push line defining the sequence
rows.push([`${tagIndent}${tagInfo.tag}`, tagInfo.vr, keyword, '']);

const sequence = {
tag: tagInfo.tag,
tagIndent,
vr: tagInfo.vr,
keyword,
values: [],
};

rows.push(sequence);

if (value === null) {
// Type 2 Sequence
Expand All @@ -165,9 +247,10 @@ function getRows(metadata, depth = 0) {
sequenceAsArray.forEach(item => {
const sequenceRows = getRows(item, depth + 1);

sequenceRows.forEach(row => {
rows.push(row);
});
// Sort the sequence group.
_sortTagList(sequenceRows);

sequence.values.push(sequenceRows);
});

continue;
Expand Down Expand Up @@ -205,16 +288,30 @@ function getRows(metadata, depth = 0) {
}
}

// tag / vr/ keyword/ value

// Remove retired tags
keyword = keyword.replace('RETIRED_', '');

if (tagInfo) {
rows.push([`${tagIndent}${tagInfo.tag}`, tagInfo.vr, keyword, value]);
rows.push({
tag: tagInfo.tag,
tagIndent,
vr: tagInfo.vr,
keyword,
value,
});
} else {
// Private tag
const tag = `(${keyword.substring(0, 4)},${keyword.substring(4, 8)})`;

rows.push([`${tagIndent}${tag}`, '', 'Private Tag', value]);
rows.push({
tag,
tagIndent,
vr: '',
keyword: 'Private Tag',
value,
});
}
}

Expand All @@ -225,4 +322,14 @@ function toArray(objectOrArray) {
return Array.isArray(objectOrArray) ? objectOrArray : [objectOrArray];
}

function _sortTagList(tagList) {
tagList.sort((a, b) => {
if (a.tag < b.tag) {
return -1;
}

return 1;
});
}

export default DicomTagBrowser;
2 changes: 1 addition & 1 deletion platform/viewer/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const appProps = {
OHIFDicomSegmentationExtension,
OHIFDicomRtExtension,
//[OHIFDebuggingExtension, { mailTo: 'support@canceridc.dev' }],
//OHIFDicomTagBrowserExtension,
OHIFDicomTagBrowserExtension,
],
};

Expand Down

0 comments on commit ccdfcd4

Please sign in to comment.