Skip to content

Commit bdc6d79

Browse files
committed
DM-7767 Make Multi image viewer support light curve type layout
- mutliple plots coming in with table selection - plots comming in as wcs matched - wcs functionallity expanded to support new plots, matching zoom and rotation - scroll together - preference for zoom and stretch - rotation will stay wcs matched - set number of images (1,3,5,7)
1 parent e6a031e commit bdc6d79

18 files changed

+452
-100
lines changed

src/firefly/java/edu/caltech/ipac/firefly/server/visualize/PlotServUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ else if (rotateNorthType.equals(CoordinateSys.EQ_J2000)){
220220
public static File createRotatedFile(File originalFile, FitsRead originalFR, double angle) throws FitsException,
221221
IOException,
222222
GeomException {
223-
FitsRead rotateFR= FitsRead.createFitsReadRotated(originalFR, angle);
223+
FitsRead rotateFR= FitsRead.createFitsReadRotated(originalFR, angle, false);
224224
String fname= originalFile.getName();
225225
String angleStr= String.format("%2f", angle);
226226
File f= File.createTempFile(FileUtil.getBase(fname)+"-rot-"+angleStr,

src/firefly/java/edu/caltech/ipac/firefly/server/visualize/WebPlotReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ private static PipelineRet applyRotation(WebPlotRequest req, FitsRead fr, Band b
248248
req.getRotateNorthType().toString());
249249
}
250250
} else if (req.getRotate()) {
251-
retval = FitsRead.createFitsReadRotated(fr, req.getRotationAngle());
251+
retval = FitsRead.createFitsReadRotated(fr, req.getRotationAngle(), true);
252252
}
253253
File rotFile= ModFileWriter.makeRotFileName(originalFile,imageIdx,req.getRotationAngle());
254254
modFileWriter = new ModFileWriter.GeomFileWriter(rotFile, retval, band);

src/firefly/java/edu/caltech/ipac/visualize/plot/FitsRead.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import nom.tam.fits.ImageHDU;
1414
import nom.tam.util.ArrayFuncs;
1515
import nom.tam.util.Cursor;
16+
1617
import java.io.DataOutputStream;
1718
import java.io.FileOutputStream;
1819
import java.io.IOException;
@@ -237,9 +238,10 @@ public static FitsRead createFitsReadNorthUpGalactic(FitsRead aFitsReader)
237238
*
238239
* @param fitsReader FitsReadLZ object for the input image
239240
* @param rotationAngle number of degrees to rotate the image counter-clockwise
241+
* @param fromNorth if true that the rotation angle is from the north
240242
* @return FitsReadLZ object for the new, rotated image
241243
*/
242-
public static FitsRead createFitsReadRotated(FitsRead fitsReader, double rotationAngle)
244+
public static FitsRead createFitsReadRotated(FitsRead fitsReader, double rotationAngle, boolean fromNorth)
243245
throws FitsException, IOException, GeomException {
244246

245247
ImageHeader imageHeader = fitsReader.getImageHeader();
@@ -254,11 +256,20 @@ public static FitsRead createFitsReadRotated(FitsRead fitsReader, double rotatio
254256
try {
255257
WorldPt worldPt1 = projection.getWorldCoords(centerX, centerY - 1);
256258
WorldPt worldPt2 = projection.getWorldCoords(centerX, centerY);
257-
double positionAngle = -VisUtil.getPositionAngle(worldPt1.getX(),
259+
double positionAngle = VisUtil.getPositionAngle(worldPt1.getX(),
258260
worldPt1.getY(), worldPt2.getX(), worldPt2.getY());
259-
260-
positionAngle += rotationAngle;
261-
return (createFitsReadPositionAngle(fitsReader, positionAngle, CoordinateSys.EQ_J2000));
261+
if (fromNorth) {
262+
long angleToRotate= Math.round((180+ rotationAngle) % 360);
263+
if (angleToRotate==Math.round(positionAngle)) {
264+
return fitsReader;
265+
}
266+
else {
267+
return createFitsReadPositionAngle(fitsReader, -angleToRotate, CoordinateSys.EQ_J2000);
268+
}
269+
}
270+
else {
271+
return createFitsReadPositionAngle(fitsReader, -positionAngle+ rotationAngle, CoordinateSys.EQ_J2000);
272+
}
262273
} catch (ProjectionException pe) {
263274
if (SUTDebug.isDebug()) {
264275
System.out.println("got ProjectionException: " + pe.getMessage());
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
3+
*/
4+
5+
import React, {Component,PropTypes} from 'react';
6+
import {omit} from 'lodash';
7+
import {flux} from '../../Firefly.js';
8+
import shallowequal from 'shallowequal';
9+
import {LcImageToolbarView} from './LcImageToolbarView.jsx';
10+
import {getTblById} from '../../tables/TableUtil.js';
11+
12+
export class LcImageToolbar extends Component {
13+
14+
constructor(props) {
15+
super(props);
16+
this.state= {activeTable : getTblById(this.props.tableId)};
17+
}
18+
19+
shouldComponentUpdate(np,ns) {
20+
const {props,state}= this;
21+
const om= ['visRoot'];
22+
var update= !shallowequal(omit(props,om), omit(np,om)) || !shallowequal(ns,state);
23+
if (update) return true;
24+
25+
return (props.visRoot.activePlotId!==np.visRoot.activePlotId ||
26+
props.visRoot.wcsMatchType!==np.visRoot.wcsMatchType);
27+
}
28+
29+
30+
componentWillUnmount() {
31+
this.iAmMounted= false;
32+
if (this.removeListener) this.removeListener();
33+
}
34+
35+
componentWillMount() {
36+
this.iAmMounted= true;
37+
this.removeListener= flux.addListener(() => this.storeUpdate(this.props));
38+
}
39+
40+
storeUpdate() {
41+
if (!this.iAmMounted) return;
42+
const {tableId}= this.props;
43+
}
44+
45+
render() {
46+
const {visRoot, viewerId, viewerPlotIds, layoutType, dlAry, tableId}= this.props;
47+
return (
48+
<LcImageToolbarView activePlotId={visRoot.activePlotId} viewerId={viewerId}
49+
viewerPlotIds={viewerPlotIds} layoutType={layoutType} dlAry={dlAry}
50+
tableId={tableId}
51+
/>
52+
);
53+
}
54+
}
55+
56+
LcImageToolbar.propTypes= {
57+
dlAry : PropTypes.arrayOf(React.PropTypes.object),
58+
visRoot : PropTypes.object,
59+
viewerId : PropTypes.string.isRequired,
60+
layoutType : PropTypes.string.isRequired,
61+
tableId: PropTypes.string,
62+
viewerPlotIds : PropTypes.arrayOf(React.PropTypes.string),
63+
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
3+
*/
4+
5+
6+
import {get} from 'lodash';
7+
import React, {PropTypes} from 'react';
8+
import BrowserInfo from '../../util/BrowserInfo.js';
9+
import {getPlotViewById, getAllDrawLayersForPlot} from '../../visualize/PlotViewUtil.js';
10+
import {WcsMatchType, visRoot, dispatchWcsMatch} from '../../visualize/ImagePlotCntlr.js';
11+
import {VisInlineToolbarView} from '../../visualize/ui/VisInlineToolbarView.jsx';
12+
import {RadioGroupInputFieldView} from '../../ui/RadioGroupInputFieldView.jsx';
13+
import {dispatchChangeLayout, getViewer, getMultiViewRoot, GRID, SINGLE} from '../../visualize/MultiViewCntlr.js';
14+
import {DEF_IMAGE_CNT, MAX_IMAGE_CNT} from './LcManager.js';
15+
16+
17+
18+
const toolsStyle= {
19+
display:'flex',
20+
flexDirection:'row',
21+
flexWrap:'nowrap',
22+
alignItems: 'center',
23+
justifyContent:'space-between',
24+
height: 30
25+
};
26+
27+
const tStyle= {
28+
display:'inline-block',
29+
whiteSpace: 'nowrap',
30+
minWidth: '3em',
31+
paddingLeft : 5
32+
};
33+
34+
var options= [];
35+
36+
for(var i= 1; (i<=MAX_IMAGE_CNT); i+=2) {
37+
options.push({label: i+'', value: i});
38+
}
39+
40+
41+
export function LcImageToolbarView({activePlotId, viewerId, viewerPlotIds, layoutType, dlAry, tableId}) {
42+
43+
const viewer= getViewer(getMultiViewRoot(), viewerId);
44+
const count= get(viewer, 'layoutDetail.count',DEF_IMAGE_CNT);
45+
const vr= visRoot();
46+
const pv= getPlotViewById(vr, activePlotId);
47+
const pvDlAry= getAllDrawLayersForPlot(dlAry,activePlotId,true);
48+
49+
const wcsMatch= (
50+
<div style={{alignSelf:'center', paddingLeft:25}}>
51+
<div style={{display:'inline-block'}}>
52+
<input style={{margin: 0}}
53+
type='checkbox'
54+
checked={vr.wcsMatchType===WcsMatchType.Standard}
55+
onChange={(ev) => wcsMatchStandard(ev.target.checked, vr.activePlotId) }
56+
/>
57+
</div>
58+
<div style={tStyle}>WCS Match</div>
59+
</div>
60+
);
61+
62+
return (
63+
<div style={toolsStyle}>
64+
<div style={{whiteSpace: 'nowrap', paddingLeft: 7}}>
65+
Image Count:
66+
<div style={{display:'inline-block', paddingLeft:7}}>
67+
<RadioGroupInputFieldView options={options} inline={true} fieldKey='frames' value={count}
68+
onChange={(ev) => changeSize(viewerId, ev.target.value)} />
69+
</div>
70+
</div>
71+
{wcsMatch}
72+
<InlineRightToolbarWrapper visRoot={vr} pv={pv} dlAry={pvDlAry} />
73+
</div>
74+
);
75+
}
76+
77+
78+
function changeSize(viewerId, value) {
79+
value= Number(value);
80+
dispatchChangeLayout(viewerId, value === 1 ? SINGLE : GRID, {count:value});
81+
}
82+
83+
// <ImagePager pageSize={10} tbl_id={tableId} />
84+
// <ToolbarButton icon={ONE} tip={'Show single image at full size'}
85+
// imageStyle={{width:24,height:24, flex: '0 0 auto'}}
86+
// enabled={true} visible={true}
87+
// horizontal={true}
88+
// onClick={() => dispatchChangeLayout(viewerId,SINGLE)}/>
89+
// <ToolbarButton icon={FULL_GRID} tip={'show before and after images'}
90+
// enabled={true} visible={true} horizontal={true}
91+
// imageStyle={{width:24,height:24, paddingLeft:5, flex: '0 0 auto'}}
92+
// onClick={() => dispatchChangeLayout(viewerId,'grid',GRID_FULL)}/>
93+
94+
LcImageToolbarView.propTypes= {
95+
dlAry : PropTypes.arrayOf(React.PropTypes.object),
96+
activePlotId : PropTypes.string,
97+
viewerId : PropTypes.string.isRequired,
98+
layoutType : PropTypes.string.isRequired,
99+
viewerPlotIds : PropTypes.arrayOf(PropTypes.string).isRequired,
100+
tableId: PropTypes.string
101+
};
102+
103+
104+
function InlineRightToolbarWrapper({visRoot,pv,dlAry}){
105+
if (!pv) return <div></div>;
106+
107+
var lVis= BrowserInfo.isTouchInput() || visRoot.apiToolsView;
108+
var tb= visRoot.apiToolsView;
109+
return (
110+
<div>
111+
<VisInlineToolbarView
112+
pv={pv} dlAry={dlAry}
113+
showLayer={lVis}
114+
showExpand={true}
115+
showToolbarButton={tb}
116+
showDelete ={false}
117+
/>
118+
</div>
119+
);
120+
}
121+
122+
InlineRightToolbarWrapper.propTypes= {
123+
visRoot: PropTypes.object,
124+
pv : PropTypes.object,
125+
dlAry : PropTypes.array
126+
};
127+
128+
function wcsMatchStandard(doWcsStandard, plotId) {
129+
dispatchWcsMatch({matchType:doWcsStandard?WcsMatchType.Standard:false, plotId});
130+
}

0 commit comments

Comments
 (0)