wip on react transition 4
This commit is contained in:
parent
895fb01a02
commit
5568490819
@ -1,15 +1,5 @@
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
|
||||
Template.flexboxLayout.events({
|
||||
'transitionend .sidebarMenu'(event) {
|
||||
if (!event.target.classList.contains('sidebarMenu')) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.ResizeViewportManager.handleResize();
|
||||
}
|
||||
});
|
||||
|
||||
Template.flexboxLayout.helpers({
|
||||
leftSidebarOpen() {
|
||||
return Template.instance().data.state.get('leftSidebar');
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
.CornerstoneViewport {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative; /*Necessary so that the viewportOverlay is on top of the viewports */
|
||||
}
|
||||
@ -1,20 +1,21 @@
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
//import * as cornerstone from 'cornerstone-core';
|
||||
//import * as cornerstoneTools from 'cornerstone-tools';
|
||||
|
||||
import { cornerstone, cornerstoneTools } from 'meteor/ohif:cornerstone';
|
||||
//import './lib/initCornerstone.js';
|
||||
import ImageScrollbar from './ImageScrollbar.js';
|
||||
import ViewportOverlay from './ViewportOverlay.js';
|
||||
import ToolContextMenu from './ToolContextMenu.js';
|
||||
import LoadingIndicator from './LoadingIndicator/LoadingIndicator.js';
|
||||
import './CornerstoneViewport.css';
|
||||
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
import debounce from 'lodash.debounce';
|
||||
import {StackManager} from "../../lib/StackManager";
|
||||
import ImageScrollbar from '../ImageScrollbar/ImageScrollbar.js';
|
||||
import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js';
|
||||
import ToolContextMenu from '../ToolContextMenu/ToolContextMenu.js';
|
||||
import LoadingIndicator from '../LoadingIndicator/LoadingIndicator.js';
|
||||
import ViewportOrientationMarkers from '../ViewportOrientationMarkers/ViewportOrientationMarkers.js';
|
||||
import { StackManager } from "../../../lib/StackManager";
|
||||
import './CornerstoneViewport.styl';
|
||||
|
||||
const EVENT_RESIZE = 'resize';
|
||||
const loadIndicatorDelay = 45;
|
||||
@ -92,6 +93,13 @@ class CornerstoneViewport extends Component {
|
||||
//loadHandlerManager.setEndLoadHandler(this.doneLoadingHandler);
|
||||
|
||||
this.debouncedResize = debounce(() => {
|
||||
try {
|
||||
cornerstone.getEnabledElement(this.element);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
cornerstone.resize(this.element, true);
|
||||
|
||||
this.setState({
|
||||
@ -117,6 +125,9 @@ class CornerstoneViewport extends Component {
|
||||
<div
|
||||
className="CornerstoneViewport viewportElement"
|
||||
onContextMenu={this.onContextMenu}
|
||||
tabIndex='0'
|
||||
unselectable='on'
|
||||
onSelectStart='return false;'
|
||||
ref={input => {
|
||||
this.element = input;
|
||||
}}
|
||||
@ -129,6 +140,10 @@ class CornerstoneViewport extends Component {
|
||||
imageId={this.state.imageId}
|
||||
numImagesLoaded={this.state.numImagesLoaded}
|
||||
/>
|
||||
<ViewportOrientationMarkers/>
|
||||
</div>
|
||||
<div className='viewportInstructions'>
|
||||
Please drag a stack here to view images.
|
||||
</div>
|
||||
{this.displayScrollbar && (
|
||||
<ImageScrollbar
|
||||
@ -191,8 +206,6 @@ class CornerstoneViewport extends Component {
|
||||
this.setState({
|
||||
viewport
|
||||
});
|
||||
|
||||
debugger;
|
||||
}
|
||||
|
||||
onNewImage() {
|
||||
@ -451,8 +464,8 @@ class CornerstoneViewport extends Component {
|
||||
isTouchActive: true
|
||||
});
|
||||
}
|
||||
|
||||
cornerstone.resize(this.element);
|
||||
|
||||
this.debouncedResize();
|
||||
}
|
||||
|
||||
setActiveTool = activeTool => {
|
||||
@ -1,8 +1,9 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
.imageViewerViewport
|
||||
.CornerstoneViewport
|
||||
width: 100%
|
||||
height: 100%
|
||||
position: relative;
|
||||
background-color: black
|
||||
|
||||
// Prevent the blue outline in Chrome when a viewport is selected
|
||||
@ -11,7 +12,7 @@
|
||||
// Prevents the entire page from getting larger
|
||||
// when the magnify tool is near the sides/corners of the page
|
||||
overflow: hidden
|
||||
|
||||
|
||||
.viewportInstructions
|
||||
display: none
|
||||
font-size: 13px
|
||||
@ -26,12 +27,12 @@
|
||||
left: 0
|
||||
margin: auto
|
||||
height: 20px
|
||||
|
||||
/* These are some good CSS settings for a circular magnifying glass
|
||||
|
||||
/* These are some good CSS settings for a circular magnifying glass
|
||||
Try removing the border-radius to make a square magnifying glass */
|
||||
.magnifyTool
|
||||
border: 4px white solid
|
||||
box-shadow: 2px 2px 10px #1e1e1e
|
||||
border-radius: 50%
|
||||
display: none
|
||||
cursor: none
|
||||
cursor: none
|
||||
@ -2,8 +2,7 @@
|
||||
<div class='imageViewerViewport'
|
||||
oncontextmenu='return false;'
|
||||
unselectable='on'
|
||||
onselectstart='return false;'
|
||||
tabindex='0'>
|
||||
onselectstart='return false;'>
|
||||
</div>
|
||||
<div class='viewportInstructions'>
|
||||
Please drag a stack here to view images.
|
||||
@ -2,7 +2,7 @@ import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import CornerstoneViewport from '../CornerstoneViewport.js';
|
||||
import CornerstoneViewport from '../CornerstoneViewport/CornerstoneViewport.js';
|
||||
import './GridLayout.styl';
|
||||
|
||||
const TOP_CLASS = 'top';
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
@value globals: "../GlobalStyles.css";
|
||||
@value activeColor, imageSliderColor from globals;
|
||||
|
||||
.scroll {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.scroll .scroll-holder {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scroll > .scroll-holder > .imageSlider {
|
||||
transform: rotate(90deg);
|
||||
transform-origin: top left;
|
||||
position: absolute;
|
||||
width: 100%; /* Note: This width does not have an effect. */
|
||||
margin-left: 10px;
|
||||
-webkit-appearance: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input.imageSlider:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input.imageSlider::-moz-focus-outer {
|
||||
border: none;
|
||||
}
|
||||
|
||||
input.imageSlider::-webkit-slider-thumb {
|
||||
cursor: -webkit-grab;
|
||||
background: imageSliderColor;
|
||||
-webkit-appearance: none;
|
||||
width: 45px;
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
input.imageSlider::-webkit-slider-thumb:active {
|
||||
background: activeColor;
|
||||
cursor: -webkit-grabbing;
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import './ImageScrollbar.css';
|
||||
import PropTypes from 'prop-types';
|
||||
import './ImageScrollbar.styl';
|
||||
|
||||
class ImageScrollbar extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -27,6 +28,7 @@ class ImageScrollbar extends Component {
|
||||
step="1"
|
||||
value={this.props.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,6 +39,25 @@ class ImageScrollbar extends Component {
|
||||
const intValue = parseInt(event.target.value, 10);
|
||||
this.props.onInputCallback(intValue);
|
||||
}
|
||||
|
||||
onKeyDown(event) {
|
||||
// We don't allow direct keyboard up/down input on the
|
||||
// image sliders since the natural direction is reversed (0 is at the top)
|
||||
|
||||
// Store the KeyCodes in an object for readability
|
||||
const keys = {
|
||||
DOWN: 40,
|
||||
UP: 38
|
||||
};
|
||||
|
||||
if (event.which === keys.DOWN) {
|
||||
OHIF.commands.run('scrollDown');
|
||||
event.preventDefault();
|
||||
} else if (event.which === keys.UP) {
|
||||
OHIF.commands.run('scrollUp');
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageScrollbar.propTypes = {
|
||||
@ -8,14 +8,14 @@ $imageSliderBorder = none
|
||||
$imageSliderWidth = 12px
|
||||
$imageSliderHeight = 39px
|
||||
|
||||
.imageControls
|
||||
.scroll
|
||||
height: 100%
|
||||
padding: 5px
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 0
|
||||
|
||||
.scrollbar
|
||||
.scroll-holder
|
||||
height: calc(100% - 20px)
|
||||
margin-top: 5px
|
||||
position: relative
|
||||
@ -1,6 +1,5 @@
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import './ViewportOverlay.css';
|
||||
/*import * as cornerstone from 'cornerstone-core';
|
||||
import * as cornerstoneTools from 'cornerstone-tools';*/
|
||||
import { cornerstone, cornerstoneTools } from 'meteor/ohif:cornerstone';
|
||||
@ -1,38 +0,0 @@
|
||||
.ViewportOverlay {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.ViewportOverlay .overlay-element {
|
||||
position: absolute;
|
||||
color: lightblue;
|
||||
text-shadow: 1px 1px black;
|
||||
}
|
||||
|
||||
.ViewportOverlay .overlay-element > span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ViewportOverlay .top-right {
|
||||
top: 10px;
|
||||
right: 25px; /* room for scrollbar */
|
||||
}
|
||||
|
||||
.ViewportOverlay .top-left {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.ViewportOverlay .bottom-right {
|
||||
bottom: 10px;
|
||||
right: 30px;
|
||||
}
|
||||
|
||||
.ViewportOverlay .bottom-left {
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import './ViewportOverlay.css';
|
||||
import PropTypes from 'prop-types';
|
||||
import './ViewportOverlay.styl';
|
||||
|
||||
class ViewportOverlay extends Component {
|
||||
render() {
|
||||
@ -8,40 +8,36 @@ $viewportTagPadding = 20px
|
||||
.imageViewerViewportOverlay
|
||||
theme('color', '$textSecondaryColor')
|
||||
|
||||
.dicomTag
|
||||
.overlay-element
|
||||
position: absolute
|
||||
font-weight: 400
|
||||
text-shadow: 1px 1px black
|
||||
pointer-events: none
|
||||
|
||||
.topleft
|
||||
.top-left
|
||||
top: $viewportTagPadding
|
||||
left: $viewportTagPadding
|
||||
|
||||
.topcenter
|
||||
.top-center
|
||||
top: $viewportTagPadding
|
||||
padding-top: $viewportTagPadding
|
||||
width: 100%
|
||||
text-align: center
|
||||
|
||||
.topright
|
||||
.top-right
|
||||
top: $viewportTagPadding
|
||||
right: $viewportTagPadding
|
||||
text-align: right
|
||||
|
||||
.bottomleft
|
||||
.bottom-left
|
||||
bottom: $viewportTagPadding
|
||||
left: $viewportTagPadding
|
||||
|
||||
.bottomright
|
||||
.bottom-right
|
||||
bottom: $viewportTagPadding
|
||||
right: $viewportTagPadding
|
||||
text-align: right
|
||||
|
||||
.priorIndicator
|
||||
font-weight: bold
|
||||
color: yellow
|
||||
|
||||
&.controlsVisible
|
||||
.topright, .bottomright
|
||||
right: "calc(%s + 19px)" % $viewportTagPadding
|
||||
@ -242,39 +242,4 @@ Template.viewportOverlay.helpers({
|
||||
|
||||
return stack.imageIds.length;
|
||||
},
|
||||
|
||||
prior() {
|
||||
// This helper is updated whenever a new image is displayed in the viewport
|
||||
Session.get('CornerstoneNewImage' + this.viewportIndex);
|
||||
|
||||
if (!this.imageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Make sure there are more than two studies loaded in the viewer
|
||||
const viewportStudies = OHIF.viewer.Studies.all();
|
||||
if (viewportStudies.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we sort the collection in ascending order by study date, so
|
||||
// that we can obtain the oldest study as the first element of the array
|
||||
//
|
||||
// TODO= Find out if we should encode studyDate as a Date in the OHIF.viewer.Studies Collection
|
||||
const viewportStudiesArray = _.sortBy(viewportStudies, function(study) {
|
||||
return viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime);
|
||||
});
|
||||
|
||||
// Get study data
|
||||
const study = cornerstone.metaData.get('study', this.imageId);
|
||||
if (!study) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldestStudy = viewportStudiesArray[0];
|
||||
if (viewportOverlayUtils.formatDateTime(study.studyDate, study.studyTime) <= viewportOverlayUtils.formatDateTime(oldestStudy.studyDate, oldestStudy.studyTime)) {
|
||||
return 'Prior';
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -4,7 +4,6 @@
|
||||
<div class="topleft dicomTag">
|
||||
<div>{{formatPN patientName}}</div>
|
||||
<div>{{patientId}}</div>
|
||||
<div class='priorIndicator'>{{prior}}</div>
|
||||
</div>
|
||||
<div class="topright dicomTag">
|
||||
<div>{{studyDescription}}</div>
|
||||
@ -33,7 +32,6 @@
|
||||
<div class="topright dicomTag">
|
||||
<div>{{formatPN patientName}}</div>
|
||||
<div>{{patientId}}</div>
|
||||
<div class='priorIndicator'>{{prior}}</div>
|
||||
<div>{{studyDescription}}</div>
|
||||
<div>{{formatDA studyDate}} {{formatTM studyTime}}</div>
|
||||
</div>
|
||||
@ -53,7 +51,6 @@
|
||||
<div class="topleft dicomTag">
|
||||
<div>{{formatPN patientName}}</div>
|
||||
<div>{{patientId}}</div>
|
||||
<div class='priorIndicator'>{{prior}}</div>
|
||||
<div>{{studyDescription}}</div>
|
||||
<div>{{formatDA studyDate}} {{formatTM studyTime}}</div>
|
||||
</div>
|
||||
@ -1,7 +0,0 @@
|
||||
<template name="imageControls">
|
||||
<div class="imageControls">
|
||||
<div class="scrollbar">
|
||||
<input class="imageSlider" type="range" min="1" value="{{imageIndex}}" max="{{numImages}}"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,83 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { setActiveViewport } from '../../../lib/setActiveViewport';
|
||||
import { switchToImageByIndex } from '../../../lib/switchToImageByIndex';
|
||||
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
const slideTimeoutTime = 40;
|
||||
let slideTimeout;
|
||||
|
||||
Template.imageControls.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Set the current imageSlider width to its parent's height
|
||||
// (because webkit is stupid and can't style vertical sliders)
|
||||
const $slider = instance.$('.imageSlider');
|
||||
const $viewport = $slider.closest('.imageViewerViewportOverlay').siblings('.imageViewerViewport');
|
||||
|
||||
instance.handleResize = _.throttle(() => {
|
||||
const viewportHeight = $viewport.height();
|
||||
$slider.width(viewportHeight - 20);
|
||||
}, 150);
|
||||
|
||||
instance.handleResize();
|
||||
|
||||
$(window).on('resize', instance.handleResize);
|
||||
});
|
||||
|
||||
Template.imageControls.onDestroyed(() => {
|
||||
const instance = Template.instance();
|
||||
if (instance.handleResize) {
|
||||
$(window).off('resize', instance.handleResize);
|
||||
}
|
||||
});
|
||||
|
||||
Template.imageControls.events({
|
||||
'rescale .scrollbar'(event, instance) {
|
||||
instance.handleResize();
|
||||
},
|
||||
|
||||
'keydown input[type=range]'(event) {
|
||||
// We don't allow direct keyboard up/down input on the
|
||||
// image sliders since the natural direction is reversed (0 is at the top)
|
||||
|
||||
// Store the KeyCodes in an object for readability
|
||||
const keys = {
|
||||
DOWN: 40,
|
||||
UP: 38
|
||||
};
|
||||
|
||||
if (event.which === keys.DOWN) {
|
||||
OHIF.commands.run('scrollDown');
|
||||
event.preventDefault();
|
||||
} else if (event.which === keys.UP) {
|
||||
OHIF.commands.run('scrollUp');
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
'input input[type=range], change input[type=range]'(event) {
|
||||
// Note that we throttle requests to prevent the
|
||||
// user's ultrafast scrolling from firing requests too quickly.
|
||||
clearTimeout(slideTimeout);
|
||||
slideTimeout = setTimeout(() => {
|
||||
// Using the slider in an inactive viewport
|
||||
// should cause that viewport to become active
|
||||
const $slider = $(event.currentTarget);
|
||||
const viewportContainer = $slider.parents('.viewportContainer');
|
||||
setActiveViewport(viewportContainer);
|
||||
|
||||
// Subtract 1 here since the slider goes from 1 to N images
|
||||
// But the stack indexing starts at 0
|
||||
const newImageIdIndex = parseInt($slider.val(), 10) - 1;
|
||||
switchToImageByIndex(newImageIdIndex);
|
||||
}, slideTimeoutTime);
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@ -1,10 +1,11 @@
|
||||
import ViewerMain from './ViewerMain/ViewerMain.js';
|
||||
import GridLayout from './GridLayout/GridLayout.js';
|
||||
import LoadingIndicator from './LoadingIndicator/LoadingIndicator.js';
|
||||
import CornerstoneViewport from './CornerstoneViewport.js';
|
||||
import ImageScrollbar from './ImageScrollbar.js';
|
||||
import ToolContextMenu from './ToolContextMenu.js';
|
||||
import ViewportOverlay from './ViewportOverlay.js';
|
||||
import CornerstoneViewport from './CornerstoneViewport/CornerstoneViewport.js';
|
||||
import ImageScrollbar from './ImageScrollbar/ImageScrollbar.js';
|
||||
import ToolContextMenu from './ToolContextMenu/ToolContextMenu.js';
|
||||
import ViewportOverlay from './ViewportOverlay/ViewportOverlay.js';
|
||||
import ViewportOrientationMarkers from './ViewportOrientationMarkers/ViewportOrientationMarkers.js';
|
||||
|
||||
const viewer = {
|
||||
ViewerMain,
|
||||
@ -14,7 +15,6 @@ const viewer = {
|
||||
ImageScrollbar,
|
||||
ToolContextMenu,
|
||||
ViewportOverlay,
|
||||
test: 'test2'
|
||||
};
|
||||
|
||||
export default viewer;
|
||||
|
||||
@ -121,26 +121,10 @@ Package.onUse(function(api) {
|
||||
api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.styl', 'client');
|
||||
|
||||
// Viewer components
|
||||
api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.html', 'client');
|
||||
api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.js', 'client');
|
||||
api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.html', 'client');
|
||||
api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.js', 'client');
|
||||
api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.html', 'client');
|
||||
api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.js', 'client');
|
||||
api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/toolContextMenu/toolContextMenu.js', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/imageControls/imageControls.html', 'client');
|
||||
api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client');
|
||||
api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/viewer/layoutButton/layoutButton.html', 'client');
|
||||
api.addFiles('client/components/viewer/layoutButton/layoutButton.js', 'client');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user