npm package: @omicsos/circular-genome-viewer
Description: React components for interactive circular and linear genome maps, powered by CGView.js
Latest version: 0.1.4

# @omicsos/circular-genome-viewer

![Circular Genome Viewer](public/banner.png)

React component library for interactive circular and linear bacterial genome/plasmid maps. Wraps [CGView.js](https://js.cgview.ca/) and [CGParse.js](https://github.com/sciguy/cgview-parse) with a typed React API supporting GenBank, EMBL, FASTA, and GFF input formats.

## Installation

```bash
npm install @omicsos/circular-genome-viewer
```

Peer dependencies (must be in your project already):

```bash
npm install react react-dom   # >=18
```

## Quick Start

### Zero-config (SimpleGenomeViewer)

```tsx
import { SimpleGenomeViewer } from '@omicsos/circular-genome-viewer';

function App() {
  return (
    <SimpleGenomeViewer
      genbankData={genbankString}
      theme="dark"
      width={800}
      height={800}
    />
  );
}
```

Renders a circular map with GC content, GC skew, and ORF tracks enabled automatically.

### Full control (CgviewViewer)

```tsx
import {
  CgviewViewer,
  RESISTANCE_HIGHLIGHTS,
} from '@omicsos/circular-genome-viewer';
import type { CgviewFeature } from '@omicsos/circular-genome-viewer';

function GenomeMap({ genbankData }: { genbankData: string }) {
  return (
    <CgviewViewer
      genbankData={genbankData}
      mapStyle="circular"
      theme="dark"
      tracks={{ gcContent: true, gcSkew: true, orfs: false }}
      highlights={RESISTANCE_HIGHLIGHTS}
      width="100%"
      height={600}
      onFeatureClick={(f: CgviewFeature) => {
        console.log(`Clicked: ${f.name} (${f.type}) at ${f.start}..${f.stop}`);
      }}
      onFeatureHover={(f) => {
        if (f) console.log(`Hovering: ${f.name}`);
      }}
    />
  );
}
```

### Using pre-built CGView JSON

```tsx
<CgviewViewer cgviewJson={prebuiltConfig} theme="light" />
```

### Custom feature highlighting

```tsx
import type { FeatureHighlight } from '@omicsos/circular-genome-viewer';

const myHighlights: FeatureHighlight[] = [
  {
    match: { qualifier: { key: 'product', pattern: 'beta-lactamase' } },
    color: '#EF4444',
    legend: 'Beta-lactam resistance',
  },
  {
    match: { name: /tet[A-Z]/ },
    color: '#EAB308',
    legend: 'Tetracycline genes',
  },
  {
    match: { type: 'tRNA' },
    color: '#3B82F6',
    legend: 'Transfer RNAs',
  },
];

<CgviewViewer genbankData={data} highlights={myHighlights} />;
```

## API Reference

### Components

| Component | Description |
|-----------|-------------|
| `CgviewViewer` | Full-featured viewer with all props |
| `SimpleGenomeViewer` | Zero-config wrapper: pass GenBank string, get a circular map |

### CgviewViewer Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `genbankData` | `string` | -- | Raw sequence data (GenBank, EMBL, FASTA, or GFF) |
| `cgviewJson` | `Record<string, unknown>` | -- | Pre-built CGView JSON config (alternative to genbankData) |
| `format` | `'genbank' \| 'embl' \| 'fasta' \| 'gff'` | `'genbank'` | Input format |
| `mapStyle` | `'circular' \| 'linear'` | -- | Display mode |
| `theme` | `'light' \| 'dark'` | -- | Color theme |
| `themeOverrides` | `CgviewThemeOverrides` | -- | Partial overrides merged on top of the selected theme (fonts, colors, dividers) |
| `tracks` | `TrackConfig` | -- | Toggle GC content, GC skew, ORF tracks |
| `highlights` | `FeatureHighlight[]` | -- | Feature highlighting rules |
| `width` | `number \| string` | `'100%'` | Container width (px or CSS value) |
| `height` | `number \| string` | `'100%'` | Container height (px or CSS value) |
| `className` | `string` | -- | Additional CSS class |
| `onFeatureClick` | `(feature: CgviewFeature) => void` | -- | Feature click callback |
| `onFeatureHover` | `(feature: CgviewFeature \| null) => void` | -- | Feature hover callback |
| `onSelection` | `(event: CgviewSelectionEvent) => void` | -- | Range selection callback (planned) |

### SimpleGenomeViewer Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `genbankData` | `string` | **(required)** | Raw GenBank data string |
| `theme` | `'light' \| 'dark'` | `'dark'` | Color theme |
| `width` | `number \| string` | -- | Container width |
| `height` | `number \| string` | -- | Container height |
| `className` | `string` | -- | Additional CSS class |

### Types

All types are exported for TypeScript consumers:

```tsx
import type {
  CgviewViewerProps,
  CgviewFeature,
  FeatureHighlight,
  TrackConfig,
  CgviewSelectionEvent,
  SimpleGenomeViewerProps,
  CgviewTheme,
  CgviewThemeOverrides,
} from '@omicsos/circular-genome-viewer';
```

### Presets

| Export | Description |
|--------|-------------|
| `RESISTANCE_HIGHLIGHTS` | 7 AMR gene categories: beta-lactam, aminoglycoside, tetracycline, vancomycin, macrolide, mobile elements, integrases |
| `PMLST_HIGHLIGHTS` | Plasmid MLST loci (repA/B/C) |

### Utilities

| Export | Description |
|--------|-------------|
| `getCgviewTheme(theme)` | Returns `CgviewTheme` object for `'light'` or `'dark'` |
| `applyTracks(config, tracks)` | Adds GC/ORF tracks to a CGView config |
| `applyHighlights(config, highlights)` | Applies feature highlight rules |
| `applyMapStyle(config, style)` | Sets circular or linear format |
| `applyTheme(config, theme)` | Applies theme colors |
| `normalizeFeature(raw)` | Converts raw CGView feature to typed `CgviewFeature` |

## Development

```bash
npm install            # Install dependencies
npm run dev            # Dev playground (loads pBR322 plasmid with interactive controls)
npm run build          # Build to dist/ (ESM + CJS + .d.ts)
npm test               # Run tests
npm run test:watch     # Watch mode
```

## Project Structure

```
src/
  index.ts                  Package entry point (all exports)
  types.ts                  Public TypeScript interfaces
  CgviewViewer.tsx          Main viewer component
  SimpleGenomeViewer.tsx    Zero-config convenience wrapper
  utils/
    cgviewConfig.ts         Pure config transforms (tracks, highlights, theme, style)
    cgviewThemes.ts         Light/dark theme definitions
  presets/
    resistance.ts           RESISTANCE_HIGHLIGHTS and PMLST_HIGHLIGHTS
  __tests__/                Unit tests
dev/
  App.tsx                   Interactive dev playground
tests/
  fixtures/
    pBR322.gbk              Real plasmid (4,361 bp)
    minimal.gbk             Synthetic minimal GenBank
dist/
  circular-genome-viewer.js   ESM bundle
  circular-genome-viewer.cjs  CJS bundle
  index.d.ts                  TypeScript declarations
```

## Tech Stack

- **Rendering:** [CGView.js](https://js.cgview.ca/) v1.8+ (Canvas-based, handles genomes up to 10 Mbp)
- **Parsing:** [CGParse.js](https://github.com/sciguy/cgview-parse) v1.1+ (GenBank/EMBL/FASTA/GFF to CGView JSON)
- **Framework:** React 18+
- **Build:** Vite library mode (ESM + CJS + .d.ts)
- **Testing:** Vitest + Testing Library
- **Language:** TypeScript (strict mode)

## Acknowledgments

This library is a React wrapper around these excellent open-source projects by [Jason Grant](https://github.com/sciguy):

- **[CGView.js](https://js.cgview.ca/)** — Canvas-based genome map renderer (Apache-2.0)
- **[CGParse.js](https://github.com/sciguy/cgview-parse)** — Sequence format parser for GenBank, EMBL, FASTA, and GFF (Apache-2.0)

CGView.js powers [Proksee.ca](https://proksee.ca/), a web-based tool for genome assembly and annotation.

## License

Apache-2.0 — see [LICENSE](./LICENSE) for details.