Skip to content

Commit

Permalink
linear map index component created
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacguerreir committed Dec 12, 2023
1 parent ea558f2 commit e6794f1
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 4 deletions.
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) {
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 }
}

0 comments on commit e6794f1

Please sign in to comment.