Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linear Map View #251

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
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
21 changes: 17 additions & 4 deletions demo/lib/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,24 @@ import { AnnotationProp, Primer } from "../../src/elements";
import Header from "./Header";
import file from "./file";

enum ViewerTypeOptions {
LINEAR="LINEAR",
CIRCULAR="CIRCULAR",
LINEAR_MAP="LINEAR_MAP",
BOTH_CIRCULAR="BOTH_CIRCULAR",
BOTH_FLIP_CIRCULAR="BOTH_FLIP_CIRCULAR",
BOTH_LINEAR_MAP="BOTH_LINEAR_MAP",
BOTH_FLIP_LINEAR_MAP="BOTH_FLIP_LINEAR_MAP"
}

const viewerTypeOptions = [
{ key: "both", text: "Both", value: "both" },
{ key: "circular", text: "Circular", value: "circular" },
{ key: "linear", text: "Linear", value: "linear" },
{ key: "both_flip", text: "Both Flip", value: "both_flip" },
{ key: ViewerTypeOptions.CIRCULAR, text: "Circular", value: ViewerTypeOptions.CIRCULAR },
{ key: ViewerTypeOptions.LINEAR, text: "Linear", value: ViewerTypeOptions.LINEAR },
{ key: ViewerTypeOptions.LINEAR_MAP, text: "Linear Map", value: ViewerTypeOptions.LINEAR_MAP },
{ key: ViewerTypeOptions.BOTH_CIRCULAR, text: "Circular + Linear", value: ViewerTypeOptions.BOTH_CIRCULAR },
{ key: ViewerTypeOptions.BOTH_FLIP_CIRCULAR, text: "Linear + Circular", value: ViewerTypeOptions.BOTH_FLIP_CIRCULAR },
{ key: ViewerTypeOptions.BOTH_LINEAR_MAP, text: "Linear Map + Linear", value: ViewerTypeOptions.BOTH_LINEAR_MAP },
{ key: ViewerTypeOptions.BOTH_FLIP_LINEAR_MAP, text: "Linear + Linear Map", value: ViewerTypeOptions.BOTH_FLIP_LINEAR_MAP }
];

interface AppState {
Expand Down
57 changes: 57 additions & 0 deletions src/LinearMap/Index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from "react";
import { indexLine, indexTick, indexTickLabel } from "../style";
import { useBuilder } from "./hooks/useBuilder";
import { Tick } from "./Tick";


/**
* The Index component renders the Linear Map's:
* 1. name (center or bottom)
* 2. number of bps (center or bottom)
* 3. index ticks and numbers along the Linear Map
*/

export interface IndexProps {
height: number
width: number
seqLength: number
}

export function Index(props: IndexProps) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can I use functional components @jjti ou should I maintain the class components being used throughout the project?

const { ruler, ticks } = useBuilder(props)

return (
<g>

{/* The ticks and their index labels */}
{ticks.map((tick: Tick) => (
<g key={`la-vz-tick-${tick.position}`}>
<path
className="la-vz-index-tick"
d={tick.path}
style={indexTick}
/>
<text
className="la-vz-index-tick-label"
style={indexTickLabel}
textAnchor="middle"
x={tick.text.x}
y={tick.text.y}
>
{tick.position}
</text>
</g>
))
}

{/* The ruler is abstract line representing sequence length and giving relative references for other elements as Annotations, Cut sites, Primers, etc. */}
<g>
<path
className="la-vz-index-line"
d={ruler.path}
style={indexLine}
/>
</g>
</g>
);
}
Empty file added src/LinearMap/LinearMap.tsx
Empty file.
30 changes: 30 additions & 0 deletions src/LinearMap/Ruler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export class Ruler {
readonly LATERAL_PADDING = 10

height: number
width: number
seqLength: number
start: number
end: number
padByBp: number

constructor(
height: number,
width: number,
seqLength: number
) {
this.height = height/2
this.start = this.LATERAL_PADDING
this.end = width - this.LATERAL_PADDING
this.width = this.end - this.start
this.seqLength = seqLength
this.padByBp = this.width / seqLength
}

get path() {
return `
M ${this.start} ${this.height}
L ${this.end} ${this.height}
`
}
}
72 changes: 72 additions & 0 deletions src/LinearMap/Tick.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Ruler } from "./Ruler"

export class RulerTicks {
private readonly HORIZONTAL_TICK_LENGTH = 10
private readonly TICK_COUNT = 6
private ruler: Ruler

constructor(ruler: Ruler) {
this.ruler = ruler
}

private getPadByPosition(bpPosition: number) {
return this.ruler.start + this.ruler.padByBp * bpPosition
}

private getTickPath(position: number) {
const pad = this.getPadByPosition(position)
return `
M ${pad} ${this.ruler.height}
L ${pad} ${this.ruler.height + this.HORIZONTAL_TICK_LENGTH}
`
}

private getTickText(rightPad: number) {
const TICK_TEXT_LINE = this.HORIZONTAL_TICK_LENGTH * 2
const textLineHeight = this.ruler.height + TICK_TEXT_LINE
return {
x: rightPad,
y: textLineHeight
}
}

private getTick(position: number): Tick {
const rightPad = this.getPadByPosition(position)
return {
position,
path: this.getTickPath(position),
text: this.getTickText(rightPad)
}
}

private buildTicks(positions: number[]) {
return positions.map(position => this.getTick(position))
}

get positions(): number[] {
const increments = Math.floor(this.ruler.seqLength / this.TICK_COUNT);
let indexInc = Math.max(+increments.toPrecision(2), 10);
while (indexInc % 10 !== 0) indexInc += 1;
//
let ticks: number[] = [];
for (let i = indexInc; i <= this.ruler.seqLength - indexInc; i += indexInc) {
ticks.push(i === 0 ? 1 : i);
}

return ticks
}

get ticks(): Tick[] {
return this.buildTicks(this.positions)
}
}


export interface Tick {
position: number
path: string
text: {
x: number
y: number
}
}
18 changes: 18 additions & 0 deletions src/LinearMap/hooks/useBuilder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useMemo } from "react"
import { IndexProps } from "../Index"
import { Ruler } from "../Ruler"
import { RulerTicks } from "../Tick"

type BuilderProps = IndexProps
export function useBuilder({ height, width, seqLength }: BuilderProps) {
const { ruler, ticks } = useMemo(() => {
const ruler = new Ruler(height, width, seqLength)
const ticks = new RulerTicks(ruler).ticks
return {
ruler,
ticks
}
}, [height, width, seqLength])

return { ruler, ticks }
}
Loading