{"spec_id":"genome-track-multi","library":"muix","language":"javascript","code":"// anyplot.ai\n// genome-track-multi: Genome Track Viewer\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 95/100 | Created: 2026-08-25\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { useXScale, useDrawingArea } from \"@mui/x-charts/hooks\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) — a 12 kb window at chr7:140,700,000+ --\n// Positions are stored as bp offsets from REGION_START so axis ticks stay short.\nconst REGION_LABEL = \"chr7:140,700,000-140,712,000\";\nconst REGION_END = 12000;\n\nconst GENES = [\n  {\n    symbol: \"GENE1\",\n    strand: \"+\",\n    exons: [\n      [400, 1100],\n      [1900, 2300],\n      [3100, 3900],\n      [4400, 4900],\n    ],\n  },\n  {\n    symbol: \"GENE2\",\n    strand: \"-\",\n    exons: [\n      [6600, 7200],\n      [7900, 8300],\n      [9000, 9600],\n      [10100, 10700],\n      [11100, 11600],\n    ],\n  },\n];\n\nconst REGULATORY = [\n  { type: \"promoter\", start: 100, end: 400 },\n  { type: \"enhancer\", start: 5100, end: 5500 },\n  { type: \"promoter\", start: 6300, end: 6600 },\n  { type: \"enhancer\", start: 11800, end: 12000 },\n];\n\nconst VARIANTS = [\n  { pos: 550, type: \"SNP\", quality: 42 },\n  { pos: 1050, type: \"indel\", quality: 28 },\n  { pos: 2150, type: \"SNP\", quality: 55 },\n  { pos: 3400, type: \"SNP\", quality: 33 },\n  { pos: 4650, type: \"indel\", quality: 47 },\n  { pos: 5800, type: \"SNP\", quality: 50 },\n  { pos: 7000, type: \"SNP\", quality: 38 },\n  { pos: 8900, type: \"indel\", quality: 52 },\n  { pos: 10300, type: \"SNP\", quality: 44 },\n];\nconst MAX_QUALITY = 60;\n\n// Read-coverage samples every 200 bp, boosted inside exons (RNA-seq-style signal).\nconst ALL_EXONS = GENES.flatMap((gene) => gene.exons);\nfunction insideExon(offset) {\n  return ALL_EXONS.some(([start, end]) => offset >= start && offset <= end);\n}\n\nlet lcgSeed = 42;\nfunction nextRandom() {\n  lcgSeed = (lcgSeed * 1103515245 + 12345) & 0x7fffffff;\n  return lcgSeed / 0x7fffffff;\n}\n\nconst COVERAGE = [];\nfor (let offset = 0; offset <= REGION_END; offset += 200) {\n  const baseline = 6 + nextRandom() * 5;\n  const exonBoost = insideExon(offset) ? 45 + nextRandom() * 25 : 0;\n  COVERAGE.push({ offset, depth: baseline + exonBoost });\n}\nconst MAX_DEPTH = Math.max(...COVERAGE.map((sample) => sample.depth));\n\nconst GRID_STEP = 2000;\nconst REGULATORY_COLOR = { promoter: t.palette[1], enhancer: t.palette[2] };\nconst VARIANT_COLOR = { SNP: t.palette[4], indel: t.palette[5] };\nconst TRACKS = [\"Genes\", \"Regulatory\", \"Coverage\", \"Variants\"];\nconst LEGEND_ITEMS = [\n  { label: \"Exon\", color: t.palette[0] },\n  { label: \"Promoter\", color: t.palette[1] },\n  { label: \"Enhancer\", color: t.palette[2] },\n  { label: \"SNP\", color: t.palette[4] },\n  { label: \"Indel\", color: t.palette[5] },\n];\n\nconst TITLE = \"genome-track-multi · javascript · muix · anyplot.ai\";\nconst TITLE_HEIGHT = 40;\nconst LEGEND_HEIGHT = 30;\n\n// --- Per-track SVG renderers (positioned from the shared genomic x-scale) ---\nfunction GenesTrack({ xScale, top, height }) {\n  const centerY = top + height / 2;\n  const exonHeight = Math.min(28, height * 0.4);\n  const exonTop = centerY - exonHeight / 2;\n\n  return (\n    <g>\n      {GENES.map((gene) => {\n        const geneStart = gene.exons[0][0];\n        const geneEnd = gene.exons[gene.exons.length - 1][1];\n        const arrowOffsets = [];\n        for (let offset = geneStart + 300; offset < geneEnd; offset += 500) {\n          arrowOffsets.push(offset);\n        }\n\n        return (\n          <g key={gene.symbol}>\n            <line x1={xScale(geneStart)} x2={xScale(geneEnd)} y1={centerY} y2={centerY} stroke={t.inkSoft} strokeWidth={2} />\n            {arrowOffsets.map((offset) => {\n              const x = xScale(offset);\n              const dx = gene.strand === \"+\" ? 5 : -5;\n              return (\n                <path\n                  key={`${gene.symbol}-arrow-${offset}`}\n                  d={`M ${x - dx} ${centerY - 5} L ${x + dx} ${centerY} L ${x - dx} ${centerY + 5}`}\n                  stroke={t.inkSoft}\n                  strokeWidth={1.5}\n                  fill=\"none\"\n                />\n              );\n            })}\n            {gene.exons.map(([start, end]) => (\n              <rect\n                key={`${gene.symbol}-${start}`}\n                x={xScale(start)}\n                y={exonTop}\n                width={Math.max(1, xScale(end) - xScale(start))}\n                height={exonHeight}\n                fill={t.palette[0]}\n              />\n            ))}\n            <text x={xScale(geneStart)} y={exonTop - 8} fontSize={13} fill={t.inkSoft}>\n              {`${gene.symbol} (${gene.strand})`}\n            </text>\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\nfunction RegulatoryTrack({ xScale, top, height }) {\n  const rectHeight = height * 0.55;\n  const rectTop = top + (height - rectHeight) / 2;\n\n  return (\n    <g>\n      {REGULATORY.map((element) => (\n        <rect\n          key={`${element.type}-${element.start}`}\n          x={xScale(element.start)}\n          y={rectTop}\n          width={Math.max(2, xScale(element.end) - xScale(element.start))}\n          height={rectHeight}\n          fill={REGULATORY_COLOR[element.type]}\n          rx={2}\n        />\n      ))}\n    </g>\n  );\n}\n\nfunction CoverageTrack({ xScale, top, height }) {\n  const baseline = top + height - 6;\n  const usableHeight = height - 14;\n  const points = COVERAGE.map((sample) => {\n    const x = xScale(sample.offset);\n    const y = baseline - (sample.depth / MAX_DEPTH) * usableHeight;\n    return `${x},${y}`;\n  });\n  const firstX = xScale(COVERAGE[0].offset);\n  const lastX = xScale(COVERAGE[COVERAGE.length - 1].offset);\n  const areaPath = `M ${firstX},${baseline} L ${points.join(\" L \")} L ${lastX},${baseline} Z`;\n\n  return <path d={areaPath} fill={t.palette[0]} fillOpacity={0.35} stroke={t.palette[0]} strokeWidth={1.5} />;\n}\n\nfunction VariantsTrack({ xScale, top, height }) {\n  const baseline = top + height - 6;\n  const usableHeight = height - 20;\n\n  return (\n    <g>\n      {VARIANTS.map((variant) => {\n        const x = xScale(variant.pos);\n        const stemTop = baseline - (variant.quality / MAX_QUALITY) * usableHeight;\n        const color = VARIANT_COLOR[variant.type];\n        return (\n          <g key={`variant-${variant.pos}`}>\n            <line x1={x} x2={x} y1={baseline} y2={stemTop} stroke={color} strokeWidth={1.5} />\n            <circle cx={x} cy={stemTop} r={5} fill={color} />\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\n// Reads the container's real x-scale so every track lines up on one genomic\n// axis, and lays out track bands from the drawing area — not an approximation.\nfunction GenomeTracks() {\n  const xScale = useXScale();\n  const drawing = useDrawingArea();\n  const gap = 12;\n  const bandHeight = (drawing.height - gap * (TRACKS.length - 1)) / TRACKS.length;\n  const bandTop = (index) => drawing.top + index * (bandHeight + gap);\n  const gridOffsets = Array.from({ length: Math.floor(REGION_END / GRID_STEP) + 1 }, (_, i) => i * GRID_STEP);\n\n  return (\n    <g>\n      {gridOffsets.map((offset) => (\n        <line\n          key={`grid-${offset}`}\n          x1={xScale(offset)}\n          x2={xScale(offset)}\n          y1={drawing.top}\n          y2={drawing.top + drawing.height}\n          stroke={t.grid}\n          strokeWidth={1}\n        />\n      ))}\n      {TRACKS.map((_, index) =>\n        index % 2 === 1 ? (\n          <rect key={`band-${index}`} x={drawing.left} y={bandTop(index)} width={drawing.width} height={bandHeight} fill={t.elevatedBg} />\n        ) : null,\n      )}\n      {TRACKS.map((label, index) => (\n        <text key={`label-${index}`} x={drawing.left - 14} y={bandTop(index) + bandHeight / 2} textAnchor=\"end\" dominantBaseline=\"middle\" fontSize={15} fontWeight={500} fill={t.ink}>\n          {label}\n        </text>\n      ))}\n      <GenesTrack xScale={xScale} top={bandTop(0)} height={bandHeight} />\n      <RegulatoryTrack xScale={xScale} top={bandTop(1)} height={bandHeight} />\n      <CoverageTrack xScale={xScale} top={bandTop(2)} height={bandHeight} />\n      <VariantsTrack xScale={xScale} top={bandTop(3)} height={bandHeight} />\n    </g>\n  );\n}\n\n// --- Chart (default-exported component — the harness mounts it) -------------\nexport default function Chart() {\n  const width = window.ANYPLOT_SIZE.width;\n  const height = window.ANYPLOT_SIZE.height;\n  const chartHeight = height - TITLE_HEIGHT - LEGEND_HEIGHT;\n\n  return (\n    <Box sx={{ width, height, display: \"flex\", flexDirection: \"column\", boxSizing: \"border-box\", px: 2 }}>\n      <Typography sx={{ fontSize: 22, fontWeight: 500, color: t.ink, lineHeight: `${TITLE_HEIGHT}px` }}>{TITLE}</Typography>\n      <Box sx={{ display: \"flex\", alignItems: \"center\", gap: 3, height: LEGEND_HEIGHT }}>\n        {LEGEND_ITEMS.map((item) => (\n          <Box key={item.label} sx={{ display: \"flex\", alignItems: \"center\", gap: 0.75 }}>\n            <Box sx={{ width: 12, height: 12, borderRadius: \"2px\", bgcolor: item.color }} />\n            <Typography sx={{ fontSize: 13, color: t.inkSoft }}>{item.label}</Typography>\n          </Box>\n        ))}\n      </Box>\n      <ChartContainer\n        width={width - 32}\n        height={chartHeight}\n        series={[]}\n        skipAnimation\n        margin={{ left: 140, right: 30, top: 16, bottom: 50 }}\n        xAxis={[\n          {\n            id: \"genomicPosition\",\n            scaleType: \"linear\",\n            min: 0,\n            max: REGION_END,\n            valueFormatter: (value) => value.toLocaleString(\"en-US\"),\n            tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n            label: `Position (bp) — ${REGION_LABEL}`,\n            labelStyle: { fontSize: 14, fill: t.inkSoft },\n          },\n        ]}\n      >\n        <ChartsXAxis />\n        <GenomeTracks />\n      </ChartContainer>\n    </Box>\n  );\n}\n"}