gene.ts 2.04 KB
Newer Older
Remi  PLANEL's avatar
Remi PLANEL committed
1
import { select, Selection } from "d3-selection"
2
import { ScaleLinear, scaleLinear } from "d3-scale";
Remi  PLANEL's avatar
Remi PLANEL committed
3
import { arrowShape } from "./gene-shapes";
4
import linearGene from "../../layout/linear-gene";
5
6
import { of } from "rxjs";
import { mergeMap } from "rxjs/operators";
7
8
9

type Strand = "+" | "-";

Remi  PLANEL's avatar
Remi PLANEL committed
10
11
export interface GeneData {
  name: string,
12
13
14
15
  strand: Strand,
  begin: number,
  end: number,
  gene: string
16
17
18
  eventHandler: {
    click: ([begin, end]: [number, number]) => void
  }
Remi  PLANEL's avatar
Remi PLANEL committed
19
}
20
21
22
23
24
25
26
27
export interface PositionedGeneData extends GeneData {
  position: {
    x: number,
    y: number,
    width: number
  }
}

Remi  PLANEL's avatar
Remi PLANEL committed
28
29

export default function () {
30
  function gene(
31
32
33
34
    _selection: Selection<SVGElement, Array<GeneData>, HTMLElement, any>,
    xScale: ScaleLinear<number, number>,
    geneHeight: number = 30,
    yPosition: number = 60
35
  ) {
Remi  PLANEL's avatar
Remi PLANEL committed
36
37
    _selection.each(function (_data: Array<GeneData>) {
      const container = select(this);
38
39
      const genes = container
        .selectAll<SVGGElement, PositionedGeneData>('.gene')
40
        .data(linearGene(_data, xScale, yPosition));
Remi  PLANEL's avatar
Remi PLANEL committed
41
42

      // ENTER
43
44
45
46
      const enterGenes = genes
        .enter()
        .append<SVGGElement>('g')
        .classed("gene", true);
47

Remi  PLANEL's avatar
Remi PLANEL committed
48
      enterGenes.append("path");
49

Remi  PLANEL's avatar
Remi PLANEL committed
50
51
52
53
54
55
      // EXIT
      genes.exit().remove()

      // UPDATE
      const updateGenes = genes.merge(enterGenes);

56
      // set the positions
57
      updateGenes.attr("transform", d => "translate(" + d.position.x + "," + d.position.y + ")");
58
      updateGenes
59
        .select<SVGPathElement>("path")
Remi  PLANEL's avatar
Remi PLANEL committed
60
        .style("fill", d => d.strand === "+" ? "darkred": "darkblue")
61
62
        .attr(
          "transform",
63
          ({ strand, position: { width } }) => (strand === "-")
64
            ? "translate(0," + (geneHeight + 5)  + ") translate(" + width + "," + geneHeight + ") rotate(180)"
65
66
67
            : null
        )
        .attr("d", d => arrowShape(d, geneHeight))
68
69
70
71
72
        .on("click", d => of(d).pipe(
          mergeMap(d => of<[number, number]>([d.begin, d.end])
          )
        ).subscribe(d.eventHandler.click)
        );
Remi  PLANEL's avatar
Remi PLANEL committed
73
74
75
76
77
78
79
80
    })
  }
  return gene;

}