Skip to content

Commit 8e8cd30

Browse files
bugzpodderJack Zhaojjti
authored
add custom children support (#206)
* add custom children support * Apply suggestions from code review Co-authored-by: Joshua Timmons <joshua.timmons1@gmail.com> * Use refs for custom children ref props --------- Co-authored-by: Jack Zhao <jzhao@betteromics.com> Co-authored-by: Joshua Timmons <joshua.timmons1@gmail.com>
1 parent 7242368 commit 8e8cd30

6 files changed

Lines changed: 213 additions & 61 deletions

File tree

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export default () => (
8282

8383
#### Non-React
8484

85-
More details are in the [Viewer without React](#viewer-without-react) section.
85+
More details are in the [Viewer without React](#without-react) section.
8686

8787
```html
8888
<script>
@@ -292,6 +292,42 @@ Whether to show the complement sequence.
292292

293293
By default, the circular viewer rotates when scrolling over the viewer. That can be disabled with rotateOnScroll: false.
294294

295+
#### `Custom Rendering`
296+
297+
This makes use of the `children` and `refs` props to allow custom rendering of the sequence viewers. For example, to render the linear viewer above the circular viewer:
298+
299+
```jsx
300+
import { useRef } from "react";
301+
import { SeqViz, Linear, Circular } from "seqviz";
302+
303+
export default () => {
304+
const linearRef = useRef();
305+
const circularRef = useRef();
306+
307+
return (
308+
<SeqViz
309+
name="J23100"
310+
seq="TTGACGGCTAGCTCAGTCCTAGGTACAGTGCTAGC"
311+
refs={{circular: circularRef, linear: linearRef}}
312+
>
313+
{({ circularProps, linearProps, ...props }) => (
314+
<div
315+
style={{ display: "flex", flexDirection: "column", width: "100%" }}
316+
>
317+
<div ref={linearRef} style={{ height: "25%", width: "100%" }}>
318+
<Linear {...linearProps} {...props} />
319+
</div>
320+
<div ref={circularRef} style={{ height: "75%", width: "100%" }}>
321+
<Circular {...circularProps} {...props} />
322+
</div>
323+
</div>
324+
)}
325+
</SeqViz>
326+
);
327+
};
328+
329+
```
330+
295331
### Without React
296332

297333
For usability in non-React apps, we provide a thin wrapper around the React component. The viewer's constructor accepts two arguments:

demo/lib/App.tsx

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
} from "semantic-ui-react";
1515
import seqparse from "seqparse";
1616

17+
import Circular from "../../src/Circular/Circular";
18+
import Linear from "../../src/Linear/Linear";
1719
import SeqViz from "../../src/SeqViz";
1820
import { AnnotationProp } from "../../src/elements";
1921
import Header from "./Header";
@@ -23,10 +25,12 @@ const viewerTypeOptions = [
2325
{ key: "both", text: "Both", value: "both" },
2426
{ key: "circular", text: "Circular", value: "circular" },
2527
{ key: "linear", text: "Linear", value: "linear" },
28+
{ key: "both_flip", text: "Both Flip", value: "both_flip" },
2629
];
2730

2831
interface AppState {
2932
annotations: AnnotationProp[];
33+
customChildren: boolean;
3034
enzymes: any[];
3135
name: string;
3236
primers: boolean;
@@ -38,14 +42,15 @@ interface AppState {
3842
showIndex: boolean;
3943
showSelectionMeta: boolean;
4044
showSidebar: boolean;
41-
translations: { end: number; start: number; direction?: 1 | -1 }[];
45+
translations: { direction?: 1 | -1; end: number; start: number }[];
4246
viewer: string;
4347
zoom: number;
4448
}
4549

4650
export default class App extends React.Component<any, AppState> {
4751
state: AppState = {
4852
annotations: [],
53+
customChildren: true,
4954
enzymes: ["PstI", "EcoRI", "XbaI", "SpeI"],
5055
name: "",
5156
primers: true,
@@ -58,13 +63,15 @@ export default class App extends React.Component<any, AppState> {
5863
showSelectionMeta: false,
5964
showSidebar: false,
6065
translations: [
61-
{ end: 630, start: 6, direction: -1 },
66+
{ direction: -1, end: 630, start: 6 },
6267
{ end: 1147, start: 736 },
6368
{ end: 1885, start: 1165 },
6469
],
6570
viewer: "",
6671
zoom: 50,
6772
};
73+
linearRef: React.RefObject<HTMLDivElement> = React.createRef();
74+
circularRef: React.RefObject<HTMLDivElement> = React.createRef();
6875

6976
componentDidMount = async () => {
7077
const seq = await seqparse(file);
@@ -96,6 +103,59 @@ export default class App extends React.Component<any, AppState> {
96103
};
97104

98105
render() {
106+
107+
let customChildren = null;
108+
if (this.state.customChildren) {
109+
customChildren = ({ circularProps, linearProps, ...props }) => {
110+
if (this.state.viewer === "linear") {
111+
return (
112+
<div ref={this.linearRef} style={{ height: "100%", width: "100%" }}>
113+
<Linear {...linearProps} {...props} />
114+
</div>
115+
);
116+
} else if (this.state.viewer === "circular") {
117+
return (
118+
<div ref={this.circularRef} style={{ height: "100%", width: "100%" }}>
119+
<Circular {...circularProps} {...props} />
120+
</div>
121+
);
122+
} else if (this.state.viewer === "both") {
123+
return (
124+
<div style={{ display: "flex", flexDirection: "row", height: "100%", width: "100%" }}>
125+
<div ref={this.circularRef} style={{ height: "100%", width: "70%" }}>
126+
<Circular {...circularProps} {...props} />
127+
</div>
128+
<div ref={this.linearRef} style={{ height: "100%", width: "30%" }}>
129+
<Linear {...linearProps} {...props} />
130+
</div>
131+
</div>
132+
);
133+
} else if (this.state.viewer === "both_flip") {
134+
return (
135+
<div style={{ display: "flex", flexDirection: "row", height: "100%", width: "100%" }}>
136+
<div ref={this.linearRef} style={{ height: "100%", width: "30%" }}>
137+
<Linear {...linearProps} {...props} />
138+
</div>
139+
<div ref={this.circularRef} style={{ height: "100%", width: "70%" }}>
140+
<Circular {...circularProps} {...props} />
141+
</div>
142+
</div>
143+
);
144+
} else {
145+
return (
146+
<div style={{ display: "flex", flexDirection: "column", width: "100%" }}>
147+
<div ref={this.linearRef} style={{ height: "25%", width: "100%" }}>
148+
<Linear {...linearProps} {...props} />
149+
</div>
150+
<div ref={this.circularRef} style={{ height: "75%", width: "100%" }}>
151+
<Circular {...circularProps} {...props} />
152+
</div>
153+
</div>
154+
);
155+
}
156+
}
157+
}
158+
99159
return (
100160
<div style={{ height: "100vh" }}>
101161
<Sidebar.Pushable className="sidebar-container">
@@ -132,6 +192,13 @@ export default class App extends React.Component<any, AppState> {
132192
<Menu.Item as="a" className="options-checkbox">
133193
<CheckboxInput label="Show index" name="index" set={showIndex => this.setState({ showIndex })} />
134194
</Menu.Item>
195+
<Menu.Item as="a" className="options-checkbox">
196+
<CheckboxInput
197+
label="Custom Children"
198+
name="customChildren"
199+
set={customChildren => this.setState({ customChildren })}
200+
/>
201+
</Menu.Item>
135202
<Menu.Item as="a">
136203
<EnzymeInput enzymes={this.state.enzymes} toggleEnzyme={this.toggleEnzyme} />
137204
</Menu.Item>
@@ -149,19 +216,23 @@ export default class App extends React.Component<any, AppState> {
149216
{this.state.seq && (
150217
<SeqViz
151218
// accession="MN623123"
219+
key={`${this.state.viewer}${this.state.customChildren}`}
152220
annotations={this.state.annotations}
153221
enzymes={this.state.enzymes}
154222
name={this.state.name}
223+
refs={{circular: this.circularRef, linear: this.linearRef}}
155224
search={this.state.search}
225+
selection={this.state.selection}
156226
seq={this.state.seq}
157227
showComplement={this.state.showComplement}
158228
showIndex={this.state.showIndex}
159229
translations={this.state.translations}
160230
viewer={this.state.viewer as "linear" | "circular"}
161231
zoom={{ linear: this.state.zoom }}
162-
selection={this.state.selection}
163232
onSelection={selection => this.setState({ selection })}
164-
/>
233+
>
234+
{customChildren}
235+
</SeqViz>
165236
)}
166237
</div>
167238
</div>

src/Circular/Circular.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export type GenArcFunc = (args: {
3737
sweepFWD?: boolean;
3838
}) => string;
3939

40-
interface CircularProps {
40+
export interface CircularProps {
4141
annotations: Annotation[];
4242
center: { x: number; y: number };
4343
compSeq: string;

0 commit comments

Comments
 (0)