WIP reorganization

This commit is contained in:
Erik Ziegler 2018-12-12 09:10:39 +01:00
parent 6706dfe634
commit 054e37dfb7
266 changed files with 98 additions and 620 deletions

View File

@ -5,7 +5,6 @@ aldeed:schema-index@1.1.1
aldeed:simple-schema@1.5.4
aldeed:template-extension@4.1.0
allow-deny@1.1.0
amplify@1.0.0
autoupdate@1.6.0-beta181.7
babel-compiler@7.2.3
babel-runtime@1.3.0
@ -36,6 +35,7 @@ ecmascript-runtime-client@0.8.0
ecmascript-runtime-server@0.7.1
ejson@1.1.0
es5-shim@4.8.0
fastclick@1.0.13
fetch@0.1.0
fortawesome:fontawesome@4.7.0
geojson-utils@1.0.10

View File

@ -0,0 +1,67 @@
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { Route, Switch } from 'react-router-dom';
import SecretRoute from './SecretRoute.js';
import { OHIF } from 'meteor/ohif:core';
import Provider from "react-redux/es/components/Provider";
const reload = () => window.location.reload();
const Studylist = OHIF.studylist.components.StudyList;
function setContext(context) {
/*Rollbar.configure({
payload: {
context
}
});*/
console.log(context);
}
class App extends Component {
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
setContext(window.location.pathname);
});
}
componentWillUnmount() {
this.unlisten();
}
render() {
return (
<Provider store={window.store}>
<Switch>
<SecretRoute
exact
path="/studylist"
component={Studylist}
auth={this.props.auth}
store={this.props.store}
/>
<SecretRoute
exact
path="/"
component={Studylist}
auth={this.props.auth}
store={this.props.store}
/>
<SecretRoute
exact
path="/viewer"
component={ConnectedViewer}
auth={this.props.auth}
store={this.props.store}
/>
{/*<Route path="/silent-refresh.html" onEnter={reload} />
<Route path="/logout-redirect.html" onEnter={reload} />*/}
<Route render={() =>
<div> Sorry, this page does not exist. </div>}
/>
</Switch>
</Provider>
);
}
}
export default withRouter(App);

View File

@ -123,7 +123,7 @@ class Viewer extends Component {
}
render() {
return (<Provider store={window.store}>
return (<>
<div className='viewerDialogs'>
<CineDialog/>
</div>
@ -131,7 +131,7 @@ class Viewer extends Component {
{/*<ToolbarSection/>*/}
<FlexboxLayout studies={this.state.studies}/>
</div>
</Provider>
</>
);
}
}

View File

@ -12,7 +12,6 @@ Package.onUse(function(api) {
api.versionsFrom('1.7');
api.use('ecmascript');
api.use('standard-app-packages');
api.use('jquery');
api.use('stylus');
api.use('underscore');

View File

@ -12,7 +12,6 @@ Package.onUse(function(api) {
api.versionsFrom('1.7');
api.use('ecmascript');
api.use('standard-app-packages');
// Our custom packages
api.use('ohif:core');

View File

@ -0,0 +1,27 @@
import React, { Component } from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';
class StudyList extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='StudyList'>
<Blaze template="studylist" />
</div>
);
}
}
StudyList.propTypes = {
studies: PropTypes.array.isRequired
};
OHIF.studylist.components = {
StudyList
};
export default StudyList;

View File

@ -1,2 +1,3 @@
import './seriesDetailsModal';
import './studylist';
import './StudyList.js';

View File

@ -1,22 +0,0 @@
<template name="imageThumbnail">
<div class="imageThumbnail">
<div class="imageThumbnailCanvas">
<img class="static-image"/>
</div>
<div class="imageThumbnailLoadingIndicator
thumbnailLoadingIndicator
{{ #if isLoading }}d-block{{/if}}">
<p>Loading {{percentComplete}}</p>
</div>
<div class="imageThumbnailErrorLoadingIndicator
thumbnailLoadingIndicator
{{ #if hasLoadingError }}d-block{{/if}}">
<p>Error</p>
</div>
{{#if showStackLoadingProgressBar}}
<div class="imageThumbnailProgressBar">
<div class="imageThumbnailProgressBarInner" style="width:{{stackPercentComplete}}%"></div>
</div>
{{/if}}
</div>
</template>

View File

@ -1,152 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { OHIF } from 'meteor/ohif:core';
import { cornerstone } from 'meteor/ohif:cornerstone';
/**
* Asynchronous wrapper around Cornerstone's renderToCanvas method.
*
* @param {HTMLElement} canvasElement An HTML <canvas> element
* @param {Image} image A Cornerstone Image
*
* @return {Promise} A promise tracking the progress of the rendering. Resolves empty.
*/
function renderAsync(canvasElement, image) {
return new Promise((resolve, reject) => {
try {
cornerstone.renderToCanvas(canvasElement, image);
resolve();
} catch(error) {
reject(error);
}
});
}
Template.imageThumbnail.onCreated(() => {
const instance = Template.instance();
instance.isLoading = new ReactiveVar(false);
instance.hasLoadingError = new ReactiveVar(false);
// Get the image ID for current thumbnail
instance.getThumbnailImageId = () => {
const settingPath = 'public.ui.useMiddleSeriesInstanceAsThumbnail';
const useMiddleFrame = OHIF.utils.ObjectPath.get(Meteor.settings, settingPath);
const stack = instance.data.thumbnail.stack;
const lastIndex = (stack.numImageFrames || stack.images.length || 1) - 1;
let imageIndex = useMiddleFrame ? Math.floor(lastIndex / 2) : 0;
let imageInstance;
if (stack.isMultiFrame) {
imageInstance = stack.images[0];
} else {
imageInstance = stack.images[imageIndex];
imageIndex = undefined;
}
return imageInstance.getImageId(imageIndex, true);
};
});
Template.imageThumbnail.onRendered(() => {
const instance = Template.instance();
// Declare DOM and jQuery objects
const $parent = instance.$('.imageThumbnail');
const $thumbnailElement = $parent.find('.imageThumbnailCanvas');
instance.refreshImage = () => {
const imageElement = $thumbnailElement.find('img').get(0);
// Activate the loading state
instance.isLoading.set(true);
instance.hasLoadingError.set(false);
// Clear the previous image
imageElement.removeAttribute('src');
// Define a handler for success on image load
const loadSuccess = image => {
// This is an off-screen canvas. It's used to get dataURL images by using
// cornerstone.renderToCanvas function.
const canvasElement = document.createElement('canvas');
canvasElement.width = 193;
canvasElement.height = 123;
// Render the image to canvas to be able to get its dataURL
renderAsync(canvasElement, image).then(() => {
instance.isLoading.set(false);
imageElement.src = canvasElement.toDataURL('image/jpeg', 1);
});
};
// Define a handler for error on image load
const loadError = () => {
instance.isLoading.set(false);
instance.hasLoadingError.set(true);
};
// Call cornerstone image loader with the defined handlers
cornerstone.loadAndCacheImage(instance.imageId).then(loadSuccess, loadError);
};
// Run this computation every time the current study is changed
instance.autorun(() => {
// Check if there is a reactive var set for current study
if (instance.data.currentStudy) {
// Register a dependency from this computation on current study
instance.data.currentStudy.dep.depend();
}
// Depend on external data and re-run this computation when it changes
Template.currentData();
// Get the image ID. If it is the same as the currently rendered imageId,
// refresh the image.
const imageId = instance.getThumbnailImageId();
if (imageId !== instance.imageId) {
instance.imageId = imageId;
instance.refreshImage();
}
});
});
Template.imageThumbnail.helpers({
// Executed every time the thumbnail image loading progress is changed
percentComplete() {
const instance = Template.instance();
// Get the encoded image ID for thumbnail
const encodedImageId = OHIF.string.encodeId(instance.imageId);
// Register a dependency from this computation on Session key
const percentComplete = Session.get('CornerstoneThumbnailLoadProgress' + encodedImageId);
// Return the complete percent amount of the image loading
if (percentComplete && percentComplete !== 100) {
return percentComplete + '%';
}
},
// Return how much the stack has already loaded
stackPercentComplete() {
const stack = Template.instance().data.thumbnail.stack;
const progress = Session.get(`StackProgress:${stack.displaySetInstanceUid}`);
return progress && progress.percentComplete;
},
showStackLoadingProgressBar() {
return OHIF.uiSettings.showStackLoadingProgressBar;
},
isLoading() {
return Template.instance().isLoading.get();
},
hasLoadingError() {
return Template.instance().hasLoadingError.get();
}
});

View File

@ -1,67 +0,0 @@
@import "{ohif:design}/app"
.thumbnailEntry.active .imageThumbnail
theme('border-color', '$activeColor')
box-shadow: none
transition($sidebarTransition)
.imageThumbnail
theme('box-shadow', 'inset 0 0 0 1px $uiBorderColorDark')
theme('background-color', '$primaryBackgroundColor')
border: 5px solid transparent
border-radius: 12px
height: 135px
margin: 0 auto
padding 1px 7px
position: relative
transition($sidebarTransition)
width: 217px
-moz-background-clip: padding
-webkit-background-clip: padding
background-clip: padding-box
.imageThumbnailClone
margin: 0 !important
&:hover
theme('border-color', '$hoverColor')
box-shadow: none
.imageThumbnailCanvas
height: 100%
overflow: hidden
img
-webkit-user-drag: none
.thumbnailLoadingIndicator
display: none
pointer-events: none
theme('color', '$textSecondaryColor')
height: 20px
width: 100%
top: 0
left: 0
right: 0
bottom: 0
margin: auto
position: absolute
&.d-block
display: block;
p
text-align: center
font-size: 10pt
.imageThumbnailProgressBar
position: relative
width: 100%
height: 3px
top: -5px
.imageThumbnailProgressBarInner
height: 100%
width: 0
border-radius: 5px
theme('background-color', '$activeColor')

View File

@ -1,99 +0,0 @@
<template name="textMarkerDialogs">
<dialog id="textMarkerOptionsDialog" oncontextmenu="return false" class="textMarkerDialog noselect">
<h5>Spine Labels</h5>
<a class="closeTextMarkerDialogs">{{> iconCrossCircle}}</a>
<div class='optionsDiv'>
<div class="select2-wrapper optionBox">
<label for="startFrom">Label: </label>
<select name="start" id="startFrom" tabindex="-1" class="select2">
<!-- Cervical spine !-->
<option value="C1" selected>C1</option>
<option value="C2">C2</option>
<option value="C3">C3</option>
<option value="C4">C4</option>
<option value="C5">C5</option>
<option value="C6">C6</option>
<option value="C7">C7</option>
<!-- Thoracic spine !-->
<option value="T1">T1</option>
<option value="T2">T2</option>
<option value="T3">T3</option>
<option value="T4">T4</option>
<option value="T5">T5</option>
<option value="T6">T6</option>
<option value="T7">T7</option>
<option value="T8">T8</option>
<option value="T9">T9</option>
<option value="T10">T10</option>
<option value="T11">T11</option>
<option value="T12">T12</option>
<!-- Lumbar spine !-->
<option value="L1">L1</option>
<option value="L2">L2</option>
<option value="L3">L3</option>
<option value="L4">L4</option>
<option value="L5">L5</option>
</select>
</div>
<div class="optionBox">
<div class="btn-group iconSwitch" data-toggle="buttons">
<label for="ascending" class="btn btn-link" title="Add labels from head to feet (down) or feet to head (up)" data-toggle="tooltip" data-container="body">
<input type="checkbox" id="ascending"> <span class="on"><i class="fa fa-long-arrow-up" aria-hidden="true"></i></span> <span class="off"><i class="fa fa-long-arrow-down" aria-hidden="true"></i></span>
</label>
</div>
</div>
<button id="clearLabels" class="btn viewerBtn btn-xs" type="button">
Clear Labels <i class="viewerIcon-clear"></i>
</button>
</div>
</dialog>
<dialog id="textMarkerRelabelDialog" oncontextmenu="return false" class="textMarkerDialog noselect">
<h5>Change Spine Label</h5>
<div class="relabelOptions">
<div class="select2-wrapper optionBox">
<label for="relabelSelect">Label:</label>
<select name="relabelSelect" class="relabelSelect">
<!-- Cervical spine !-->
<option value="C1">C1</option>
<option value="C2">C2</option>
<option value="C3">C3</option>
<option value="C4">C4</option>
<option value="C5">C5</option>
<option value="C6">C6</option>
<option value="C7">C7</option>
<!-- Thoracic spine !-->
<option value="T1">T1</option>
<option value="T2">T2</option>
<option value="T3">T3</option>
<option value="T4">T4</option>
<option value="T5">T5</option>
<option value="T6">T6</option>
<option value="T7">T7</option>
<option value="T8">T8</option>
<option value="T9">T9</option>
<option value="T10">T10</option>
<option value="T11">T11</option>
<option value="T12">T12</option>
<!-- Lumbar spine !-->
<option value="L1">L1</option>
<option value="L2">L2</option>
<option value="L3">L3</option>
<option value="L4">L4</option>
<option value="L5">L5</option>
</select>
</div>
</div>
<div class="relabelButtons">
<button class="relabelRemove btn btn-xs btn-secondary viewerBtn">Delete</button>
<button class="relabelConfirm btn btn-xs viewerBtn">Save</button>
</div>
<div class="dialog arrow">
</div>
</dialog>
</template>

View File

@ -1,124 +0,0 @@
/**
* @TODO: add this to OHIF's Viewers
*/
import { Template } from 'meteor/templating';
import { $ } from 'meteor/jquery';
import { toolManager } from '../../../lib/toolManager';
import { viewportUtils } from '../../../lib/viewportUtils';
Template.textMarkerDialogs.events({
'change #startFrom'(e) {
const config = cornerstoneTools.textMarker.getConfiguration();
config.current = $(e.target).val();
//console.log("Changed starting point to: " + config.current);
},
'change #ascending'(e) {
const config = cornerstoneTools.textMarker.getConfiguration();
config.ascending = $(e.target).is(':checked');
const currentIndex = config.markers.indexOf(config.current);
config.current = config.markers[currentIndex];
const nextMarker = config.current;
$('#startFrom').val(nextMarker).trigger('change');
//console.log("Changed ascending to: " + config.ascending);
},
'click #clearLabels'() {
const element = viewportUtils.getActiveViewportElement();
const toolType = 'textMarker';
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
const toolState = toolStateManager.toolState;
// We might want to make this a convenience function in cornerstoneTools
const stack = cornerstoneTools.getToolState(element, 'stack');
if (stack && stack.data.length && stack.data[0].imageIds.length) {
const imageIds = stack.data[0].imageIds;
// Clear the tool data for each image in the stack
imageIds.forEach( imageId => {
if(toolState.hasOwnProperty(imageId)) {
const toolData = toolState[imageId];
if (toolData.hasOwnProperty(toolType)) {
delete toolData[toolType];
}
}
});
}
cornerstone.updateImage(element);
},
'click .closeTextMarkerDialogs'() {
toolManager.setActiveTool();
document.getElementById('textMarkerOptionsDialog').close();
$('#spine').removeClass('active');
const defaultTool = toolManager.getDefaultTool();
$('#' + defaultTool).addClass('active');
}
});
Template.textMarkerDialogs.onRendered(function() {
const optionsDialog = $('#textMarkerOptionsDialog');
optionsDialog.draggable();
dialogPolyfill.registerDialog(optionsDialog.get(0));
const relabelDialog = $('#textMarkerRelabelDialog');
relabelDialog.draggable();
dialogPolyfill.registerDialog(relabelDialog.get(0));
$(document).on('click', event => {
if (!$(event.target).closest('.select2-wrapper').length) {
setTimeout(() => {
$('#startFrom, .relabelSelect').select2('close');
}, 200);
}
});
$(document).on('touchmove', event => {
if (!$(event.target).closest('.select2-container').length) {
setTimeout(() => {
$('#startFrom, .relabelSelect').select2('close');
}, 200);
}
});
$(() => {
FastClick.attach(document.body);
const $customSelects = $('#startFrom, .relabelSelect')
$customSelects.select2({
/**
* Adds needsclick class to all DOM elements in the Select2 results list
* so they can be accessible on iOS mobile when FastClick is initiated too.
*/
templateResult(result, container) {
if (!result.id) {
return result.text;
}
container.className += ' needsclick';
return result.text;
},
placeholder: 'C1',
minimumResultsForSearch: -1,
theme: 'viewerDropdown'
});
/**
* Additional to tweaking the templateResult option in Select2,
* add needsclick class to all DOM elements in the Select2 container,
* so they can be accessible on iOS mobile when FastClick is initiated too.
*
* More info about needsclick:
* https://github.com/ftlabs/fastclick#ignore-certain-elements-with-needsclick
*
*/
$customSelects.each( (index, el) =>{
$(el).data('select2').$container.find('*').addClass('needsclick');
});
});
});

View File

@ -1,147 +0,0 @@
.textMarkerDialog
z-index: 1000
width: 260px
position: absolute
top: auto
left: auto
bottom: 3px
right: 3px
margin: auto
padding:.5em
background-image: linear-gradient(#2E608D, #23557F)
box-sizing: border-box
border: 1px black solid
border-radius: 5px
height: 81px
max-height: 81px
h5
color: #D1EDFB;
font-size: 14px;
line-height: 22px;
font-weight: 600;
cursor:default
.handle
width: 40px;
float: left;
height: 22px;
display: block;
margin-right: 10px;
position: relative;
margin-top: 1px;
margin-left: 1px;
#startFrom
margin-right:10px
#clearLabels
margin-left:10px
float:right
.optionBox
color: #d1edfb
margin-bottom: 5px
float: left
span.subLabel
width: 50px
display: block
float: left
line-height: 30px
> label
color: #d1edfb
float: left
min-width: 40px
line-height: 24px
font-size: 12px
font-weight: 600
.closeTextMarkerDialogs
position: absolute
top: 5px
right: 4px
padding: 5px
cursor: pointer
svg
width: 19px
height: 19px
fill: #d1edfb
&:hover
svg
fill: #FFF
.dialog.arrow
left: 50%
margin-left: -11px
border-top-width: 0
border-bottom-color: #999999
border-bottom-color: rgba(0, 0, 0, 0.25)
border-width: 11px
bottom: -10px
position: absolute
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #23557f;
&:after
content: " "
top: 1px
margin-left: -10px
border-top-width: 0
border-bottom-color: #23557f
border-width: 10px
button.btn-secondary
background-color: #CFE3F5;
border: 1px solid #E5F3FF;
font-size: 12px !important;
color:#0D416D
&:hover
color:#0D416D
#textMarkerRelabelDialog
margin: 0
.relabelOptions
padding: 15px 0px 0px 0px
.relabelSelect
margin-left: 5px
#textMarkerOptionsDialog
.optionsDiv
padding-top: 10px
//Avoids Cine Play and Text Marker dialog to overlap
#textMarkerOptionsDialog[open='open'] ~ #cineDialog[open='open']
bottom: 90px
.relabelButtons
text-align:right
button.viewerBtn
background-color: #5D9ACE;
border: 1px solid #6EAEE4;
font-size: 12px !important;
color:#FFF
line-height: 21px;
&:hover
color:#FFF
.iconSwitch
margin:0px 5px
.btn
span
display: none
.on
display: none
.off
display: block
&.btn-link, &.active, &:active, &:hover, &:focus, &.active:focus
background-color: #225682;
border: 1px solid #7AB0DE;
box-shadow: none;
padding: 1px 7px;
border-radius: 4px;
color: #d1edfb;
box-shadow: none;
outline: none;
&:hover
color:#fff
&.active
.on
display:block
.off
display: none

View File

@ -154,10 +154,6 @@ Package.onUse(function(api) {
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.html', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.js', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.styl', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.html', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.styl', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.js', 'client');

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More