fix: ui for dicom tag browswer (#3022)
* fix: ui for dicom tag browswer * fix build
This commit is contained in:
parent
ccf010c0fe
commit
6db4d7a917
@ -1,48 +1,37 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
|
||||||
import { classes } from '@ohif/core';
|
|
||||||
import Range from './Range';
|
|
||||||
import DicomTagTable from './DicomTagTable';
|
|
||||||
import dcmjs from 'dcmjs';
|
import dcmjs from 'dcmjs';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import React, { useState, useMemo } from 'react';
|
||||||
|
import { classes } from '@ohif/core';
|
||||||
|
import DicomTagTable from './DicomTagTable';
|
||||||
import './DicomTagBrowser.css';
|
import './DicomTagBrowser.css';
|
||||||
import { Select, Typography } from '@ohif/ui';
|
import { InputRange, Select, Typography } from '@ohif/ui';
|
||||||
|
|
||||||
const { ImageSet } = classes;
|
const { ImageSet } = classes;
|
||||||
const { DicomMetaDictionary } = dcmjs.data;
|
const { DicomMetaDictionary } = dcmjs.data;
|
||||||
const { nameMap } = DicomMetaDictionary;
|
const { nameMap } = DicomMetaDictionary;
|
||||||
|
|
||||||
|
|
||||||
let instanceSelectList = null;
|
|
||||||
let instanceSelectTitle = null;
|
|
||||||
|
|
||||||
const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
||||||
const [
|
const [
|
||||||
activeDisplaySetInstanceUID,
|
selectedDisplaySetInstanceUID,
|
||||||
setActiveDisplaySetInstanceUID,
|
setSelectedDisplaySetInstanceUID,
|
||||||
] = useState(displaySetInstanceUID);
|
] = useState(displaySetInstanceUID);
|
||||||
const [activeInstance, setActiveInstance] = useState(1);
|
const [instanceNumber, setInstanceNumber] = useState(1);
|
||||||
const [tags, setTags] = useState([]);
|
|
||||||
const [meta, setMeta] = useState('');
|
const onSelectChange = value => {
|
||||||
const [instanceList, setInstanceList] = useState([]);
|
setSelectedDisplaySetInstanceUID(value.value);
|
||||||
const [displaySetList, setDisplaySetList] = useState([]);
|
setInstanceNumber(1);
|
||||||
const [isImageStack, setIsImageStack] = useState(false);
|
|
||||||
const [selectedDisplaySetValue, setSelectedDisplaySetValue] = useState({}
|
|
||||||
);
|
|
||||||
const onSeriesSelect = value => {
|
|
||||||
console.log(value);
|
|
||||||
setActiveDisplaySetInstanceUID(value.value);
|
|
||||||
setActiveInstance(1);
|
|
||||||
setSelectedDisplaySetValue(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const activeDisplaySet = displaySets.find(
|
||||||
var activeDisplaySet = displaySets.find(
|
ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID
|
||||||
ds => ds.displaySetInstanceUID === activeDisplaySetInstanceUID
|
);
|
||||||
);
|
|
||||||
|
|
||||||
|
const isImageStack = _isImageStack(activeDisplaySet);
|
||||||
|
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
||||||
|
|
||||||
|
const displaySetList = useMemo(() => {
|
||||||
displaySets.sort((a, b) => a.SeriesNumber - b.SeriesNumber);
|
displaySets.sort((a, b) => a.SeriesNumber - b.SeriesNumber);
|
||||||
|
return displaySets.map(displaySet => {
|
||||||
const newDisplaySetList = displaySets.map(displaySet => {
|
|
||||||
const {
|
const {
|
||||||
displaySetInstanceUID,
|
displaySetInstanceUID,
|
||||||
SeriesDate,
|
SeriesDate,
|
||||||
@ -56,123 +45,72 @@ const DicomTagBrowser = ({ displaySets, displaySetInstanceUID }) => {
|
|||||||
const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0];
|
const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0];
|
||||||
const date = moment(dateStr, 'YYYYMMDD:HHmmss');
|
const date = moment(dateStr, 'YYYYMMDD:HHmmss');
|
||||||
const displayDate = date.format('ddd, MMM Do YYYY');
|
const displayDate = date.format('ddd, MMM Do YYYY');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: displaySetInstanceUID,
|
value: displaySetInstanceUID,
|
||||||
label: `${SeriesNumber} (${Modality}): ${SeriesDescription}`,
|
label: `${SeriesNumber} (${Modality}): ${SeriesDescription}`,
|
||||||
description: displayDate,
|
description: displayDate,
|
||||||
onClick: () => {
|
|
||||||
setActiveDisplaySetInstanceUID(displaySetInstanceUID);
|
|
||||||
setActiveInstance(1);
|
|
||||||
|
|
||||||
//instanceSelectList.props.children.props.value = 1;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
}, [displaySets]);
|
||||||
let metadata;
|
|
||||||
if (!activeDisplaySet) {
|
|
||||||
if (!displaySets || displaySets.length == 0) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
activeDisplaySet = displaySets[0];
|
|
||||||
setActiveDisplaySetInstanceUID(displaySets[0].displaySetInstanceUID);
|
|
||||||
setSelectedDisplaySetValue(newDisplaySetList[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
setSelectedDisplaySetValue(newDisplaySetList.find(
|
|
||||||
ds => ds.value === activeDisplaySetInstanceUID
|
|
||||||
));
|
|
||||||
}
|
|
||||||
const isImageStack =
|
|
||||||
activeDisplaySet instanceof ImageSet; /*&&
|
|
||||||
activeDisplaySet.isSOPClassUIDSupported === true*/;
|
|
||||||
|
|
||||||
let instanceList;
|
|
||||||
if (isImageStack) {
|
|
||||||
const { images } = activeDisplaySet;
|
|
||||||
const image = images[activeInstance - 1];
|
|
||||||
instanceList = images.map((image, index) => {
|
|
||||||
// const metadata = image.getData().metadata;
|
|
||||||
|
|
||||||
const { InstanceNumber } = image;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: index,
|
|
||||||
title: `Instance Number: ${InstanceNumber}`,
|
|
||||||
description: '',
|
|
||||||
onClick: () => {
|
|
||||||
setActiveInstance(index);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
metadata = image;
|
|
||||||
} else {
|
|
||||||
metadata = activeDisplaySet;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isImageStack) {
|
|
||||||
instanceSelectTitle = (
|
|
||||||
<Typography variant="subtitle" className="mr-5 text-right h-full">
|
|
||||||
Instance Number
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
instanceSelectList = (
|
|
||||||
<div className="dicom-tag-browser-instance-range ml-auto">
|
|
||||||
<Range
|
|
||||||
showValue
|
|
||||||
step={1}
|
|
||||||
min={1}
|
|
||||||
max={instanceList.length}
|
|
||||||
value={activeInstance}
|
|
||||||
valueRenderer={value => <p>{value}</p>}
|
|
||||||
onChange={({ target }) => {
|
|
||||||
const instanceIndex = parseInt(target.value);
|
|
||||||
setActiveInstance(instanceIndex);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
instanceSelectList = null;
|
|
||||||
}
|
|
||||||
setTags(getSortedTags(metadata));
|
|
||||||
setMeta(metadata);
|
|
||||||
setInstanceList(instanceList);
|
|
||||||
setDisplaySetList(newDisplaySetList);
|
|
||||||
setIsImageStack(isImageStack);
|
|
||||||
}, [activeDisplaySetInstanceUID, activeInstance, displaySets]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dicom-tag-browser-content">
|
<div className="dicom-tag-browser-content">
|
||||||
<div className="flex flex-row items-center justify-between">
|
<div className="flex flex-row items-center mb-2">
|
||||||
<Typography variant="subtitle" className="mr-5 text-right h-full">
|
<Typography variant="subtitle" className="w-1/2 mr-8">
|
||||||
Series
|
Series
|
||||||
</Typography>
|
</Typography>
|
||||||
{instanceSelectTitle}</div>
|
{showInstanceList && (
|
||||||
<div className="flex flex-row items-center">
|
<Typography variant="subtitle" className="w-1/2">
|
||||||
|
Instance Number
|
||||||
<div className="w-72">
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row items-center mb-6">
|
||||||
|
<div className="w-1/2 mr-8">
|
||||||
<Select
|
<Select
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
onChange={onSeriesSelect}
|
onChange={onSelectChange}
|
||||||
options={displaySetList}
|
options={displaySetList}
|
||||||
value={selectedDisplaySetValue}
|
value={displaySetList.find(
|
||||||
/></div>
|
ds => ds.value === selectedDisplaySetInstanceUID
|
||||||
{instanceSelectList}
|
)}
|
||||||
</div>
|
className="text-white"
|
||||||
|
/>
|
||||||
<div className="dicom-tag-browser-table-wrapper">
|
</div>
|
||||||
<DicomTagTable rows={getFormattedRowsFromTags(tags, meta)}></DicomTagTable>
|
{showInstanceList ? (
|
||||||
|
<div className="w-1/2">
|
||||||
|
<InputRange
|
||||||
|
value={instanceNumber}
|
||||||
|
onChange={value => {
|
||||||
|
setInstanceNumber(parseInt(value));
|
||||||
|
}}
|
||||||
|
minValue={1}
|
||||||
|
maxValue={activeDisplaySet.images.length}
|
||||||
|
step={1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
<DicomTagTable
|
||||||
|
rows={getFormattedRowsFromTags(activeDisplaySet, instanceNumber)}
|
||||||
|
></DicomTagTable>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getFormattedRowsFromTags(displaySet, instanceNumber) {
|
||||||
|
const isImageStack = _isImageStack(displaySet);
|
||||||
|
|
||||||
function getFormattedRowsFromTags(tags, meta) {
|
let metadata;
|
||||||
|
|
||||||
|
if (isImageStack) {
|
||||||
|
metadata = displaySet.images[instanceNumber - 1];
|
||||||
|
} else {
|
||||||
|
metadata = displaySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = getSortedTags(metadata);
|
||||||
const rows = [];
|
const rows = [];
|
||||||
|
|
||||||
tags.forEach(tagInfo => {
|
tags.forEach(tagInfo => {
|
||||||
@ -205,7 +143,6 @@ function getFormattedRowsFromTags(tags, meta) {
|
|||||||
meta.StudyInstanceUID
|
meta.StudyInstanceUID
|
||||||
);*/
|
);*/
|
||||||
// console.log(dataset);
|
// console.log(dataset);
|
||||||
|
|
||||||
// const tag = dcmjs.data.Tag.fromPString(tagInfo.tag).toCleanString();
|
// const tag = dcmjs.data.Tag.fromPString(tagInfo.tag).toCleanString();
|
||||||
// const originalTagInfo = dataset[tag];
|
// const originalTagInfo = dataset[tag];
|
||||||
// tagInfo.vr = originalTagInfo.vr;
|
// tagInfo.vr = originalTagInfo.vr;
|
||||||
@ -220,10 +157,9 @@ function getFormattedRowsFromTags(tags, meta) {
|
|||||||
`${tagInfo.tagIndent}${tagInfo.tag}`,
|
`${tagInfo.tagIndent}${tagInfo.tag}`,
|
||||||
tagInfo.vr,
|
tagInfo.vr,
|
||||||
tagInfo.keyword,
|
tagInfo.keyword,
|
||||||
tagInfo.value
|
tagInfo.value,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
rows.push([
|
rows.push([
|
||||||
`${tagInfo.tagIndent}${tagInfo.tag}`,
|
`${tagInfo.tagIndent}${tagInfo.tag}`,
|
||||||
tagInfo.vr,
|
tagInfo.vr,
|
||||||
@ -353,7 +289,7 @@ function getRows(metadata, depth = 0) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// skip properties without hex tag numbers
|
// skip properties without hex tag numbers
|
||||||
var regex = /[0-9A-Fa-f]{6}/g;
|
const regex = /[0-9A-Fa-f]{6}/g;
|
||||||
if (keyword.match(regex)) {
|
if (keyword.match(regex)) {
|
||||||
const tag = `(${keyword.substring(0, 4)},${keyword.substring(4, 8)})`;
|
const tag = `(${keyword.substring(0, 4)},${keyword.substring(4, 8)})`;
|
||||||
rows.push({
|
rows.push({
|
||||||
@ -370,6 +306,10 @@ function getRows(metadata, depth = 0) {
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _isImageStack(displaySet) {
|
||||||
|
return displaySet instanceof ImageSet;
|
||||||
|
}
|
||||||
|
|
||||||
function toArray(objectOrArray) {
|
function toArray(objectOrArray) {
|
||||||
return Array.isArray(objectOrArray) ? objectOrArray : [objectOrArray];
|
return Array.isArray(objectOrArray) ? objectOrArray : [objectOrArray];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,55 +1,99 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
function ColumnHeaders() {
|
function ColumnHeaders() {
|
||||||
return (<div className="border-b-4 border-black"> <div className="pt-3 pb-3 bg-primary-dark ">
|
return (
|
||||||
<div className="container m-auto relative flex flex-col"><div className="flex flex-row w-full">
|
<div className="m-auto flex flex-col py-2 bg-secondary-light">
|
||||||
<div className="px-3 w-5/24">
|
<div className="flex flex-row w-full">
|
||||||
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
<div className="px-3 w-5/24">
|
||||||
<span className="flex flex-row items-center focus:outline-none">
|
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
||||||
Tag</span></label></div> <div className="px-3 w-4/24">
|
<span className="flex flex-row items-center focus:outline-none">
|
||||||
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
Tag
|
||||||
<span className="flex flex-row items-center focus:outline-none">
|
</span>
|
||||||
Value Representation</span></label></div> <div className="px-3 w-6/24">
|
</label>
|
||||||
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
</div>
|
||||||
<span className="flex flex-row items-center focus:outline-none">
|
<div className="px-3 w-4/24">
|
||||||
Keyword</span></label></div> <div className="px-3 w-5/24">
|
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
||||||
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
<span className="flex flex-row items-center focus:outline-none">
|
||||||
<span className="flex flex-row items-center focus:outline-none">
|
VR
|
||||||
Value</span></label></div></div></div>
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div></div>)
|
<div className="px-3 w-6/24">
|
||||||
|
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
||||||
|
<span className="flex flex-row items-center focus:outline-none">
|
||||||
|
Keyword
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="px-3 w-5/24">
|
||||||
|
<label className="flex flex-col flex-1 text-white text-lg pl-1 select-none">
|
||||||
|
<span className="flex flex-row items-center focus:outline-none">
|
||||||
|
Value
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DicomTagTable({ rows }) {
|
function DicomTagTable({ rows }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ColumnHeaders()}
|
||||||
|
<div
|
||||||
|
className="m-auto relative border-2 border-secondary-light overflow-hidden ohif-scrollbar"
|
||||||
|
style={{ height: '32rem' }}
|
||||||
|
>
|
||||||
|
<table className="w-full text-white">
|
||||||
|
<tbody>
|
||||||
|
{rows.map((row, index) => {
|
||||||
|
const className = row.className ? row.className : null;
|
||||||
|
|
||||||
return (<div>{ColumnHeaders()}
|
return (
|
||||||
<div className="container m-auto relative">
|
<tr
|
||||||
<table className="w-full text-white">
|
className="hover:bg-secondary-main transition duration-300 bg-primary-dark"
|
||||||
|
key={`DICOMTagRow-${index}`}
|
||||||
<tbody>
|
>
|
||||||
{rows.map((row, index) => {
|
<td
|
||||||
const className = row.className ? row.className : null;
|
style={{ maxWidth: '0px' }}
|
||||||
|
className="px-4 py-2 text-base break-all border-b border-secondary-light w-5/24"
|
||||||
return (
|
>
|
||||||
<tr className="hover:bg-secondary-main transition duration-300 bg-primary-dark" key={`DICOMTagRow-${index}`}>
|
<div className="flex">
|
||||||
<td style={{ maxWidth: "0px" }} className="px-4 py-2 text-base break-all border-b border-secondary-light w-5/24">
|
<div className="inline-flex max-w-full">{row[0]}</div>
|
||||||
<div className="flex"><div className="inline-flex max-w-full">{row[0]}</div></div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td style={{ maxWidth: "0px" }} className="px-4 py-2 text-base break-all border-b border-secondary-light w-4/24">
|
<td
|
||||||
<div className="flex"><div className="inline-flex max-w-full">{row[1]}</div></div>
|
style={{ maxWidth: '0px' }}
|
||||||
</td>
|
className="px-4 py-2 text-base break-all border-b border-secondary-light w-4/24"
|
||||||
<td style={{ maxWidth: "0px" }} className="px-4 py-2 text-base break-all border-b border-secondary-light w-6/24">
|
>
|
||||||
<div className="flex"><div className="inline-flex max-w-full">{row[2]}</div></div>
|
<div className="flex">
|
||||||
</td>
|
<div className="inline-flex max-w-full">{row[1]}</div>
|
||||||
<td style={{ maxWidth: "0px" }} className="px-4 py-2 text-base break-all border-b border-secondary-light w-14/24">
|
</div>
|
||||||
<div className="flex"><div className="inline-flex max-w-full">{row[3]}</div></div>
|
</td>
|
||||||
</td>
|
<td
|
||||||
</tr>
|
style={{ maxWidth: '0px' }}
|
||||||
);
|
className="px-4 py-2 text-base break-all border-b border-secondary-light w-6/24"
|
||||||
})}
|
>
|
||||||
</tbody>
|
<div className="flex">
|
||||||
</table></div></div >
|
<div className="inline-flex max-w-full">{row[2]}</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{ maxWidth: '0px' }}
|
||||||
|
className="px-4 py-2 text-base break-all border-b border-secondary-light w-14/24"
|
||||||
|
>
|
||||||
|
<div className="flex">
|
||||||
|
<div className="inline-flex max-w-full">{row[3]}</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
.range {
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range::-webkit-slider-runnable-track {
|
|
||||||
width: 100%;
|
|
||||||
height: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: #3C5D80;
|
|
||||||
border-radius: 0px;
|
|
||||||
border: 0px solid #3C5D80;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range::-moz-range-track {
|
|
||||||
width: 100%;
|
|
||||||
height: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: none;
|
|
||||||
background-color: #3C5D80;
|
|
||||||
border-radius: 0px;
|
|
||||||
border: 0px solid #3C5D80;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range::-webkit-slider-thumb {
|
|
||||||
box-shadow: none;
|
|
||||||
border: 0px solid #20A5D6;
|
|
||||||
box-shadow: 0px 10px 10px rgba(0, 0, 0, 0.25);
|
|
||||||
height: 21px;
|
|
||||||
width: 11px;
|
|
||||||
border-radius: 11px;
|
|
||||||
background: #20A5D6;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
margin-top: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range::-moz-range-thumb {
|
|
||||||
box-shadow: none;
|
|
||||||
border: 0px solid #20A5D6;
|
|
||||||
box-shadow: 0px 10px 10px rgba(0, 0, 0, 0.25);
|
|
||||||
height: 21px;
|
|
||||||
width: 11px;
|
|
||||||
border-radius: 11px;
|
|
||||||
background: #20A5D6;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
margin-top: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range::-moz-focus-outer {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range-example {
|
|
||||||
background: black;
|
|
||||||
height: 2em;
|
|
||||||
}
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
import './Range.css';
|
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
function Range(props) {
|
|
||||||
const [value, setValue] = useState(props.value);
|
|
||||||
const handleChange = event => {
|
|
||||||
setValue(event.target.value);
|
|
||||||
if (props.onChange) props.onChange(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<input
|
|
||||||
ref={props.ref}
|
|
||||||
type="range"
|
|
||||||
value={props.value}
|
|
||||||
min={props.min}
|
|
||||||
max={props.max}
|
|
||||||
step={props.step || 1}
|
|
||||||
onChange={handleChange}
|
|
||||||
id={props.id}
|
|
||||||
className="range"
|
|
||||||
/>
|
|
||||||
{props.showPercentage && <span>{`${value}%`}</span>}
|
|
||||||
{props.showValue && (
|
|
||||||
<span>
|
|
||||||
{props.valueRenderer
|
|
||||||
? props.valueRenderer(props.value)
|
|
||||||
: props.value}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Range.propTypes = {
|
|
||||||
value: PropTypes.number,
|
|
||||||
min: PropTypes.number.isRequired,
|
|
||||||
max: PropTypes.number.isRequired,
|
|
||||||
step: PropTypes.number,
|
|
||||||
id: PropTypes.string,
|
|
||||||
valueRenderer: PropTypes.func,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
showPercentage: PropTypes.bool,
|
|
||||||
showValue: PropTypes.bool,
|
|
||||||
ref: PropTypes.any,
|
|
||||||
};
|
|
||||||
|
|
||||||
Range.defaultProps = {
|
|
||||||
showPercentage: false,
|
|
||||||
showValue: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Range;
|
|
||||||
@ -377,19 +377,6 @@ const toolbarButtons = [
|
|||||||
],
|
],
|
||||||
'Reset'
|
'Reset'
|
||||||
),
|
),
|
||||||
_createActionButton(
|
|
||||||
'TagBrowser',
|
|
||||||
'list-bullets',
|
|
||||||
'Dicom Tag Browser',
|
|
||||||
[
|
|
||||||
{
|
|
||||||
commandName: 'openDICOMTagViewer',
|
|
||||||
commandOptions: {},
|
|
||||||
context: 'DEFAULT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'Dicom Tag Browser'
|
|
||||||
),
|
|
||||||
_createActionButton(
|
_createActionButton(
|
||||||
'rotate-right',
|
'rotate-right',
|
||||||
'tool-rotate-right',
|
'tool-rotate-right',
|
||||||
@ -535,6 +522,19 @@ const toolbarButtons = [
|
|||||||
],
|
],
|
||||||
'Rectangle'
|
'Rectangle'
|
||||||
),
|
),
|
||||||
|
_createActionButton(
|
||||||
|
'TagBrowser',
|
||||||
|
'list-bullets',
|
||||||
|
'Dicom Tag Browser',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
commandName: 'openDICOMTagViewer',
|
||||||
|
commandOptions: {},
|
||||||
|
context: 'DEFAULT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'Dicom Tag Browser'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import Dialog from './Dialog';
|
|||||||
import Dropdown from './Dropdown';
|
import Dropdown from './Dropdown';
|
||||||
import EmptyStudies from './EmptyStudies';
|
import EmptyStudies from './EmptyStudies';
|
||||||
import ErrorBoundary from './ErrorBoundary';
|
import ErrorBoundary from './ErrorBoundary';
|
||||||
import Icon, { addIcon } from './Icon';
|
import Icon from './Icon';
|
||||||
import IconButton from './IconButton';
|
import IconButton from './IconButton';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import InputDateRange from './InputDateRange';
|
import InputDateRange from './InputDateRange';
|
||||||
@ -89,7 +89,6 @@ export {
|
|||||||
ExpandableToolbarButton,
|
ExpandableToolbarButton,
|
||||||
ListMenu,
|
ListMenu,
|
||||||
Icon,
|
Icon,
|
||||||
addIcon,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
InputDateRange,
|
InputDateRange,
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export {
|
|||||||
Icon,
|
Icon,
|
||||||
IconButton,
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
|
InputRange,
|
||||||
InputDateRange,
|
InputDateRange,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
InputLabelWrapper,
|
InputLabelWrapper,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user