diff --git a/demo-no-ncolor-3ce77ba35d.tar.gz b/demo-no-ncolor-3ce77ba35d.tar.gz new file mode 100644 index 000000000..a3d7b4bd2 Binary files /dev/null and b/demo-no-ncolor-3ce77ba35d.tar.gz differ diff --git a/embed.html b/embed.html index 35843087b..de9414258 100644 --- a/embed.html +++ b/embed.html @@ -1,5 +1,6 @@ + @@ -11,23 +12,45 @@ - - -
- - + + +
+ + - + \ No newline at end of file diff --git a/js/bam/alignmentTrack.js b/js/bam/alignmentTrack.js index b67238d3d..b130799a0 100644 --- a/js/bam/alignmentTrack.js +++ b/js/bam/alignmentTrack.js @@ -1,18 +1,18 @@ import BaseModificationRenderer from "./mods/baseModificationRenderer.js" import IGVGraphics from "../igv-canvas.js" import PairedAlignment from "./pairedAlignment.js" -import {IGVColor, StringUtils} from "../../node_modules/igv-utils/src/index.js" -import {isSecureContext} from "../util/igvUtils.js" -import {createBlatTrack, maxSequenceSize} from "../blat/blatTrack.js" -import {reverseComplementSequence} from "../util/sequenceUtils.js" +import { IGVColor, StringUtils } from "../../node_modules/igv-utils/src/index.js" +import { isSecureContext } from "../util/igvUtils.js" +import { createBlatTrack, maxSequenceSize } from "../blat/blatTrack.js" +import { reverseComplementSequence } from "../util/sequenceUtils.js" import orientationTypes from "./orientationTypes.js" -import {ColorTable, PaletteColorTable} from "../util/colorPalletes.js" +import { ColorTable, PaletteColorTable } from "../util/colorPalletes.js" import TrackBase from "../trackBase.js" -import {getChrColor} from "../util/getChrColor.js" +import { getChrColor } from "../util/getChrColor.js" import $ from "../vendor/jquery-3.3.1.slim.js" -import {createCheckbox} from "../igv-icons.js" +import { createCheckbox } from "../igv-icons.js" import BaseModificationKey from "./mods/baseModificationKey.js" -import {modificationName} from "./mods/baseModificationUtils.js" +import { modificationName } from "./mods/baseModificationUtils.js" const alignmentStartGap = 5 @@ -232,7 +232,7 @@ class AlignmentTrack extends TrackBase { xBlockStart += 1 xBlockEnd -= 1 } - IGVGraphics.fillRect(ctx, xBlockStart, 2, (xBlockEnd - xBlockStart), downsampleRowHeight - 2, {fillStyle: "black"}) + IGVGraphics.fillRect(ctx, xBlockStart, 2, (xBlockEnd - xBlockStart), downsampleRowHeight - 2, { fillStyle: "black" }) }) } else { @@ -346,7 +346,7 @@ class AlignmentTrack extends TrackBase { if (alignment.mq <= 0) { connectorColor = IGVColor.addAlpha(connectorColor, 0.15) } - IGVGraphics.setProperties(ctx, {fillStyle: connectorColor, strokeStyle: connectorColor}) + IGVGraphics.setProperties(ctx, { fillStyle: connectorColor, strokeStyle: connectorColor }) IGVGraphics.strokeLine(ctx, xBlockStart, yStrokedLine, xBlockEnd, yStrokedLine) } @@ -365,7 +365,7 @@ class AlignmentTrack extends TrackBase { if (alignment.mq <= 0) { alignmentColor = IGVColor.addAlpha(alignmentColor, 0.15) } - IGVGraphics.setProperties(ctx, {fillStyle: alignmentColor, strokeStyle: outlineColor}) + IGVGraphics.setProperties(ctx, { fillStyle: alignmentColor, strokeStyle: outlineColor }) // Save bases to draw into an array for later drawing, so they can be overlaid on insertion blocks, // which is relevant if we have insertions with size label @@ -409,7 +409,7 @@ class AlignmentTrack extends TrackBase { // Add gap width as text like Java IGV if it fits nicely and is a multi-base gap if (this.showDeletionText && gap.len > 1 && lineWidth >= gapTextWidth + 8) { const textStart = gapCenter - (gapTextWidth / 2) - IGVGraphics.fillRect(ctx, textStart - 1, y - 1, gapTextWidth + 2, 12, {fillStyle: "white"}) + IGVGraphics.fillRect(ctx, textStart - 1, y - 1, gapTextWidth + 2, 12, { fillStyle: "white" }) IGVGraphics.fillText(ctx, gapLenText, textStart, y + 10, { 'font': 'normal 10px monospace', 'fillStyle': this.deletionTextColor, @@ -442,7 +442,7 @@ class AlignmentTrack extends TrackBase { const xBlockStart = (refOffset / bpPerPixel) - (widthBlock / 2) if ((xBlockStart - lastXBlockStart) > 2) { - const props = {fillStyle: this.insertionColor} + const props = { fillStyle: this.insertionColor } // Draw decorations like Java IGV to make an 'I' shape IGVGraphics.fillRect(ctx, xBlockStart - 2, y, widthBlock + 4, 2, props) @@ -463,18 +463,18 @@ class AlignmentTrack extends TrackBase { } } - for (let {bbox, baseColor, readChar} of basesToDraw) { + for (let { bbox, baseColor, readChar } of basesToDraw) { const threshold = 1.0 / 10.0 if (bpPerPixel <= threshold && bbox.height >= 8) { // render letter const fontHeight = Math.min(10, bbox.height) ctx.font = '' + fontHeight + 'px sans-serif' const center = bbox.x + (bbox.width / 2.0) - IGVGraphics.strokeText(ctx, readChar, center - (ctx.measureText(readChar).width / 2), fontHeight - 1 + bbox.y, {strokeStyle: baseColor}) + IGVGraphics.strokeText(ctx, readChar, center - (ctx.measureText(readChar).width / 2), fontHeight - 1 + bbox.y, { strokeStyle: baseColor }) } else { // render colored block - IGVGraphics.fillRect(ctx, bbox.x, bbox.y, bbox.width, bbox.height, {fillStyle: baseColor}) + IGVGraphics.fillRect(ctx, bbox.x, bbox.y, bbox.width, bbox.height, { fillStyle: baseColor }) } } @@ -564,16 +564,16 @@ class AlignmentTrack extends TrackBase { y] } - IGVGraphics.fillPolygon(ctx, xListPixel, yListPixel, {fillStyle: alignmentColor}) + IGVGraphics.fillPolygon(ctx, xListPixel, yListPixel, { fillStyle: alignmentColor }) if (strokeOutline) { - IGVGraphics.strokePolygon(ctx, xListPixel, yListPixel, {strokeStyle: blockOutlineColor}) + IGVGraphics.strokePolygon(ctx, xListPixel, yListPixel, { strokeStyle: blockOutlineColor }) } } // Internal block else { - IGVGraphics.fillRect(ctx, blockStartPixel, y, blockWidthPixel, alignmentHeight, {fillStyle: alignmentColor}) + IGVGraphics.fillRect(ctx, blockStartPixel, y, blockWidthPixel, alignmentHeight, { fillStyle: alignmentColor }) if (strokeOutline) { ctx.save() @@ -610,7 +610,7 @@ class AlignmentTrack extends TrackBase { readChar = refChar } if (readChar === "X" || refChar !== readChar || isSoftClip || showAllBases) { - + console.log(nucleotideColors) let baseColor = nucleotideColors[readChar] || "rgb(0,0,0)" if (!isSoftClip && qual !== undefined && qual.length > seqOffset + i) { const readQual = qual[seqOffset + i] @@ -646,11 +646,11 @@ class AlignmentTrack extends TrackBase { const fontHeight = Math.min(10, bbox.height) context.font = '' + fontHeight + 'px sans-serif' center = bbox.x + (bbox.width / 2.0) - IGVGraphics.strokeText(context, char, center - (context.measureText(char).width / 2), fontHeight - 1 + bbox.y, {strokeStyle: color}) + IGVGraphics.strokeText(context, char, center - (context.measureText(char).width / 2), fontHeight - 1 + bbox.y, { strokeStyle: color }) } else { // render colored block - IGVGraphics.fillRect(context, bbox.x, bbox.y, bbox.width, bbox.height, {fillStyle: color}) + IGVGraphics.fillRect(context, bbox.x, bbox.y, bbox.width, bbox.height, { fillStyle: color }) } } } @@ -679,18 +679,18 @@ class AlignmentTrack extends TrackBase { menuItems.push('
') const $e = $('
') $e.text('Color by:') - menuItems.push({name: undefined, object: $e, click: undefined, init: undefined}) + menuItems.push({ name: undefined, object: $e, click: undefined, init: undefined }) const colorByMenuItems = [] - colorByMenuItems.push({key: 'none', label: 'none'}) - colorByMenuItems.push({key: 'strand', label: 'read strand'}) + colorByMenuItems.push({ key: 'none', label: 'none' }) + colorByMenuItems.push({ key: 'strand', label: 'read strand' }) if (this.hasPairs) { - colorByMenuItems.push({key: 'firstOfPairStrand', label: 'first-of-pair strand'}) - colorByMenuItems.push({key: 'pairOrientation', label: 'pair orientation'}) - colorByMenuItems.push({key: 'tlen', label: 'insert size (TLEN)'}) - colorByMenuItems.push({key: 'unexpectedPair', label: 'pair orientation & insert size (TLEN)'}) + colorByMenuItems.push({ key: 'firstOfPairStrand', label: 'first-of-pair strand' }) + colorByMenuItems.push({ key: 'pairOrientation', label: 'pair orientation' }) + colorByMenuItems.push({ key: 'tlen', label: 'insert size (TLEN)' }) + colorByMenuItems.push({ key: 'unexpectedPair', label: 'pair orientation & insert size (TLEN)' }) } - colorByMenuItems.push({key: 'tag', label: 'tag'}) + colorByMenuItems.push({ key: 'tag', label: 'tag' }) for (let item of colorByMenuItems) { const selected = (this.colorBy === undefined && item.key === 'none') || this.colorBy === item.key menuItems.push(this.colorByCB(item, selected)) @@ -733,29 +733,29 @@ class AlignmentTrack extends TrackBase { menuItems.push('
') const $e2 = $('
') $e2.text('Group by:') - menuItems.push({name: undefined, object: $e2, click: undefined, init: undefined}) + menuItems.push({ name: undefined, object: $e2, click: undefined, init: undefined }) const groupByMenuItems = [] - groupByMenuItems.push({key: 'none', label: 'none'}) - groupByMenuItems.push({key: 'strand', label: 'read strand'}) + groupByMenuItems.push({ key: 'none', label: 'none' }) + groupByMenuItems.push({ key: 'strand', label: 'read strand' }) if (this.hasPairs) { - groupByMenuItems.push({key: 'firstOfPairStrand', label: 'first-of-pair strand'}) - groupByMenuItems.push({key: 'pairOrientation', label: 'pair orientation'}) - groupByMenuItems.push({key: 'mateChr', label: 'chromosome of mate'}) + groupByMenuItems.push({ key: 'firstOfPairStrand', label: 'first-of-pair strand' }) + groupByMenuItems.push({ key: 'pairOrientation', label: 'pair orientation' }) + groupByMenuItems.push({ key: 'mateChr', label: 'chromosome of mate' }) } - groupByMenuItems.push({key: 'chimeric', label: 'chimeric'}) - groupByMenuItems.push({key: 'supplementary', label: 'supplementary flag'}) - groupByMenuItems.push({key: 'readOrder', label: 'read order'}) + groupByMenuItems.push({ key: 'chimeric', label: 'chimeric' }) + groupByMenuItems.push({ key: 'supplementary', label: 'supplementary flag' }) + groupByMenuItems.push({ key: 'readOrder', label: 'read order' }) //groupByMenuItems.push({key: 'phase', label: 'phase'}) for (let groupByTag of this._groupByTags) { - groupByMenuItems.push({key: `tag:${groupByTag}`, label: `tag:${groupByTag}`}) + groupByMenuItems.push({ key: `tag:${groupByTag}`, label: `tag:${groupByTag}` }) } for (let groupByPos of this._groupByPositions) { - groupByMenuItems.push({key: `base:${groupByPos}`, label: `base:${groupByPos}`}) + groupByMenuItems.push({ key: `base:${groupByPos}`, label: `base:${groupByPos}` }) } - groupByMenuItems.push({key: 'tag', label: 'tag...'}) + groupByMenuItems.push({ key: 'tag', label: 'tag...' }) for (let item of groupByMenuItems) { const selected = (this.groupBy === undefined && item.key === 'none') || this.groupBy === item.key @@ -856,7 +856,7 @@ class AlignmentTrack extends TrackBase { menuItems.push('
') const $dml = $('
') $dml.text('Display mode:') - menuItems.push({name: undefined, object: $dml, click: undefined, init: undefined}) + menuItems.push({ name: undefined, object: $dml, click: undefined, init: undefined }) for (let mode of ["EXPANDED", "SQUISHED", "FULL"]) menuItems.push({ @@ -896,7 +896,7 @@ class AlignmentTrack extends TrackBase { this.trackView.repaintViews() } - return {name: undefined, object: $e, click: clickHandler, init: undefined} + return { name: undefined, object: $e, click: clickHandler, init: undefined } } else { function dialogPresentationHandler(ev) { @@ -921,7 +921,7 @@ class AlignmentTrack extends TrackBase { }, ev) } - return {name: undefined, object: $e, dialog: dialogPresentationHandler, init: undefined} + return { name: undefined, object: $e, dialog: dialogPresentationHandler, init: undefined } } } @@ -929,7 +929,7 @@ class AlignmentTrack extends TrackBase { basemodColorByCB(menuItem) { const showCheck = this.colorBy === menuItem.key - + const $e = $(createCheckbox(menuItem.label, showCheck)) function clickHandler() { @@ -941,7 +941,7 @@ class AlignmentTrack extends TrackBase { this.trackView.repaintViews() } - return {name: undefined, object: $e, click: clickHandler, init: undefined} + return { name: undefined, object: $e, click: clickHandler, init: undefined } } @@ -991,7 +991,7 @@ class AlignmentTrack extends TrackBase { } } - return {name: undefined, object: $e, dialog: clickHandler, init: undefined} + return { name: undefined, object: $e, dialog: clickHandler, init: undefined } } @@ -1025,39 +1025,39 @@ class AlignmentTrack extends TrackBase { viewport.repaint() } list.push('Sort by...') - list.push({label: '  base', click: () => sortByOption("BASE")}) - list.push({label: '  read strand', click: () => sortByOption("strand")}) - list.push({label: '  start location', click: () => sortByOption("START")}) - list.push({label: '  insert size', click: () => sortByOption("INSERT_SIZE")}) - list.push({label: '  gap size', click: () => sortByOption("GAP_SIZE")}) - list.push({label: '  chromosome of mate', click: () => sortByOption("MATE_CHR")}) - list.push({label: '  mapping quality', click: () => sortByOption("MQ")}) - list.push({label: '  read name', click: () => sortByOption("READ_NAME")}) - list.push({label: '  aligned read length', click: () => sortByOption("ALIGNED_READ_LENGTH")}) + list.push({ label: '  base', click: () => sortByOption("BASE") }) + list.push({ label: '  read strand', click: () => sortByOption("strand") }) + list.push({ label: '  start location', click: () => sortByOption("START") }) + list.push({ label: '  insert size', click: () => sortByOption("INSERT_SIZE") }) + list.push({ label: '  gap size', click: () => sortByOption("GAP_SIZE") }) + list.push({ label: '  chromosome of mate', click: () => sortByOption("MATE_CHR") }) + list.push({ label: '  mapping quality', click: () => sortByOption("MQ") }) + list.push({ label: '  read name', click: () => sortByOption("READ_NAME") }) + list.push({ label: '  aligned read length', click: () => sortByOption("ALIGNED_READ_LENGTH") }) list.push({ label: '  tag', click: () => { const cs = this.sortObject const direction = (cs && cs.position === Math.floor(clickState.genomicLocation)) ? !cs.direction : true const config = - { - label: 'Tag Name', - value: this.sortByTag ? this.sortByTag : '', - callback: (tag) => { - if (tag) { - const newSortObject = { - chr: viewport.referenceFrame.chr, - position: Math.floor(clickState.genomicLocation), - option: "TAG", - tag: tag, - direction: direction - } - this.sortByTag = tag - this.sortObject = newSortObject - viewport.cachedFeatures.sortRows(newSortObject) - viewport.repaint() + { + label: 'Tag Name', + value: this.sortByTag ? this.sortByTag : '', + callback: (tag) => { + if (tag) { + const newSortObject = { + chr: viewport.referenceFrame.chr, + position: Math.floor(clickState.genomicLocation), + option: "TAG", + tag: tag, + direction: direction } + this.sortByTag = tag + this.sortObject = newSortObject + viewport.cachedFeatures.sortRows(newSortObject) + viewport.repaint() } } + } this.browser.inputDialog.present(config, clickState.event) } }) @@ -1152,7 +1152,7 @@ class AlignmentTrack extends TrackBase { const sequence = clickedAlignment.isNegativeStrand() ? reverseComplementSequence(seqstring) : seqstring const name = `${clickedAlignment.readName} - blat` const title = `${this.name} - ${name}` - createBlatTrack({sequence, browser: this.browser, name, title}) + createBlatTrack({ sequence, browser: this.browser, name, title }) } }) } @@ -1166,7 +1166,7 @@ class AlignmentTrack extends TrackBase { const sequence = clickedAlignment.isNegativeStrand() ? reverseComplementSequence(clippedSequence) : clippedSequence const name = `${clickedAlignment.readName} - blat left clip` const title = `${this.name} - ${name}` - createBlatTrack({sequence, browser: this.browser, name, title}) + createBlatTrack({ sequence, browser: this.browser, name, title }) } }) } @@ -1178,7 +1178,7 @@ class AlignmentTrack extends TrackBase { const sequence = clickedAlignment.isNegativeStrand() ? reverseComplementSequence(clippedSequence) : clippedSequence const name = `${clickedAlignment.readName} - blat right clip` const title = `${this.name} - ${name}` - createBlatTrack({sequence, browser: this.browser, name, title}) + createBlatTrack({ sequence, browser: this.browser, name, title }) } }) } @@ -1374,6 +1374,7 @@ class AlignmentTrack extends TrackBase { } get nucleotideColors() { + console.log(this.browser.nucleotideColors) return this.browser.nucleotideColors } diff --git a/js/igv.d.ts b/js/igv.d.ts index 4f3f03d8a..70664c9d7 100644 --- a/js/igv.d.ts +++ b/js/igv.d.ts @@ -2,6 +2,9 @@ // allow extra keys type ExtraKeys = T & { [key: string]: any }; +declare class Opaque { + private readonly __opaque_brand: N; +} // TODO: Unworked types for placeholder purposes type Track = any; @@ -74,6 +77,8 @@ export interface ReferenceGenome { * only true is allowed in the type definition. * * @type {boolean=} + * + * @deprecated */ indexed?: true; /** @@ -145,7 +150,11 @@ interface CreateOptExtras { export type CreateOpt = GenomeOpt & CreateOptExtras; + declare class _Browser { + // this forces the user to cast the return value to acknowledge this is not stable + toJSON(): Opaque<'igv.js session JSON'>; + compressedSession(): string; toSVG(): string; } diff --git a/js/sequenceTrack.js b/js/sequenceTrack.js index 32a25d2e7..264695107 100755 --- a/js/sequenceTrack.js +++ b/js/sequenceTrack.js @@ -24,11 +24,11 @@ */ import IGVGraphics from "./igv-canvas.js" -import {isSecureContext} from "./util/igvUtils.js" -import {reverseComplementSequence} from "./util/sequenceUtils.js" -import {loadSequence} from "./genome/fasta.js" -import {defaultNucleotideColors} from "./util/nucleotideColors.js"; -import {createBlatTrack} from "./blat/blatTrack.js" +import { isSecureContext } from "./util/igvUtils.js" +import { reverseComplementSequence } from "./util/sequenceUtils.js" +import { loadSequence } from "./genome/fasta.js" +import { defaultNucleotideColors } from "./util/nucleotideColors.js"; +import { createBlatTrack } from "./blat/blatTrack.js" const defaultSequenceTrackOrder = Number.MIN_SAFE_INTEGER @@ -137,11 +137,11 @@ class SequenceTrack { this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT // Hack for backward compatibility - if(config.url) { + if (config.url) { config.fastaURL = config.url } - if(!config.fastaURL) { + if (!config.fastaURL) { // Mark this as the genome reference sequence ==> backward compatibility convention this.id = config.id || "sequence" } @@ -224,17 +224,17 @@ class SequenceTrack { items.push({ label: 'BLAT read sequence', - click: async () => { - let sequence = await this.browser.genome.getSequence(chr, start, end) - if (sequence) { - if (this.reversed) { - sequence = reverseComplementSequence(sequence) - } - const name = `blat: ${chr}:${start + 1}-${end}` - const title = `blat: ${chr}:${start + 1}-${end}` - createBlatTrack({sequence, browser: this.browser, name, title}) + click: async () => { + let sequence = await this.browser.genome.getSequence(chr, start, end) + if (sequence) { + if (this.reversed) { + sequence = reverseComplementSequence(sequence) } + const name = `blat: ${chr}:${start + 1}-${end}` + const title = `blat: ${chr}:${start + 1}-${end}` + createBlatTrack({ sequence, browser: this.browser, name, title }) } + } }) @@ -278,8 +278,8 @@ class SequenceTrack { * @returns {Promise} */ async getSequenceSource() { - if(this.config.fastaURL) { - if(!this.fasta) { + if (this.config.fastaURL) { + if (!this.fasta) { this.fasta = new WrappedFasta(this.config, this.browser.genome) await this.fasta.init() } @@ -314,7 +314,7 @@ class SequenceTrack { if (options.features) { let sequence = options.features.sequence - if(!sequence) { + if (!sequence) { return } @@ -340,7 +340,7 @@ class SequenceTrack { const color = this.fillColor(baseLetter.toUpperCase()) if (options.bpPerPixel > BP_PER_PIXEL_THRESHOLD) { - IGVGraphics.fillRect(ctx, aPixel, FRAME_BORDER, pixelWidth, SEQUENCE_HEIGHT - FRAME_BORDER, {fillStyle: color}) + IGVGraphics.fillRect(ctx, aPixel, FRAME_BORDER, pixelWidth, SEQUENCE_HEIGHT - FRAME_BORDER, { fillStyle: color }) } else { const textPixel = aPixel + 0.5 * (pixelWidth - ctx.measureText(baseLetter).width) @@ -350,10 +350,10 @@ class SequenceTrack { if ('y' === options.axis) { ctx.save() IGVGraphics.labelTransformWithContext(ctx, textPixel) - IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {strokeStyle: color}) + IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, { strokeStyle: color }) ctx.restore() } else { - IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {strokeStyle: color}) + IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, { strokeStyle: color }) } } @@ -395,7 +395,7 @@ class SequenceTrack { aaLabel = 'START' //Color blind accessible } - IGVGraphics.fillRect(ctx, p0, y, p1 - p0, FRAME_HEIGHT, {fillStyle: color}) + IGVGraphics.fillRect(ctx, p0, y, p1 - p0, FRAME_HEIGHT, { fillStyle: color }) if (options.bpPerPixel <= 1 / 10) { IGVGraphics.strokeText(ctx, aaLabel, pc - (ctx.measureText(aaLabel).width / 2), y + 15) @@ -463,7 +463,7 @@ class WrappedFasta { async init() { this.fasta = await loadSequence(this.config) this.chrNameMap = new Map() - for(let name of this.fasta.chromosomeNames) { + for (let name of this.fasta.chromosomeNames) { this.chrNameMap.set(this.genome.getChromosomeName(name), name) } } @@ -475,7 +475,7 @@ class WrappedFasta { } -export {defaultSequenceTrackOrder, bppSequenceThreshold, translationDict } +export { defaultSequenceTrackOrder, bppSequenceThreshold, translationDict } export default SequenceTrack diff --git a/js/tests.ts b/js/tests.ts new file mode 100644 index 000000000..37bc7933c --- /dev/null +++ b/js/tests.ts @@ -0,0 +1,73 @@ +import igv, { CreateOpt, Opaque } from './igv'; + + +const IGV_TARGETS = ["H3K4me3", "H3K27me3"]; +const IGV_COLORS = ["green", "red"]; +const CHR = "chr11"; +const VIEWPORT_CENTER = 101_173_617; +const VIEWPORT_EXTENT = 300_000; +const LOCUS_SEARCH = `${CHR}:${VIEWPORT_CENTER - VIEWPORT_EXTENT / 2}-${VIEWPORT_CENTER + VIEWPORT_EXTENT / 2}`; + +// @ts-expect-error +const x: Opaque<'Internal Opaque JSON'> = { a: 1 } as Opaque<'Internal Opaque JSON'>; + +// @ts-expect-error +console.log(x.a); + +console.log((x as any).a); + +~async function () { + const igvDiv = document.getElementById('igv-app'); + const igvOptions: CreateOpt = { + genome: 'mm10', + locus: LOCUS_SEARCH, + tracks: [...IGV_TARGETS + .map(target => ({ + names: target, + min: 0, + max: 4.0, + autoscale: false, + type: "wig", + format: "bigWig", + url: `/submodules/mikkelson_2007/bowtie2/mergedLibrary/bigwig/ES_${target}_IP.bigWig` + })) + .map((track, i) => ({ + ...track, + color: IGV_COLORS[i] + })) + , + { + names: "MysteryFactorX", + type: "annotation", + format: "bed", + url: "/data/MysteryFactorX_ChIPseq_mm10.bed" + }], + nucleotideColors: { + A: 'red', + C: 'blue', + T: 'green', + G: 'orange', + N: 'black', + // @ts-expect-error + a: 'red', + } + }; + + + const igvapp = await igv.createBrowser(igvDiv!, igvOptions); + + // @ts-expect-error + const igvappBad = await igv.createBrowser(igvDiv!, { gename: 'mm10' }); + + const igvsvg = igvapp.toSVG(); + const svgBlob = new Blob([igvsvg], { + type: 'image/svg+xml' + }); + const svgUrl = URL.createObjectURL(svgBlob); + const svgLink = document.createElement('a'); + svgLink.href = svgUrl; + svgLink.download = 'igv.svg'; + svgLink.innerText = 'Download SVG'; + document.body.appendChild(svgLink); + +}()