Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions demo/lib/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as React from "react";
import { Menu as ContextMenu, Item, Separator, Submenu, useContextMenu } from "react-contexify";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Separator and Submenu are not being used, remove import.

import "react-contexify/dist/ReactContexify.css";
import {
Button,
Checkbox,
Expand All @@ -13,15 +15,21 @@ import {
Sidebar,
} from "semantic-ui-react";
import seqparse from "seqparse";
import tippy from "tippy.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use the component for tooltips from Semantic UI (since it's already being used)? https://semantic-ui.com/modules/popup.html#/definition

import "tippy.js/dist/tippy.css";
import { TextSpan } from "typescript";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This import is also not being used, remove import


import Circular from "../../src/Circular/Circular";
import Linear from "../../src/Linear/Linear";
import SeqViz from "../../src/SeqViz";
import { chooseRandomColor } from "../../src/colors";
import { AnnotationProp, Primer, TranslationProp } from "../../src/elements";
import { SEQVIZ_ELEMENTS_TYPES } from "../../src/seqvizElementsTypes";
import Header from "./Header";
import file from "./file";

const CONTEXT_MENU_ID = "menu-id";

const viewerTypeOptions = [
{ key: "both", text: "Both", value: "both" },
{ key: "circular", text: "Circular", value: "circular" },
Expand All @@ -35,6 +43,7 @@ interface AppState {
enzymes: any[];
name: string;
primers: Primer[];
hoveredBase: number;
search: { query: string };
searchResults: any;
selection: any;
Expand All @@ -53,6 +62,7 @@ export default class App extends React.Component<any, AppState> {
annotations: [],
customChildren: true,
enzymes: ["PstI", "EcoRI", "XbaI", "SpeI"],
hoveredBase: 0,
name: "",
primers: [
{
Expand Down Expand Up @@ -107,12 +117,90 @@ export default class App extends React.Component<any, AppState> {
linearRef: React.RefObject<HTMLDivElement> = React.createRef();
circularRef: React.RefObject<HTMLDivElement> = React.createRef();

showContextMenu: (params: any) => void = () => {
//do nothing
};

componentDidMount = async () => {
const seq = await seqparse(file);

this.setState({ annotations: seq.annotations, name: seq.name, seq: seq.seq });

const { show } = useContextMenu({
id: CONTEXT_MENU_ID,
});

this.showContextMenu = show;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why creating it on line 120 to then re-assign it to what useContextMenu returns? Is this for the sake of renaming show?


this.setState({ annotations: seq.annotations, name: seq.name, seq: seq.seq, hoveredBase: 0 });
};

handleContextMenuAddForwardTranslation = ({ event, props, triggerEvent, data }) => {
// console.log(event, props, triggerEvent, data);
console.log(this.state.selection);
if (
!this.state.selection.start ||
!this.state.selection.end ||
!this.state.selection.length ||
this.state.selection.length === 0
) {
this.state.translations.push({
direction: 1,
end: this.state.seq.length,
start: 0,
name: "",
});
} else {
const { start, end, clockwise } = this.state.selection;
this.state.translations.push({
direction: 1,
end: clockwise ? end : start,
start: clockwise ? start : end,
name: "",
});
}
this.setState({
translations: this.state.translations,
});
};

handleContextMenuAddReverseTranslation = ({ event, props, triggerEvent, data }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could combine handleContextMenuAddForwardTranslation and handleContextMenuAddReverseTranslation into one function with an argument for the direction

// console.log(event, props, triggerEvent, data);
// console.log(this.state.selection);
if (
!this.state.selection.start ||
!this.state.selection.end ||
!this.state.selection.length ||
this.state.selection.length === 0
) {
this.state.translations.push({
direction: 1,
end: this.state.seq.length,
start: 0,
name: "",
});
} else {
const { start, end, clockwise } = this.state.selection;
this.state.translations.push({
direction: -1,
end: clockwise ? end : start,
start: clockwise ? start : end,
name: "",
});
}
this.setState({
translations: this.state.translations,
});
};

displayContextMenu(e) {
// put whatever custom logic you need
// you can even decide to not display the Menu
this.showContextMenu({
event: e,
});
}

toggleSidebar = () => {
const { showSidebar } = this.state;
this.setState({ showSidebar: !showSidebar });
Expand Down Expand Up @@ -256,6 +344,55 @@ export default class App extends React.Component<any, AppState> {
enzymes={this.state.enzymes}
highlights={[{ start: 0, end: 10 }]}
name={this.state.name}
onClick={(element, circular, linear, container) => {
// console.log({ element, circular, linear, container });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to also show the functionality of these other events. Could be as simple as a single tooltip for all that display some info of the event and what was clicked (like the one you did for annotations on hover)

}}
onContextMenu={(element, circular, linear, event) => {
// console.log({ element, circular, linear, event });
this.displayContextMenu(event);
}}
onDoubleClick={(element, circular, linear, container) => {
// console.log({ element, circular, linear, container });
}}
onHover={(element, hover, view, container) => {
// console.log({ element, hover, view, container });
if (element.type === SEQVIZ_ELEMENTS_TYPES.base) {
if (hover) {
this.setState({ hoveredBase: element.start + element.index + 1 });
} else {
this.setState({ hoveredBase: 0 });
}
} else if (element.type == SEQVIZ_ELEMENTS_TYPES.annotation) {
if (hover) {
if ((container as any)._tippy) {
(container as any)._tippy?.show();
} else {
// you can pass some details with annotations to display in tippy
tippy(container, {
content: `
<div>
<div>
<strong>Name</strong>: <span>${element.name}</span>
</div>
<div>
<strong>position</strong>: <span>[${element.start}-${element.end}]</span>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Use capital P on position

</div>
<div>
<strong>Length</strong>: <span>${element.end - element.start + 1}</span>
</div>
</div>
`,
allowHTML: true,
}).show();
}
} else {
(container as any)._tippy?.hide();
}
}
}}
onKeyPress={(e, selection) => {
// console.log(e, selection)
}}
onSelection={selection => this.setState({ selection })}
refs={{ circular: this.circularRef, linear: this.linearRef }}
search={this.state.search}
Expand All @@ -271,9 +408,16 @@ export default class App extends React.Component<any, AppState> {
</SeqViz>
)}
</div>
<footer>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a small padding/margin on the left

<div>Over base {this.state.hoveredBase > 0 ? this.state.hoveredBase : "-"}</div>
</footer>
</div>
</Sidebar.Pusher>
</Sidebar.Pushable>
<ContextMenu id={CONTEXT_MENU_ID}>
<Item onClick={this.handleContextMenuAddForwardTranslation}>Add forward translations</Item>
<Item onClick={this.handleContextMenuAddReverseTranslation}>Add reverse translations</Item>
</ContextMenu>
</div>
);
}
Expand Down
Loading