Skip to content
This repository has been archived by the owner on Jan 22, 2024. It is now read-only.

Commit

Permalink
Merge pull request #122 from TeselaGen/searching
Browse files Browse the repository at this point in the history
mergin in branches
  • Loading branch information
salafrance committed Jan 13, 2016
2 parents 104571b + 5e81043 commit 9ea9fc3
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 70 deletions.
157 changes: 91 additions & 66 deletions app/HighlightLayer.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,109 @@
import React, {PropTypes} from 'react';
import Caret from './Caret';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import { propTypes } from './react-props-decorators.js';

import styles from './highlight-layer.css';

var getXStartAndWidthOfRowAnnotation = require('./getXStartAndWidthOfRowAnnotation');
var assign = require('lodash/object/assign');
let React = require('react');
var Caret = require('./Caret');
let getOverlapsOfPotentiallyCircularRanges = require('ve-range-utils/getOverlapsOfPotentiallyCircularRanges');
let PureRenderMixin = require('react-addons-pure-render-mixin');

var highlightLayerStyle = {
height: "98%",
position: "absolute",
top: "0",
opacity: ".3",
};

let HighlightLayer = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
charWidth: React.PropTypes.number.isRequired,
bpsPerRow: React.PropTypes.number.isRequired,
color: React.PropTypes.string,
row: React.PropTypes.object.isRequired,
sequenceLength: React.PropTypes.number.isRequired,
selectionLayer: React.PropTypes.object.isRequired,
},
render: function() {

function mixin(target, source) {
target = target.prototype;

Object.getOwnPropertyNames(source).forEach((name) => {
let sourceProp = Object.getOwnPropertyDescriptor(source, name);

if (name !== "constructor") {
Object.defineProperty(target, name, sourceProp);
}
});
}

@propTypes({
charWidth: PropTypes.number.isRequired,
bpsPerRow: PropTypes.number.isRequired,
color: PropTypes.string,
row: PropTypes.object.isRequired,
sequenceLength: PropTypes.number.isRequired,
regions: PropTypes.array.isRequired,
})
export default class HighlightLayer extends React.Component {
render() {
var {
charWidth,
bpsPerRow,
row,
sequenceLength,
selectionLayer,
regions,
color
} = this.props;
if (selectionLayer.selected) {
var startSelectionCursor;
var endSelectionCursor;
var overlaps = getOverlapsOfPotentiallyCircularRanges(selectionLayer, row, sequenceLength);
var selectionLayers = overlaps.map(function(overlap, index) {
if (overlap.start === selectionLayer.start) {
startSelectionCursor = (<Caret
charWidth={charWidth}
row={row}
sequenceLength={sequenceLength}
shouldBlink={!selectionLayer.cursorAtEnd}
caretPosition= {overlap.start} />)
}
if (overlap.end === selectionLayer.end) {
endSelectionCursor = (<Caret
charWidth={charWidth}
row={row}
sequenceLength={sequenceLength}
shouldBlink={selectionLayer.cursorAtEnd}
caretPosition= {overlap.end + 1} />)
}
var result = getXStartAndWidthOfRowAnnotation(overlap, bpsPerRow, charWidth);
var xStart = result.xStart;
var width = result.width;

var style = assign({}, highlightLayerStyle, {
width: width,
left: xStart,
background: color ? color : 'blue'

var selectionLayers;

for (let i = 0; i < regions.length; i++) {
let selectionLayer = regions[i];

if (selectionLayer.selected) {
var startSelectionCursor;
var endSelectionCursor;
var overlaps = getOverlapsOfPotentiallyCircularRanges(selectionLayer, row, sequenceLength);
let layers = overlaps.map(function(overlap, index) {
if (overlap.start === selectionLayer.start) {
startSelectionCursor = (<Caret
charWidth={charWidth}
row={row}
sequenceLength={sequenceLength}
shouldBlink={!selectionLayer.cursorAtEnd}
caretPosition={overlap.start} />);
}
if (overlap.end === selectionLayer.end) {
endSelectionCursor = (<Caret
charWidth={charWidth}
row={row}
sequenceLength={sequenceLength}
shouldBlink={selectionLayer.cursorAtEnd}
caretPosition={overlap.end + 1} />);
}
var result = getXStartAndWidthOfRowAnnotation(overlap, bpsPerRow, charWidth);
var xStart = result.xStart;
var width = result.width;

var style = {
width: width,
left: xStart
};

if (color !== undefined) {
style.background = color;
}

return (<div key={index} className={styles.selectionLayer} style={style}/>);
});
return (<div key={index} className="selectionLayer" style={style}/>);
});

selectionLayers = selectionLayers || [];
selectionLayers.push(layers);
}
}

if (selectionLayers !== undefined && selectionLayers.length > 0) {
return (
<div onContextMenu={function (event) {
//tnrtodo: add context menu here
event.preventDefault();
event.stopPropagation();
}}>
{selectionLayers}
{startSelectionCursor}
{endSelectionCursor}
//tnrtodo: add context menu here
event.preventDefault();
event.stopPropagation();
}}>
{selectionLayers}
{startSelectionCursor}
{endSelectionCursor}
</div>
);
} else {
return null;
}

return null;
}
});
}

mixin(HighlightLayer, PureRenderMixin);

module.exports = HighlightLayer;
module.exports = HighlightLayer;
20 changes: 16 additions & 4 deletions app/RowItem.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, {PropTypes} from 'react';
import HighlightLayer from './HighlightLayer';

var getComplementSequenceString = require('ve-sequence-utils/getComplementSequenceString');
var SequenceContainer = require('./SequenceContainer');
var AxisContainer = require('./AxisContainer');
Expand All @@ -7,14 +9,14 @@ var TranslationContainer = require('./TranslationContainer');
var FeatureContainer = require('./FeatureContainer');
var CutsiteLabelContainer = require('./CutsiteLabelContainer');
var CutsiteSnipsContainer = require('./CutsiteSnipsContainer');
var HighlightLayer = require('./HighlightLayer');
var Caret = require('./Caret');

class RowItem extends React.Component {
render() {
var {
charWidth,
selectionLayer,
searchLayers,
cutsiteLabelSelectionLayer,
annotationHeight,
tickSpacing,
Expand Down Expand Up @@ -136,7 +138,7 @@ class RowItem extends React.Component {
row={row}
signals={signals}
sequenceLength={sequenceLength}
selectionLayer={selectionLayer}
regions={[selectionLayer]}
>
</HighlightLayer>
<HighlightLayer
Expand All @@ -146,7 +148,17 @@ class RowItem extends React.Component {
color={'green'}
signals={signals}
sequenceLength={sequenceLength}
selectionLayer={cutsiteLabelSelectionLayer}
regions={[cutsiteLabelSelectionLayer]}
>
</HighlightLayer>
<HighlightLayer
charWidth={charWidth}
bpsPerRow={bpsPerRow}
row={row}
color={'yellow'}
signals={signals}
sequenceLength={sequenceLength}
regions={searchLayers}
>
</HighlightLayer>
{!selectionLayer.selected &&
Expand Down Expand Up @@ -184,4 +196,4 @@ RowItem.propTypes = {
row: PropTypes.object.isRequired
};

module.exports = RowItem;
module.exports = RowItem;
4 changes: 4 additions & 0 deletions app/RowView.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import styles from './row-view.css';
rowData: ['rowData'],
charWidth: ['charWidth'],
selectionLayer: ['selectionLayer'],
searchLayers: ['searchLayers'],
cutsiteLabelSelectionLayer: ['cutsiteLabelSelectionLayer'],
annotationHeight: ['annotationHeight'],
tickSpacing: ['tickSpacing'],
Expand All @@ -32,6 +33,7 @@ import styles from './row-view.css';
rowData: PropTypes.array.isRequired,
charWidth: PropTypes.number.isRequired,
selectionLayer: PropTypes.object.isRequired,
searchLayers: PropTypes.array.isRequired,
cutsiteLabelSelectionLayer: PropTypes.object.isRequired,
annotationHeight: PropTypes.number.isRequired,
tickSpacing: PropTypes.number.isRequired,
Expand Down Expand Up @@ -112,6 +114,7 @@ class RowView extends React.Component {
rowToJumpTo,
charWidth,
selectionLayer,
searchLayers,
cutsiteLabelSelectionLayer,
annotationHeight,
tickSpacing,
Expand All @@ -133,6 +136,7 @@ class RowView extends React.Component {
return (<RowItem
charWidth={charWidth}
selectionLayer={selectionLayer}
searchLayers={searchLayers}
cutsiteLabelSelectionLayer={cutsiteLabelSelectionLayer}
annotationHeight={annotationHeight}
tickSpacing={tickSpacing}
Expand Down
13 changes: 13 additions & 0 deletions app/ToolBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IconButton } from 'material-ui';
import { RaisedButton } from 'material-ui'
import SettingsIcon from 'material-ui/lib/svg-icons/action/settings';
import MenuItem from 'material-ui/lib/menus/menu-item';
import TextField from 'material-ui/lib/text-field';

@Cerebral({
showOrfs: ['showOrfs'],
Expand All @@ -30,6 +31,14 @@ import MenuItem from 'material-ui/lib/menus/menu-item';
})
export default class ToolBar extends React.Component {

search() {
this.props.signals.searchSequence({ searchString: this.refs.searchField.getValue() });
}

clearSearch() {
this.props.signals.searchSequence({ searchString: "" });
}

render() {
var {
showFeatures,
Expand Down Expand Up @@ -111,6 +120,10 @@ export default class ToolBar extends React.Component {
<IconMenu iconButtonElement={iconButtonElement} openDirection="bottom-right">
{toggleMenuItems}
</IconMenu>

<TextField ref="searchField" hintText="search" />
<RaisedButton label='Search' onClick={this.search.bind(this)}/>
<RaisedButton label='Clear Search' onClick={this.clearSearch.bind(this)}/>
</ToolbarGroup>
</Toolbar>
);
Expand Down
32 changes: 32 additions & 0 deletions app/cerebral/actions/searchSequence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
function searchSequence({ searchString }, tree, output) {
if (searchString.length === 0) {
output({ searchLayers: [] });
return;
}
var sequence = tree.get(['sequenceData', 'sequence']);

var layers = [];
var inResult = false;
var lastIndex = 0;

for (let i = 0; i < sequence.length; i++) {
if (!inResult) {
lastIndex = i;
}

if (sequence[i] === searchString[i - lastIndex]) {
inResult = true;

if (i - lastIndex === searchString.length - 1) {
layers.push({ start: lastIndex, end: i, selected: true });
inResult = false;
}
} else {
inResult = false;
}
}

output({ searchLayers: layers });
}

module.exports = searchSequence;
5 changes: 5 additions & 0 deletions app/cerebral/actions/updateSearchLayers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function updateSearchLayers({ searchLayers }, tree, output) {
tree.set('searchLayers', searchLayers);
}

module.exports = updateSearchLayers;
4 changes: 4 additions & 0 deletions app/cerebral/signals.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export default function(controller, options) {
resizeCircularView: [
a.resizeCircularView
],
searchSequence: [
a.searchSequence,
a.updateSearchLayers
],
//tnr: NOT YET WORKING:
//higher priority
pasteSequenceString: [a.pasteSequenceString],
Expand Down
1 change: 1 addition & 0 deletions app/cerebral/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ module.exports = {
height: 500,
width: 500
},
searchLayers: [],
selectionLayer: {
start: -1,
end: -1,
Expand Down
7 changes: 7 additions & 0 deletions app/highlight-layer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.selectionLayer {
height: 98%;
position: absolute;
top: 0;
opacity: .3;
background-color: blue;
}

0 comments on commit 9ea9fc3

Please sign in to comment.