parent
c3ce909434
commit
33307d3cd2
@ -25,11 +25,9 @@ executors:
|
||||
docker:
|
||||
# Primary container image where all steps run.
|
||||
- image: 'cypress/browsers:node14.15.0-chrome86-ff82'
|
||||
- image: 'ohif/viewer-testdata:0.1-test'
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: circleci/node:14.15.0
|
||||
- image: cimg/node:14.18
|
||||
environment:
|
||||
TERM: xterm # Enable colors in term
|
||||
QUICK_BUILD: true
|
||||
@ -349,7 +347,8 @@ workflows:
|
||||
store_artifacts: true
|
||||
working_directory: platform/viewer
|
||||
build:
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
|
||||
git submodule update --init &&
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
||||
yarn run build
|
||||
start: yarn run test:e2e:serve
|
||||
spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'
|
||||
@ -377,7 +376,8 @@ workflows:
|
||||
store_artifacts: true
|
||||
working_directory: platform/viewer
|
||||
build:
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
|
||||
git submodule update --init &&
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
||||
yarn run build:package
|
||||
start: yarn run test:e2e:serve
|
||||
spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'
|
||||
@ -410,7 +410,8 @@ workflows:
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
build:
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
|
||||
git submodule update --init &&
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
||||
yarn run build
|
||||
# start server --> verify running --> percy + chrome + cypress
|
||||
command: yarn run test:e2e:dist
|
||||
@ -489,7 +490,8 @@ workflows:
|
||||
store_artifacts: false
|
||||
working_directory: platform/viewer
|
||||
build:
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
|
||||
git submodule update --init &&
|
||||
npx cross-env QUICK_BUILD=true APP_CONFIG=config/e2e.js
|
||||
yarn run build
|
||||
# start server --> verify running --> percy + chrome + cypress
|
||||
command: yarn run test:e2e:dist
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "testdata"]
|
||||
path = testdata
|
||||
url = https://github.com/OHIF/viewer-testdata-dicomweb.git
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
||||
14.18.0
|
||||
@ -28,7 +28,7 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
|
||||
const config = {
|
||||
mode: isProdBuild ? 'production' : 'development',
|
||||
devtool: isProdBuild ? 'source-map' : 'cheap-module-eval-source-map',
|
||||
devtool: isProdBuild ? 'source-map' : 'eval-cheap-module-source-map',
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
|
||||
@ -33,6 +33,7 @@ class DicomPDFViewport extends Component {
|
||||
|
||||
static propTypes = {
|
||||
byteArray: TypedArrayProp.uint8,
|
||||
rawPdf: PropTypes.bool,
|
||||
useNative: PropTypes.bool,
|
||||
viewportData: PropTypes.object,
|
||||
activeViewportIndex: PropTypes.number,
|
||||
@ -45,7 +46,8 @@ class DicomPDFViewport extends Component {
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
const dataSet = this.parseByteArray(this.props.byteArray);
|
||||
const { rawPdf } = this.props
|
||||
const dataSet = !rawPdf && this.parseByteArray(this.props.byteArray);
|
||||
const fileURL = this.getPDFFileUrl(dataSet, this.props.byteArray);
|
||||
|
||||
this.setState(state => ({ ...state, fileURL }));
|
||||
|
||||
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import OHIF from '@ohif/core';
|
||||
import OHIFComponentPlugin from './OHIFComponentPlugin.js';
|
||||
import DicomPDFViewport from './DicomPDFViewport';
|
||||
import { str2ab } from '@ohif/core';
|
||||
|
||||
const { DicomLoaderService } = OHIF.utils;
|
||||
|
||||
@ -18,6 +19,7 @@ class OHIFDicomPDFViewport extends Component {
|
||||
|
||||
state = {
|
||||
byteArray: null,
|
||||
rawPdf: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
@ -34,6 +36,15 @@ class OHIFDicomPDFViewport extends Component {
|
||||
componentDidMount() {
|
||||
const { displaySet, studies } = this.props.viewportData;
|
||||
|
||||
if (displaySet.metadata && displaySet.metadata.EncapsulatedDocument) {
|
||||
const { InlineBinary, BulkDataURI } = displaySet.metadata.EncapsulatedDocument;
|
||||
if (InlineBinary) {
|
||||
const inlineBinaryData = atob(InlineBinary);
|
||||
const byteArray = str2ab(inlineBinaryData);
|
||||
this.setState({ byteArray, rawPdf: true });
|
||||
return;
|
||||
}
|
||||
}
|
||||
DicomLoaderService.findDicomDataPromise(displaySet, studies).then(
|
||||
data => this.setState({ byteArray: new Uint8Array(data) }),
|
||||
error => {
|
||||
@ -49,15 +60,16 @@ class OHIFDicomPDFViewport extends Component {
|
||||
viewportIndex,
|
||||
activeViewportIndex,
|
||||
} = this.props;
|
||||
const { byteArray, error } = this.state;
|
||||
const { byteArray, error, rawPdf } = this.state;
|
||||
const { id, init, destroy } = OHIFDicomPDFViewport;
|
||||
const pluginProps = { id, init, destroy };
|
||||
|
||||
return (
|
||||
<OHIFComponentPlugin {...pluginProps}>
|
||||
{byteArray && (
|
||||
{(byteArray) && (
|
||||
<DicomPDFViewport
|
||||
byteArray={byteArray}
|
||||
rawPdf={rawPdf}
|
||||
setViewportActive={setViewportActive}
|
||||
viewportIndex={viewportIndex}
|
||||
activeViewportIndex={activeViewportIndex}
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
"@babel/preset-env": "^7.5.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@percy/cypress": "^2.2.0",
|
||||
"@webpack-cli/serve": "^1.6.1",
|
||||
"babel-eslint": "9.x",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-inline-react-svg": "1.1.0",
|
||||
@ -104,8 +105,8 @@
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^2.1.0",
|
||||
"webpack": "^4.35.2",
|
||||
"webpack-cli": "^3.3.5",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.3",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.1",
|
||||
"workbox-webpack-plugin": "^5.0.0-beta.1",
|
||||
@ -123,6 +124,7 @@
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"**/node-gyp": "8.4.1",
|
||||
"**/@babel/runtime": "7.5.5"
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ import ui from './ui';
|
||||
import user from './user.js';
|
||||
import errorHandler from './errorHandler.js';
|
||||
import utils, { hotkeys } from './utils/';
|
||||
import str2ab from './utils/str2ab';
|
||||
|
||||
import {
|
||||
UINotificationService,
|
||||
@ -96,6 +97,8 @@ export {
|
||||
UIDialogService,
|
||||
MeasurementService,
|
||||
LoggerService,
|
||||
|
||||
str2ab,
|
||||
};
|
||||
|
||||
export { OHIF };
|
||||
|
||||
@ -26,6 +26,7 @@ describe('Top level exports', () => {
|
||||
'cornerstone',
|
||||
'default', //
|
||||
'errorHandler',
|
||||
'str2ab',
|
||||
'string',
|
||||
'ui',
|
||||
'user',
|
||||
|
||||
@ -9,38 +9,27 @@ import { api } from 'dicomweb-client';
|
||||
*/
|
||||
export default class StaticWadoClient extends api.DICOMwebClient {
|
||||
static filterKeys = {
|
||||
StudyInstanceUID: '0020000D',
|
||||
PatientName: '00100010',
|
||||
PatientID: '00100020',
|
||||
StudyDescription: '00081030',
|
||||
ModalitiesInStudy: '00080061',
|
||||
"StudyInstanceUID": "0020000D",
|
||||
"PatientName": "00100010",
|
||||
"00100020": "mrn",
|
||||
"PatientID": "00100020",
|
||||
"StudyDescription": "00081030",
|
||||
"StudyDate": "00080020",
|
||||
"ModalitiesInStudy": "00080061",
|
||||
AccessionNumber: "00080050",
|
||||
};
|
||||
|
||||
constructor(qidoConfig) {
|
||||
super(qidoConfig);
|
||||
this.staticWado = qidoConfig.staticWado;
|
||||
this.extendMetadataWithInstances = qidoConfig.extendMetadataWithInstances;
|
||||
}
|
||||
|
||||
async retrieveSeriesMetadata(options) {
|
||||
if (!this.extendMetadataWithInstances)
|
||||
return super.retrieveSeriesMetadata(options);
|
||||
const results = await Promise.all([
|
||||
super.retrieveSeriesMetadata(options),
|
||||
this.searchForInstances(options),
|
||||
]);
|
||||
const metadata = results[0];
|
||||
const instances = results[1];
|
||||
return metadata.map(item => {
|
||||
const sopUID = item['00080018'].Value[0];
|
||||
const instance = instances.find(
|
||||
instance => instance['00080018'].Value[0] == sopUID
|
||||
);
|
||||
Object.assign(item, instance);
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the search for studies remote query with a local version which
|
||||
* retrieves a complete query list and then sub-selects from it locally.
|
||||
* @param {*} options
|
||||
* @returns
|
||||
*/
|
||||
async searchForStudies(options) {
|
||||
if (!this.staticWado) return super.searchForStudies(options);
|
||||
|
||||
@ -56,6 +45,62 @@ export default class StaticWadoClient extends api.DICOMwebClient {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares values, matching any instance of desired to any instance of
|
||||
* actual by recursively go through the paired set of values. That is,
|
||||
* this is O(m*n) where m is how many items in desired and n is the length of actual
|
||||
* Then, at the individual item node, compares the Alphabetic name if present,
|
||||
* and does a sub-string matching on string values, and otherwise does an
|
||||
* exact match comparison.
|
||||
*
|
||||
* @param {*} desired
|
||||
* @param {*} actual
|
||||
* @returns true if the values match
|
||||
*/
|
||||
compareValues(desired, actual) {
|
||||
if (Array.isArray(desired)) {
|
||||
return desired.find(item => this.compareValues(item, actual));
|
||||
}
|
||||
if (Array.isArray(actual)) {
|
||||
return actual.find(actualItem => this.compareValues(desired, actualItem));
|
||||
}
|
||||
if (actual && actual.Alphabetic) {
|
||||
actual = actual.Alphabetic;
|
||||
}
|
||||
if (typeof (actual) == 'string') {
|
||||
if (actual.length === 0) return true;
|
||||
if (desired.length === 0 || desired === '*') return true;
|
||||
if (desired[0] === '*' && desired[desired.length - 1] === '*') {
|
||||
console.log(`Comparing ${actual} to ${desired.substring(1, desired.length - 1)}`)
|
||||
return actual.indexOf(desired.substring(1, desired.length - 1)) != -1;
|
||||
} else if (desired[desired.length - 1] === '*') {
|
||||
return actual.indexOf(desired.substring(0, desired.length - 1)) != -1;
|
||||
} else if (desired[0] === '*') {
|
||||
return actual.indexOf(desired.substring(1)) === actual.length - desired.length + 1;
|
||||
}
|
||||
}
|
||||
return desired === actual;
|
||||
}
|
||||
|
||||
/** Compares a pair of dates to see if the value is within the range */
|
||||
compareDateRange(range, value) {
|
||||
if (!value) return true;
|
||||
const dash = range.indexOf('-');
|
||||
if (dash === -1) return this.compareValues(range, value);
|
||||
const start = range.substring(0, dash);
|
||||
const end = range.substring(dash + 1);
|
||||
return (!start || value >= start) &&
|
||||
(!end || value <= end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the return list by the query parameters.
|
||||
*
|
||||
* @param {*} key
|
||||
* @param {*} queryParams
|
||||
* @param {*} study
|
||||
* @returns
|
||||
*/
|
||||
filterItem(key, queryParams, study) {
|
||||
const altKey = StaticWadoClient.filterKeys[key] || key;
|
||||
if (!queryParams) return true;
|
||||
@ -63,23 +108,8 @@ export default class StaticWadoClient extends api.DICOMwebClient {
|
||||
if (!testValue) return true;
|
||||
const valueElem = study[key] || study[altKey];
|
||||
if (!valueElem) return false;
|
||||
if (valueElem.vr == 'DA') return this.compareDateRange(testValue, valueElem.Value[0]);
|
||||
const value = valueElem.Value;
|
||||
return this.eqItem(testValue, value);
|
||||
}
|
||||
|
||||
eqItem(testValue, value) {
|
||||
if (testValue.filter) {
|
||||
return (
|
||||
testValue.filter(testItem => this.eqItem(testItem, value)).length > 0
|
||||
);
|
||||
}
|
||||
if (value === testValue) return true;
|
||||
if (typeof value == 'string') {
|
||||
return value.indexOf(testValue) != -1;
|
||||
}
|
||||
if (value.Alphabetic) return this.eqItem(testValue, value.Alphabetic);
|
||||
if (value.filter)
|
||||
return value.filter(item => this.eqItem(testValue, item)).length > 0;
|
||||
return false;
|
||||
return this.compareValues(testValue, value) && true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,16 @@ const PROXY_TARGET = process.env.PROXY_TARGET;
|
||||
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
|
||||
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
|
||||
|
||||
|
||||
const setHeaders = (res, path) => {
|
||||
res.setHeader('Content-Type', 'text/plain')
|
||||
if (path.indexOf('.gz') !== -1) {
|
||||
res.setHeader('Content-Encoding', 'gzip')
|
||||
} else if (path.indexOf('.br') !== -1) {
|
||||
res.setHeader('Content-Encoding', 'br')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const baseConfig = webpackBase(env, argv, { SRC_DIR, DIST_DIR });
|
||||
const isProdBuild = process.env.NODE_ENV === 'production';
|
||||
@ -134,11 +144,40 @@ module.exports = (env, argv) => {
|
||||
hot: true,
|
||||
open: true,
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
public: 'http://localhost:' + 3000,
|
||||
client: {
|
||||
overlay: { errors: true, warnings: false },
|
||||
},
|
||||
'static': [
|
||||
{
|
||||
directory: path.join(require('os').homedir(), 'dicomweb'),
|
||||
staticOptions: {
|
||||
extensions: ['gz', 'br'],
|
||||
index: "index.json.gz",
|
||||
redirect: true,
|
||||
setHeaders,
|
||||
},
|
||||
publicPath: '/dicomweb',
|
||||
},
|
||||
{
|
||||
directory: '../../testdata',
|
||||
staticOptions: {
|
||||
extensions: ['gz', 'br'],
|
||||
index: "index.json.gz",
|
||||
redirect: true,
|
||||
setHeaders,
|
||||
},
|
||||
publicPath: '/testdata',
|
||||
},
|
||||
],
|
||||
//public: 'http://localhost:' + 3000,
|
||||
//writeToDisk: true,
|
||||
historyApiFallback: {
|
||||
disableDotRule: true,
|
||||
},
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import '@percy/cypress';
|
||||
import { enable } from 'cornerstone-core';
|
||||
import 'cypress-file-upload';
|
||||
import { DragSimulator } from '../helpers/DragSimulator.js';
|
||||
import {
|
||||
@ -199,6 +200,11 @@ Cypress.Commands.add('waitDicomImage', (timeout = 50000) => {
|
||||
.its('cornerstone')
|
||||
.then({ timeout }, $cornerstone => {
|
||||
return new Cypress.Promise(resolve => {
|
||||
const onEnabled = enabledEvt => {
|
||||
const element = enabledEvt.detail.element;
|
||||
|
||||
element.addEventListener('cornerstoneimagerendered', onEvent);
|
||||
};
|
||||
const onEvent = renderedEvt => {
|
||||
const element = renderedEvt.detail.element;
|
||||
|
||||
@ -209,15 +215,17 @@ Cypress.Commands.add('waitDicomImage', (timeout = 50000) => {
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
const onEnabled = enabledEvt => {
|
||||
const element = enabledEvt.detail.element;
|
||||
|
||||
element.addEventListener('cornerstoneimagerendered', onEvent);
|
||||
};
|
||||
$cornerstone.events.addEventListener(
|
||||
'cornerstoneelementenabled',
|
||||
onEnabled
|
||||
);
|
||||
const enabledElements = $cornerstone.getEnabledElements();
|
||||
if (enabledElements && enabledElements.length && !enabledElements[0].invalid) {
|
||||
// Sometimes the page finishes rendering before this gets run,
|
||||
// if so, just resolve immediately.
|
||||
resolve();
|
||||
} else {
|
||||
$cornerstone.events.addEventListener(
|
||||
'cornerstoneelementenabled',
|
||||
onEnabled
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
"build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js",
|
||||
"build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js",
|
||||
"build:viewer:package": "yarn run build:package",
|
||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --config .webpack/webpack.pwa.js --watch",
|
||||
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js --watch",
|
||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --config .webpack/webpack.pwa.js",
|
||||
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack-dev-server --config .webpack/webpack.pwa.js",
|
||||
"dev:viewer": "yarn run dev",
|
||||
"start": "yarn run dev",
|
||||
"test:e2e": "cypress open",
|
||||
@ -31,7 +31,7 @@
|
||||
"test:e2e:script-tag": "cypress run --config video=false --browser chrome --spec 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'",
|
||||
"test:e2e:local": "cypress run --config video=false --browser chrome --spec 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'",
|
||||
"test:e2e:dist": "start-server-and-test test:e2e:serve http://localhost:3000 test:e2e:ci",
|
||||
"test:e2e:serve": "serve -n -l 3000 -s dist",
|
||||
"test:e2e:serve": "cross-env APP_CONFIG=config/e2e.js yarn start",
|
||||
"test:unit": "jest --watchAll",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage",
|
||||
"prepublishOnly": "yarn run build:package",
|
||||
|
||||
116
platform/viewer/public/config/e2e.js
Normal file
116
platform/viewer/public/config/e2e.js
Normal file
@ -0,0 +1,116 @@
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
showStudyList: true,
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'LocalStatic',
|
||||
wadoUriRoot: '/testdata',
|
||||
qidoRoot: '/testdata',
|
||||
wadoRoot: '/testdata',
|
||||
qidoSupportsIncludeField: false,
|
||||
imageRendering: 'wadors',
|
||||
enableStudyLazyLoad: true,
|
||||
supportsFuzzyMatching: false,
|
||||
staticWado: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Extensions should be able to suggest default values for these?
|
||||
// Or we can require that these be explicitly set
|
||||
hotkeys: [
|
||||
// ~ Global
|
||||
{
|
||||
commandName: 'incrementActiveViewport',
|
||||
label: 'Next Viewport',
|
||||
keys: ['right'],
|
||||
},
|
||||
{
|
||||
commandName: 'decrementActiveViewport',
|
||||
label: 'Previous Viewport',
|
||||
keys: ['left'],
|
||||
},
|
||||
// Supported Keys: https://craig.is/killing/mice
|
||||
// ~ Cornerstone Extension
|
||||
{ commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
|
||||
{ commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
|
||||
{ commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
|
||||
{
|
||||
commandName: 'flipViewportVertical',
|
||||
label: 'Flip Horizontally',
|
||||
keys: ['h'],
|
||||
},
|
||||
{
|
||||
commandName: 'flipViewportHorizontal',
|
||||
label: 'Flip Vertically',
|
||||
keys: ['v'],
|
||||
},
|
||||
{ commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
|
||||
{ commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
|
||||
{ commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
|
||||
{ commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
|
||||
// clearAnnotations
|
||||
{ commandName: 'nextImage', label: 'Next Image', keys: ['down'] },
|
||||
{ commandName: 'previousImage', label: 'Previous Image', keys: ['up'] },
|
||||
// firstImage
|
||||
// lastImage
|
||||
{
|
||||
commandName: 'previousViewportDisplaySet',
|
||||
label: 'Previous Series',
|
||||
keys: ['pagedown'],
|
||||
},
|
||||
{
|
||||
commandName: 'nextViewportDisplaySet',
|
||||
label: 'Next Series',
|
||||
keys: ['pageup'],
|
||||
},
|
||||
// ~ Cornerstone Tools
|
||||
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
|
||||
// ~ Window level presets
|
||||
{
|
||||
commandName: 'windowLevelPreset1',
|
||||
label: 'W/L Preset 1',
|
||||
keys: ['1'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset2',
|
||||
label: 'W/L Preset 2',
|
||||
keys: ['2'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset3',
|
||||
label: 'W/L Preset 3',
|
||||
keys: ['3'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset4',
|
||||
label: 'W/L Preset 4',
|
||||
keys: ['4'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset5',
|
||||
label: 'W/L Preset 5',
|
||||
keys: ['5'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset6',
|
||||
label: 'W/L Preset 6',
|
||||
keys: ['6'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset7',
|
||||
label: 'W/L Preset 7',
|
||||
keys: ['7'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset8',
|
||||
label: 'W/L Preset 8',
|
||||
keys: ['8'],
|
||||
},
|
||||
{
|
||||
commandName: 'windowLevelPreset9',
|
||||
label: 'W/L Preset 9',
|
||||
keys: ['9'],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -5,9 +5,9 @@ window.config = {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'LocalStatic',
|
||||
wadoUriRoot: 'http://localhost:5000/',
|
||||
qidoRoot: 'http://localhost:5000',
|
||||
wadoRoot: 'http://localhost:5000/',
|
||||
wadoUriRoot: '/dicomweb',
|
||||
qidoRoot: '/dicomweb',
|
||||
wadoRoot: '/dicomweb',
|
||||
qidoSupportsIncludeField: false,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'thumbnail',
|
||||
|
||||
1
runtime.txt
Normal file
1
runtime.txt
Normal file
@ -0,0 +1 @@
|
||||
3.7
|
||||
1
testdata
Submodule
1
testdata
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 47d51e15a0d41c02f806570d8cf78ab39e782387
|
||||
Loading…
Reference in New Issue
Block a user