', {class: 'igv-zoom-in-notice-container'})
- $parent.append($container)
+ createZoomInNotice(parentElement) {
+ const container = document.createElement('div');
+ container.className = 'igv-zoom-in-notice-container';
+ parentElement.appendChild(container);
- const $e = $('
')
- $container.append($e)
+ const e = document.createElement('div');
+ container.appendChild(e);
- $e.text('Zoom in to see features')
+ e.textContent = 'Zoom in to see features';
- $container.hide()
+ container.style.display = 'none';
- return $container
+ return container;
}
viewIsReady() {
- return this.browser && this.browser.referenceFrameList && this.referenceFrame
+ return this.browser && this.browser.referenceFrameList && this.referenceFrame;
}
addMouseHandlers() {
+ const viewport = this.viewportElement;
- const viewport = this.$viewport.get(0)
-
- this.addViewportContextMenuHandler(viewport)
+ this.addViewportContextMenuHandler(viewport);
// Mouse down
const md = (event) => {
- this.enableClick = true
- this.browser.mouseDownOnViewport(event, this)
- mouseDownCoords = DOMUtils.pageCoordinates(event)
- }
- viewport.addEventListener('mousedown', md)
- viewport.addEventListener('touchstart', md)
+ this.enableClick = true;
+ this.browser.mouseDownOnViewport(event, this);
+ mouseDownCoords = DOMUtils.pageCoordinates(event);
+ };
+ viewport.addEventListener('mousedown', md);
+ viewport.addEventListener('touchstart', md);
// Mouse up
const mu = (event) => {
// Any mouse up cancels drag and scrolling
if (this.browser.dragObject || this.browser.isScrolling) {
- this.browser.cancelTrackPan()
- // event.preventDefault();
- // event.stopPropagation();
- this.enableClick = false // Until next mouse down
+ this.browser.cancelTrackPan();
+ this.enableClick = false; // Until next mouse down
} else {
- this.browser.cancelTrackPan()
- this.browser.endTrackDrag()
+ this.browser.cancelTrackPan();
+ this.browser.endTrackDrag();
}
- }
- viewport.addEventListener('mouseup', mu)
- viewport.addEventListener('touchend', mu)
+ };
+ viewport.addEventListener('mouseup', mu);
+ viewport.addEventListener('touchend', mu);
// Mouse move
if (typeof this.trackView.track.hoverText === 'function') {
- viewport.addEventListener('mousemove', (event => {
+ viewport.addEventListener('mousemove', (event) => {
if (event.buttons === 0 && (Date.now() - lastHoverUpdateTime > 100)) {
- lastHoverUpdateTime = Date.now()
- const clickState = this.createClickState(event)
+ lastHoverUpdateTime = Date.now();
+ const clickState = this.createClickState(event);
if (clickState) {
- const tooltip = this.trackView.track.hoverText(clickState)
+ const tooltip = this.trackView.track.hoverText(clickState);
if (tooltip) {
- this.$viewport[0].setAttribute("title", tooltip)
+ this.viewportElement.setAttribute("title", tooltip);
} else {
- this.$viewport[0].removeAttribute("title")
+ this.viewportElement.removeAttribute("title");
}
}
}
- }))
+ });
}
- this.addViewportClickHandler(this.$viewport.get(0))
+ this.addViewportClickHandler(viewport);
if (this.trackView.track.name && "sequence" !== this.trackView.track.config.type) {
- this.addTrackLabelClickHandler(this.$trackLabel.get(0))
+ this.addTrackLabelClickHandler(this.trackLabel);
}
-
}
addViewportContextMenuHandler(viewport) {
-
viewport.addEventListener('contextmenu', (event) => {
-
// Ignore if we are doing a drag. This can happen with touch events.
if (this.browser.dragObject) {
- return false
+ return false;
}
- const clickState = this.createClickState(event)
+ const clickState = this.createClickState(event);
if (undefined === clickState) {
- return false
+ return false;
}
- event.preventDefault()
+ event.preventDefault();
// Track specific items
- let menuItems = []
+ let menuItems = [];
if (typeof this.trackView.track.contextMenuItemList === "function") {
- const trackMenuItems = this.trackView.track.contextMenuItemList(clickState)
+ const trackMenuItems = this.trackView.track.contextMenuItemList(clickState);
if (trackMenuItems) {
- menuItems = trackMenuItems
+ menuItems = trackMenuItems;
}
}
// Add items common to all tracks
if (menuItems.length > 0) {
- menuItems.push({label: $('
')})
+ menuItems.push({ label: '
' });
}
- menuItems.push({label: 'Save Image (PNG)', click: () => this.savePNG()})
- menuItems.push({label: 'Save Image (SVG)', click: () => this.saveSVG()})
-
- this.browser.menuPopup.presentTrackContextMenu(event, menuItems)
- })
+ menuItems.push({ label: 'Save Image (PNG)', click: () => this.savePNG() });
+ menuItems.push({ label: 'Save Image (SVG)', click: () => this.saveSVG() });
+ this.browser.menuPopup.presentTrackContextMenu(event, menuItems);
+ });
}
-
addViewportClickHandler(viewport) {
-
viewport.addEventListener('click', (event) => {
-
if (this.enableClick && this.canvas) {
if (3 === event.which || event.ctrlKey) {
- return
+ return;
}
if (this.browser.dragObject || this.browser.isScrolling) {
- return
+ return;
}
// Treat as a mouse click, it's either a single or double click.
// Handle here and stop propagation / default
- event.preventDefault()
+ event.preventDefault();
- const mouseX = DOMUtils.translateMouseCoordinates(event, this.$viewport.get(0)).x
- const mouseXCanvas = DOMUtils.translateMouseCoordinates(event, this.canvas).x
- const referenceFrame = this.referenceFrame
- const xBP = Math.floor((referenceFrame.start) + referenceFrame.toBP(mouseXCanvas))
+ const mouseX = DOMUtils.translateMouseCoordinates(event, this.viewportElement).x;
+ const mouseXCanvas = DOMUtils.translateMouseCoordinates(event, this.canvas).x;
+ const referenceFrame = this.referenceFrame;
+ const xBP = Math.floor((referenceFrame.start) + referenceFrame.toBP(mouseXCanvas));
- const time = Date.now()
+ const time = Date.now();
if (time - lastClickTime < this.browser.constants.doubleClickDelay) {
-
// double-click
if (popupTimerID) {
- window.clearTimeout(popupTimerID)
- popupTimerID = undefined
+ window.clearTimeout(popupTimerID);
+ popupTimerID = undefined;
}
- const centerBP = Math.round(referenceFrame.start + referenceFrame.toBP(mouseX))
+ const centerBP = Math.round(referenceFrame.start + referenceFrame.toBP(mouseX));
- let string
+ let string;
if ('all' === this.referenceFrame.chr.toLowerCase()) {
-
- const chr = this.browser.genome.getChromosomeCoordinate(centerBP).chr
+ const chr = this.browser.genome.getChromosomeCoordinate(centerBP).chr;
if (1 === this.browser.referenceFrameList.length) {
- string = chr
+ string = chr;
} else {
- const loci = this.browser.referenceFrameList.map(({locusSearchString}) => locusSearchString)
- const index = this.browser.referenceFrameList.indexOf(this.referenceFrame)
- loci[index] = chr
- string = loci.join(' ')
+ const loci = this.browser.referenceFrameList.map(({ locusSearchString }) => locusSearchString);
+ const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
+ loci[index] = chr;
+ string = loci.join(' ');
}
- this.browser.search(string)
-
+ this.browser.search(string);
} else {
- this.browser.zoomWithScaleFactor(0.5, centerBP, this.referenceFrame)
+ this.browser.zoomWithScaleFactor(0.5, centerBP, this.referenceFrame);
}
-
-
} else {
// single-click
-
- /*if (event.shiftKey && typeof this.trackView.track.shiftClick === "function") {
-
- this.trackView.track.shiftClick(xBP, event)
-
- } else */
-
if (typeof this.trackView.track.popupData === "function") {
-
popupTimerID = setTimeout(() => {
+ const content = this.getPopupContent(event);
+ if (content) {
+ if (false === event.shiftKey) {
+ if (popover) {
+ popover.dispose();
+ }
- const content = this.getPopupContent(event)
- if (content) {
-
- if (false === event.shiftKey) {
-
- if (popover) {
- popover.dispose()
- }
-
- if (trackViewportPopoverList.length > 0) {
- for (const gp of trackViewportPopoverList) {
- gp.dispose()
- }
- trackViewportPopoverList.length = 0
+ if (trackViewportPopoverList.length > 0) {
+ for (const gp of trackViewportPopoverList) {
+ gp.dispose();
}
+ trackViewportPopoverList.length = 0;
+ }
- popover = new Popover(this.$viewport.get(0).parentElement, true, undefined, () => {
- popover.dispose()
- })
-
- popover.presentContentWithEvent(event, content)
- } else {
-
- let po = new Popover(this.$viewport.get(0).parentElement, true, undefined, () => {
- const index = trackViewportPopoverList.indexOf(po)
- trackViewportPopoverList.splice(index, 1)
- po.dispose()
- })
+ popover = new Popover(this.viewportElement.parentElement, true, undefined, () => {
+ popover.dispose();
+ });
- trackViewportPopoverList.push(po)
+ popover.presentContentWithEvent(event, content);
+ } else {
+ let po = new Popover(this.viewportElement.parentElement, true, undefined, () => {
+ const index = trackViewportPopoverList.indexOf(po);
+ trackViewportPopoverList.splice(index, 1);
+ po.dispose();
+ });
- po.presentContentWithEvent(event, content)
- }
+ trackViewportPopoverList.push(po);
+ po.presentContentWithEvent(event, content);
}
- window.clearTimeout(popupTimerID)
- popupTimerID = undefined
- },
- this.browser.constants.doubleClickDelay)
+ }
+ window.clearTimeout(popupTimerID);
+ popupTimerID = undefined;
+ }, this.browser.constants.doubleClickDelay);
}
}
- lastClickTime = time
-
+ lastClickTime = time;
}
- })
+ });
}
addTrackLabelClickHandler(trackLabel) {
-
trackLabel.addEventListener('click', (event) => {
+ event.stopPropagation();
- event.stopPropagation()
-
- const {track} = this.trackView
+ const { track } = this.trackView;
- let str
+ let str;
if (typeof track.description === 'function') {
- str = track.description()
+ str = track.description();
} else if (track.description) {
- str = `
${track.description}
`
+ str = `
${track.description}
`;
}
if (str) {
if (undefined === this.popover) {
- this.popover = new Popover(this.browser.columnContainer, true, (track.name || ''), undefined)
+ this.popover = new Popover(this.browser.columnContainer, true, (track.name || ''), undefined);
}
- this.popover.presentContentWithEvent(event, str)
+ this.popover.presentContentWithEvent(event, str);
}
- })
+ });
}
createClickState(event) {
+ if (!this.canvas) return; // Can happen during initialization
- if (!this.canvas) return // Can happen during initialization
-
- const referenceFrame = this.referenceFrame
- const viewportCoords = DOMUtils.translateMouseCoordinates(event, this.$viewport.get(0))
- const canvasCoords = DOMUtils.translateMouseCoordinates(event, this.canvas)
- const genomicLocation = (((referenceFrame.start) + referenceFrame.toBP(viewportCoords.x)))
+ const referenceFrame = this.referenceFrame;
+ const viewportCoords = DOMUtils.translateMouseCoordinates(event, this.viewportElement);
+ const canvasCoords = DOMUtils.translateMouseCoordinates(event, this.canvas);
+ const genomicLocation = (((referenceFrame.start) + referenceFrame.toBP(viewportCoords.x)));
return {
event,
@@ -848,117 +787,96 @@ class TrackViewport extends Viewport {
y: viewportCoords.y - this.contentTop,
canvasX: canvasCoords.x,
canvasY: canvasCoords.y
- }
-
+ };
}
getPopupContent(event) {
-
- const clickState = this.createClickState(event)
+ const clickState = this.createClickState(event);
if (undefined === clickState) {
- return
+ return;
}
- let track = this.trackView.track
- const dataList = track.popupData(clickState)
+ let track = this.trackView.track;
+ const dataList = track.popupData(clickState);
- const popupClickHandlerResult = this.browser.fireEvent('trackclick', [track, dataList])
+ const popupClickHandlerResult = this.browser.fireEvent('trackclick', [track, dataList]);
- let content
+ let content;
if (undefined === popupClickHandlerResult || true === popupClickHandlerResult) {
// Indicates handler did not handle the result, or the handler wishes default behavior to occur
if (dataList && dataList.length > 0) {
- content = formatPopoverText(dataList)
+ content = formatPopoverText(dataList);
}
-
} else if (typeof popupClickHandlerResult === 'string') {
- content = popupClickHandlerResult
+ content = popupClickHandlerResult;
}
- return content
+ return content;
}
dispose() {
-
if (this.popover) {
- this.popover.dispose()
+ this.popover.dispose();
}
- // if (trackViewportPopoverList) {
- // for (let i = 0; i < trackViewportPopoverList.length; i++ ) {
- // trackViewportPopoverList[ i ].dispose()
- // }
- //
- // trackViewportPopoverList = undefined
- // }
-
- super.dispose()
+ super.dispose();
}
-
}
-
function formatPopoverText(nameValues) {
-
const rows = nameValues.map(nameValue => {
-
if (nameValue.name) {
- const str = `
${nameValue.name}   ${nameValue.value}`
- return `
${str}
`
+ const str = `
${nameValue.name} ${nameValue.value}`;
+ return `
${str}
`;
} else if ('
' === nameValue) { // this can be retired if nameValue.html is allowed.
- return nameValue
+ return nameValue;
} else if (nameValue.html) {
- return nameValue.html
+ return nameValue.html;
} else {
- return `
${nameValue}
`
+ return `
${nameValue}
`;
}
+ });
- })
-
- return rows.join('')
+ return rows.join('');
}
class FeatureCache {
-
constructor(chr, tileStart, tileEnd, bpPerPixel, features, roiFeatures, multiresolution, windowFunction) {
- this.chr = chr
- this.bpStart = tileStart
- this.bpEnd = tileEnd
- this.bpPerPixel = bpPerPixel
- this.features = features
- this.roiFeatures = roiFeatures
- this.multiresolution = multiresolution
- this.windowFunction = windowFunction
+ this.chr = chr;
+ this.bpStart = tileStart;
+ this.bpEnd = tileEnd;
+ this.bpPerPixel = bpPerPixel;
+ this.features = features;
+ this.roiFeatures = roiFeatures;
+ this.multiresolution = multiresolution;
+ this.windowFunction = windowFunction;
}
containsRange(chr, start, end, bpPerPixel, windowFunction) {
-
- if (windowFunction && windowFunction !== this.windowFunction) return false
+ if (windowFunction && windowFunction !== this.windowFunction) return false;
// For multi-resolution tracks allow for a 2X change in bpPerPixel
- const r = this.multiresolution ? this.bpPerPixel / bpPerPixel : 1
+ const r = this.multiresolution ? this.bpPerPixel / bpPerPixel : 1;
- return start >= this.bpStart && end <= this.bpEnd && chr === this.chr && r > 0.5 && r < 2
+ return start >= this.bpStart && end <= this.bpEnd && chr === this.chr && r > 0.5 && r < 2;
}
overlapsRange(chr, start, end) {
- return this.chr === chr && end >= this.bpStart && start <= this.bpEnd
+ return this.chr === chr && end >= this.bpStart && start <= this.bpEnd;
}
}
-
/**
* Merge 2 arrays. a and/or b can be undefined. If both are undefined, return undefined
* @param a An array or undefined
* @param b An array or undefined
*/
function mergeArrays(a, b) {
- if (a && b) return a.concat(b)
- else if (a) return a
- else return b
-
+ if (a && b) return a.concat(b);
+ else if (a) return a;
+ else return b;
}
-export {trackViewportPopoverList}
-export default TrackViewport
+export { trackViewportPopoverList };
+export default TrackViewport;
diff --git a/js/variant/variantTrack.js b/js/variant/variantTrack.js
index 42e0dd70f..d54ee0929 100644
--- a/js/variant/variantTrack.js
+++ b/js/variant/variantTrack.js
@@ -24,26 +24,24 @@
* THE SOFTWARE.
*/
-import $ from "../vendor/jquery-3.3.1.slim.js"
-import FeatureSource from '../feature/featureSource.js'
-import TrackBase from "../trackBase.js"
-import IGVGraphics from "../igv-canvas.js"
-import {createCheckbox} from "../igv-icons.js"
-import {ColorTable, PaletteColorTable} from "../util/colorPalletes.js"
-import SampleInfo from "../sample/sampleInfo.js"
-import {makeVCFChords, sendChords} from "../jbrowse/circularViewUtils.js"
-import {FileUtils, StringUtils, IGVColor} from "../../node_modules/igv-utils/src/index.js"
-import CNVPytorTrack from "../cnvpytor/cnvpytorTrack.js"
-import {doSortByAttributes} from "../sample/sampleUtils.js"
-
-const isString = StringUtils.isString
-
-const DEFAULT_COLOR = "rgb(0,0,150)"
-const DEFAULT_VISIBILITY_WINDOW = 1000000
-const TOP_MARGIN = 10
+import FeatureSource from '../feature/featureSource.js';
+import TrackBase from "../trackBase.js";
+import IGVGraphics from "../igv-canvas.js";
+import { createCheckbox } from "../igv-icons.js";
+import { ColorTable, PaletteColorTable } from "../util/colorPalletes.js";
+import SampleInfo from "../sample/sampleInfo.js";
+import { makeVCFChords, sendChords } from "../jbrowse/circularViewUtils.js";
+import { FileUtils, StringUtils, IGVColor } from "../../node_modules/igv-utils/src/index.js";
+import CNVPytorTrack from "../cnvpytor/cnvpytorTrack.js";
+import { doSortByAttributes } from "../sample/sampleUtils.js";
+
+const isString = StringUtils.isString;
+
+const DEFAULT_COLOR = "rgb(0,0,150)";
+const DEFAULT_VISIBILITY_WINDOW = 1000000;
+const TOP_MARGIN = 10;
class VariantTrack extends TrackBase {
-
static defaults = {
displayMode: "EXPANDED",
sortDirection: "ASC",
@@ -69,136 +67,130 @@ class VariantTrack extends TrackBase {
visibilityWindow: undefined,
labelDisplayMode: undefined,
type: "variant"
- }
+ };
- _sortDirections = new Map()
+ _sortDirections = new Map();
constructor(config, browser) {
- super(config, browser)
+ super(config, browser);
}
// Note -- init gets called during base class construction. Confusing
init(config) {
-
- super.init(config)
+ super.init(config);
if (config.variantHeight) {
// Override for backward compatibility
- this.expandedVariantHeight = config.variantHeight
+ this.expandedVariantHeight = config.variantHeight;
}
- this.featureSource = FeatureSource(config, this.browser.genome)
+ this.featureSource = FeatureSource(config, this.browser.genome);
- this.colorTables = new Map()
+ this.colorTables = new Map();
if (config.colorTable) {
- const key = config.colorBy || "*"
- this.colorTables.set(key, new ColorTable(config.colorTable))
+ const key = config.colorBy || "*";
+ this.colorTables.set(key, new ColorTable(config.colorTable));
}
- this.strokecolor = config.strokecolor
- this._context_hook = config.context_hook
+ this.strokecolor = config.strokecolor;
+ this._context_hook = config.context_hook;
// If a color is explicitly set disable colorBy
if (config.color) {
- this.colorBy = undefined
+ this.colorBy = undefined;
}
// The number of variant rows are computed dynamically, but start with "1" by default
- this.nVariantRows = 1
+ this.nVariantRows = 1;
// Explicitly set samples -- used to select a subset of samples from a dataset
if (config.samples) {
// Explicit setting, keys == names
- for (let s of config.samples) {
- this.sampleKeys = config.samples
- }
+ this.sampleKeys = config.samples;
}
if (config.sort) {
- this.initialSort = config.sort
+ this.initialSort = config.sort;
}
- this._colorByItems = new Map([['none', 'None']])
+ this._colorByItems = new Map([['none', 'None']]);
}
async postInit() {
-
- this.header = await this.getHeader()
+ this.header = await this.getHeader();
// Set colorBy, if not explicitly set default to allele frequency, if available, otherwise default to none (undefined)
- const infoFields = new Set(Object.keys(this.header.INFO))
+ const infoFields = new Set(Object.keys(this.header.INFO));
if (this.config.colorBy) {
- this.colorBy = this.config.colorBy
+ this.colorBy = this.config.colorBy;
} else if (!this.config.color && infoFields.has('AF')) {
- this.colorBy = 'AF'
+ this.colorBy = 'AF';
}
// Configure menu items based on info available
if (infoFields.has('AF')) {
- this._colorByItems.set('AF', 'Allele frequency')
+ this._colorByItems.set('AF', 'Allele frequency');
}
if (infoFields.has('VT')) {
- this._colorByItems.set('VT', 'Variant Type')
+ this._colorByItems.set('VT', 'Variant Type');
}
if (infoFields.has('SVTYPE')) {
- this._colorByItems.set('SVTYPE', 'SV Type')
+ this._colorByItems.set('SVTYPE', 'SV Type');
}
if (this.config.colorBy && !this._colorByItems.has(this.config.colorBy)) {
- this._colorByItems.set(this.config.colorBy, this.config.colorBy)
+ this._colorByItems.set(this.config.colorBy, this.config.colorBy);
}
-
- if (this.disposed) return // This track was removed during async load
+ if (this.disposed) return; // This track was removed during async load
if (this.header && !this.sampleKeys) {
- this.sampleKeys = this.header.sampleNameMap ? Array.from(this.header.sampleNameMap.keys()) : []
+ this.sampleKeys = this.header.sampleNameMap ? Array.from(this.header.sampleNameMap.keys()) : [];
}
if (undefined === this.visibilityWindow && this.config.indexed !== false) {
- const fn = FileUtils.isFile(this.config.url) ? this.config.url.name : this.config.url
+ const fn = FileUtils.isFile(this.config.url) ? this.config.url.name : this.config.url;
if (isString(fn) && fn.toLowerCase().includes("gnomad")) {
- this.visibilityWindow = 1000 // these are known to be very dense
+ this.visibilityWindow = 1000; // these are known to be very dense
} else if (typeof this.featureSource.defaultVisibilityWindow === 'function') {
- this.visibilityWindow = await this.featureSource.defaultVisibilityWindow()
+ this.visibilityWindow = await this.featureSource.defaultVisibilityWindow();
} else {
- this.visibilityWindow = DEFAULT_VISIBILITY_WINDOW
+ this.visibilityWindow = DEFAULT_VISIBILITY_WINDOW;
}
}
- return this
+ return this;
}
get supportsWholeGenome() {
- return !this.config.indexURL || this.config.supportsWholeGenome === true
+ return !this.config.indexURL || this.config.supportsWholeGenome === true;
}
get color() {
- return this._color || DEFAULT_COLOR
+ return this._color || DEFAULT_COLOR;
}
set color(c) {
- this._color = c
+ this._color = c;
if (c) {
- this.colorBy = undefined
+ this.colorBy = undefined;
}
}
async getHeader() {
if (!this.header) {
if (typeof this.featureSource.getHeader === "function") {
- this.header = await this.featureSource.getHeader()
+ this.header = await this.featureSource.getHeader();
}
}
- return this.header
+ return this.header;
}
getSampleCount() {
- return this.sampleKeys ? this.sampleKeys.length : 0
+ return this.sampleKeys ? this.sampleKeys.length : 0;
}
async getFeatures(chr, start, end, bpPerPixel) {
-
if (this.header === undefined) {
- this.header = await this.getHeader()
+ this.header = await this.getHeader();
}
const features = await this.featureSource.getFeatures({
chr,
@@ -206,45 +198,44 @@ class VariantTrack extends TrackBase {
end,
bpPerPixel,
visibilityWindow: this.visibilityWindow
- })
+ });
if (this.initialSort) {
- const sort = this.initialSort
+ const sort = this.initialSort;
if (sort.option === undefined || sort.option.toUpperCase() === "GENOTYPE") {
- this.sortSamplesByGenotype(sort, features)
+ this.sortSamplesByGenotype(sort, features);
} else if ("ATTRIBUTE" === sort.option.toUpperCase() && sort.attribute) {
- const sortDirection = "ASC" === sort.direction ? 1 : -1
- this.sortByAttribute(sort.attribute, sortDirection)
+ const sortDirection = "ASC" === sort.direction ? 1 : -1;
+ this.sortByAttribute(sort.attribute, sortDirection);
}
- this.initialSort = undefined // Sample order is sorted,
+ this.initialSort = undefined; // Sample order is sorted,
}
- return features
+ return features;
}
hasSamples() {
- return this.getSampleCount() > 0
+ return this.getSampleCount() > 0;
}
/**
* Required method of the sample name and info viewports
*/
getSamples() {
-
- const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap
- const nVariantRows = "COLLAPSED" === this.displayMode ? 1 : this.nVariantRows
- const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight
- const callHeight = ("SQUISHED" === this.displayMode ? this.squishedCallHeight : this.expandedCallHeight)
- const height = nVariantRows * (callHeight + vGap)
+ const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap;
+ const nVariantRows = "COLLAPSED" === this.displayMode ? 1 : this.nVariantRows;
+ const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
+ const callHeight = ("SQUISHED" === this.displayMode ? this.squishedCallHeight : this.expandedCallHeight);
+ const height = nVariantRows * (callHeight + vGap);
// Y Offset at which samples begin
- const yOffset = TOP_MARGIN + nVariantRows * (variantHeight + vGap)
+ const yOffset = TOP_MARGIN + nVariantRows * (variantHeight + vGap);
return {
names: this.sampleKeys,
yOffset,
height
- }
+ };
}
/**
@@ -255,353 +246,267 @@ class VariantTrack extends TrackBase {
* @returns {*}
*/
computePixelHeight(features) {
+ if (!features || 0 === features.length) return TOP_MARGIN;
- if (!features || 0 === features.length) return TOP_MARGIN
-
- const nVariantRows = (this.displayMode === "COLLAPSED") ? 1 : this.nVariantRows
- const vGap = (this.displayMode === "SQUISHED") ? this.squishedVGap : this.expandedVGap
- const variantHeight = (this.displayMode === "SQUISHED") ? this.squishedVariantHeight : this.expandedVariantHeight
- const callHeight = (this.displayMode === "SQUISHED") ? this.squishedCallHeight : this.expandedCallHeight
- const nGenotypes = this.showGenotypes === false ? 0 : this.getSampleCount() * nVariantRows
- const h = TOP_MARGIN + nVariantRows * (variantHeight + vGap)
- return h + vGap + (nGenotypes + 1) * (callHeight + vGap)
-
+ const nVariantRows = (this.displayMode === "COLLAPSED") ? 1 : this.nVariantRows;
+ const vGap = (this.displayMode === "SQUISHED") ? this.squishedVGap : this.expandedVGap;
+ const variantHeight = (this.displayMode === "SQUISHED") ? this.squishedVariantHeight : this.expandedVariantHeight;
+ const callHeight = (this.displayMode === "SQUISHED") ? this.squishedCallHeight : this.expandedCallHeight;
+ const nGenotypes = this.showGenotypes === false ? 0 : this.getSampleCount() * nVariantRows;
+ const h = TOP_MARGIN + nVariantRows * (variantHeight + vGap);
+ return h + vGap + (nGenotypes + 1) * (callHeight + vGap);
}
variantRowCount(count) {
- this.nVariantRows = count
+ this.nVariantRows = count;
}
- draw({context, pixelWidth, pixelHeight, bpPerPixel, bpStart, pixelTop, features}) {
-
- IGVGraphics.fillRect(context, 0, pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"})
+ draw({ context, pixelWidth, pixelHeight, bpPerPixel, bpStart, pixelTop, features }) {
+ IGVGraphics.fillRect(context, 0, pixelTop, pixelWidth, pixelHeight, { 'fillStyle': "rgb(255, 255, 255)" });
- const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap
- const rowCount = ("COLLAPSED" === this.displayMode) ? 1 : this.nVariantRows
- const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight
- this.variantBandHeight = TOP_MARGIN + rowCount * (variantHeight + vGap)
+ const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap;
+ const rowCount = ("COLLAPSED" === this.displayMode) ? 1 : this.nVariantRows;
+ const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
+ this.variantBandHeight = TOP_MARGIN + rowCount * (variantHeight + vGap);
- let callSets = this.sampleColumns
+ let callSets = this.sampleColumns;
- const hasSamples = this.hasSamples()
+ const hasSamples = this.hasSamples();
if (callSets && hasSamples && this.showGenotypes !== false) {
- IGVGraphics.strokeLine(context, 0, this.variantBandHeight, pixelWidth, this.variantBandHeight, {strokeStyle: 'rgb(224,224,224) '})
+ IGVGraphics.strokeLine(context, 0, this.variantBandHeight, pixelWidth, this.variantBandHeight, { strokeStyle: 'rgb(224,224,224) ' });
}
if (features) {
-
- const callHeight = ("SQUISHED" === this.displayMode) ? this.squishedCallHeight : this.expandedCallHeight
- const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap
- const bpEnd = bpStart + pixelWidth * bpPerPixel + 1
+ const callHeight = ("SQUISHED" === this.displayMode) ? this.squishedCallHeight : this.expandedCallHeight;
+ const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
// Loop through variants. A variant == a row in a VCF file
for (let v of features) {
- if (v.end < bpStart) continue
- if (v.start > bpEnd) break
+ if (v.end < bpStart) continue;
+ if (v.start > bpEnd) break;
- const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight
- const y = TOP_MARGIN + ("COLLAPSED" === this.displayMode ? 0 : v.row * (variantHeight + vGap))
- const h = variantHeight
+ const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
+ const y = TOP_MARGIN + ("COLLAPSED" === this.displayMode ? 0 : v.row * (variantHeight + vGap));
+ const h = variantHeight;
// Compute pixel width. Minimum width is 3 pixels, if > 5 pixels create gap between variants
- let x = (v.start - bpStart) / bpPerPixel
- let x1 = (v.end - bpStart) / bpPerPixel
+ let x = (v.start - bpStart) / bpPerPixel;
+ let x1 = (v.end - bpStart) / bpPerPixel;
- let w = Math.max(1, x1 - x)
+ let w = Math.max(1, x1 - x);
if (w < 3) {
- w = 3
- x -= 1
+ w = 3;
+ x -= 1;
} else if (w > 5) {
- x += 1
- w -= 2
+ x += 1;
+ w -= 2;
}
- const variant = v._f || v // True variant record, used for whole genome view and SV mate records
- let af
+ const variant = v._f || v; // True variant record, used for whole genome view and SV mate records
+ let af;
try {
- af = variant.alleleFreq()
+ af = variant.alleleFreq();
} catch (e) {
- console.log(e)
+ console.log(e);
}
if ("AF" === this.colorBy && af) {
- const hAlt = Math.min(1, af) * h
- const hRef = h - hAlt
- context.fillStyle = variant.isFiltered() ? this.refColorFiltered : this.refColor
- context.fillRect(x, y, w, hRef)
- context.fillStyle = variant.isFiltered() ? this.altColorFiltered : this.altColor
- context.fillRect(x, y + hRef, w, hAlt)
-
+ const hAlt = Math.min(1, af) * h;
+ const hRef = h - hAlt;
+ context.fillStyle = variant.isFiltered() ? this.refColorFiltered : this.refColor;
+ context.fillRect(x, y, w, hRef);
+ context.fillStyle = variant.isFiltered() ? this.altColorFiltered : this.altColor;
+ context.fillRect(x, y + hRef, w, hAlt);
} else {
- context.fillStyle = this.getColorForFeature(variant)
- context.fillRect(x, y, w, h)
+ context.fillStyle = this.getColorForFeature(variant);
+ context.fillRect(x, y, w, h);
}
//only paint stroke if a color is defined
- let strokecolor = this.getVariantStrokecolor(variant)
+ let strokecolor = this.getVariantStrokecolor(variant);
if (strokecolor) {
- context.strokeStyle = strokecolor
- context.strokeRect(x, y, w, h)
+ context.strokeStyle = strokecolor;
+ context.strokeRect(x, y, w, h);
}
// call hook if _context_hook fn is defined
- this.callContextHook(variant, context, x, y, w, h)
-
- //variant.pixelRect = {x, y, w, h}
+ this.callContextHook(variant, context, x, y, w, h);
// Loop though the samples for this variant.
if (hasSamples && this.showGenotypes !== false) {
+ const nVariantRows = "COLLAPSED" === this.displayMode ? 1 : this.nVariantRows;
+ this.sampleYOffset = this.variantBandHeight + vGap;
+ this.sampleHeight = nVariantRows * (callHeight + vGap); // For each sample, there is a call for each variant at this position
- const nVariantRows = "COLLAPSED" === this.displayMode ? 1 : this.nVariantRows
- this.sampleYOffset = this.variantBandHeight + vGap
- this.sampleHeight = nVariantRows * (callHeight + vGap) // For each sample, there is a call for each variant at this position
-
- let sampleNumber = 0
+ let sampleNumber = 0;
for (let sample of this.sampleKeys) {
-
- const index = this.header.sampleNameMap.get(sample)
- const call = variant.calls[index]
+ const index = this.header.sampleNameMap.get(sample);
+ const call = variant.calls[index];
if (call) {
- const row = "COLLAPSED" === this.displayMode ? 0 : variant.row
- const py = this.sampleYOffset + sampleNumber * this.sampleHeight + row * (callHeight + vGap)
- let allVar = true // until proven otherwise
- let allRef = true
- let noCall = false
+ const row = "COLLAPSED" === this.displayMode ? 0 : variant.row;
+ const py = this.sampleYOffset + sampleNumber * this.sampleHeight + row * (callHeight + vGap);
+ let allVar = true; // until proven otherwise
+ let allRef = true;
+ let noCall = false;
if (call.genotype) {
for (let g of call.genotype) {
if ('.' === g) {
- noCall = true
- break
+ noCall = true;
+ break;
} else {
- if (g !== 0) allRef = false
- if (g === 0) allVar = false
+ if (g !== 0) allRef = false;
+ if (g === 0) allVar = false;
}
}
}
if (!call.genotype) {
- context.fillStyle = this.noGenotypeColor
+ context.fillStyle = this.noGenotypeColor;
} else if (noCall) {
- context.fillStyle = this.noCallColor
+ context.fillStyle = this.noCallColor;
} else if (allRef) {
- context.fillStyle = this.homrefColor
+ context.fillStyle = this.homrefColor;
} else if (allVar) {
- context.fillStyle = this.homvarColor
+ context.fillStyle = this.homvarColor;
} else {
- context.fillStyle = this.hetvarColor
+ context.fillStyle = this.hetvarColor;
}
- context.fillRect(x, py, w, callHeight)
-
- //callSet.pixelRect = {x, y: py, w, h: callHeight}
+ context.fillRect(x, py, w, callHeight);
}
- sampleNumber++
+ sampleNumber++;
}
-
}
}
-
} else {
- console.log("No feature list")
+ console.log("No feature list");
}
- };
+ }
get refColorFiltered() {
if (!this._refColorFiltered) {
- this._refColorFiltered = IGVColor.addAlpha(this.refColor, 0.2)
+ this._refColorFiltered = IGVColor.addAlpha(this.refColor, 0.2);
}
- return this._refColorFiltered
+ return this._refColorFiltered;
}
get altColorFiltered() {
if (!this._altColorFiltered) {
- this._altColorFiltered = IGVColor.addAlpha(this.altColor, 0.2)
+ this._altColorFiltered = IGVColor.addAlpha(this.altColor, 0.2);
}
- return this._altColorFiltered
+ return this._altColorFiltered;
}
getColorForFeature(variant) {
-
- const v = variant._f || variant
- let variantColor
+ const v = variant._f || variant;
+ let variantColor;
if (this.colorBy && 'none' !== this.colorBy) {
-
- const value = v.getAttributeValue(this.colorBy)
- variantColor = value !== undefined ? this.getVariantColorTable(this.colorBy).getColor(value) : "gray"
-
+ const value = v.getAttributeValue(this.colorBy);
+ variantColor = value !== undefined ? this.getVariantColorTable(this.colorBy).getColor(value) : "gray";
} else if (this.color) {
- variantColor = (typeof this.color === "function") ? this.color(variant) : this.color
+ variantColor = (typeof this.color === "function") ? this.color(variant) : this.color;
} else if ("NONVARIANT" === v.type) {
- variantColor = this.nonRefColor
+ variantColor = this.nonRefColor;
} else if ("MIXED" === v.type) {
- variantColor = this.mixedColor
+ variantColor = this.mixedColor;
} else {
- variantColor = this.color
+ variantColor = this.color;
}
if (v.isFiltered()) {
- variantColor = IGVColor.addAlpha(variantColor, 0.2)
+ variantColor = IGVColor.addAlpha(variantColor, 0.2);
}
- return variantColor
+ return variantColor;
}
-
getVariantStrokecolor(variant) {
-
- const v = variant._f || variant
- let variantStrokeColor
+ const v = variant._f || variant;
+ let variantStrokeColor;
if (this.strokecolor) {
- variantStrokeColor = (typeof this.strokecolor === "function") ? this.strokecolor(v) : this.strokecolor
+ variantStrokeColor = (typeof this.strokecolor === "function") ? this.strokecolor(v) : this.strokecolor;
} else {
- variantStrokeColor = undefined
+ variantStrokeColor = undefined;
}
- return variantStrokeColor
+ return variantStrokeColor;
}
callContextHook(variant, context, x, y, w, h) {
if (this._context_hook) {
if (typeof this._context_hook === "function") {
- const v = variant._f || variant
+ const v = variant._f || variant;
- context.save()
- this._context_hook(v, context, x, y, w, h)
- context.restore()
+ context.save();
+ this._context_hook(v, context, x, y, w, h);
+ context.restore();
}
}
}
clickedFeatures(clickState) {
+ let featureList = super.clickedFeatures(clickState);
- let featureList = super.clickedFeatures(clickState)
-
- const vGap = (this.displayMode === 'EXPANDED') ? this.expandedVGap : this.squishedVGap
- const callHeight = vGap + ("SQUISHED" === this.displayMode ? this.squishedCallHeight : this.expandedCallHeight)
+ const vGap = (this.displayMode === 'EXPANDED') ? this.expandedVGap : this.squishedVGap;
+ const callHeight = vGap + ("SQUISHED" === this.displayMode ? this.squishedCallHeight : this.expandedCallHeight);
// Find the variant row (i.e. row assigned during feature packing)
- const yOffset = clickState.y
+ const yOffset = clickState.y;
if (yOffset <= this.variantBandHeight) {
// Variant
- const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight
- const variantRow = Math.floor((yOffset - TOP_MARGIN) / (variantHeight + vGap))
+ const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
+ const variantRow = Math.floor((yOffset - TOP_MARGIN) / (variantHeight + vGap));
if ("COLLAPSED" !== this.displayMode) {
- featureList = featureList.filter(f => f.row === variantRow)
+ featureList = featureList.filter(f => f.row === variantRow);
}
} else if (this.sampleKeys) {
- const sampleY = yOffset - this.variantBandHeight
- const sampleRow = Math.floor(sampleY / this.sampleHeight)
+ const sampleY = yOffset - this.variantBandHeight;
+ const sampleRow = Math.floor(sampleY / this.sampleHeight);
if (sampleRow >= 0 && sampleRow < this.sampleKeys.length) {
- const variantRow = Math.floor((sampleY - sampleRow * this.sampleHeight) / callHeight)
- const variants = "COLLAPSED" === this.displayMode ? featureList : featureList.filter(f => f.row === variantRow)
- const sampleName = this.sampleKeys[sampleRow]
- const index = this.header.sampleNameMap.get(sampleName)
+ const variantRow = Math.floor((sampleY - sampleRow * this.sampleHeight) / callHeight);
+ const variants = "COLLAPSED" === this.displayMode ? featureList : featureList.filter(f => f.row === variantRow);
+ const sampleName = this.sampleKeys[sampleRow];
+ const index = this.header.sampleNameMap.get(sampleName);
featureList = variants.map(v => {
- const call = v.calls[index]
+ const call = v.calls[index];
// This is hacky, but it avoids expanding all calls in advance in case one is clicked, or
// alternatively storing backpoints to the variant for all calls.
- call.genotypeString = expandGenotype(call, v)
- return call
- })
+ call.genotypeString = expandGenotype(call, v);
+ return call;
+ });
}
}
- return featureList
+ return featureList;
}
-
/**
* Return "popup data" for feature @ genomic location. Data is an array of key-value pairs
*/
popupData(clickState, featureList) {
+ if (featureList === undefined) featureList = this.clickedFeatures(clickState);
+ const genomicLocation = clickState.genomicLocation;
+ const genomeID = this.browser.genome.id;
- if (featureList === undefined) featureList = this.clickedFeatures(clickState)
- const genomicLocation = clickState.genomicLocation
- const genomeID = this.browser.genome.id
-
- let popupData = []
+ let popupData = [];
for (let v of featureList) {
-
- const f = v._f || v // Get real variant from psuedo-variant, e.g. whole genome or SV mate
+ const f = v._f || v; // Get real variant from psuedo-variant, e.g. whole genome or SV mate
if (popupData.length > 0) {
- popupData.push({html: '
'})
+ popupData.push({ html: '
' });
}
if (typeof f.popupData === 'function') {
- const v = f.popupData(genomicLocation, genomeID)
- Array.prototype.push.apply(popupData, v)
+ const v = f.popupData(genomicLocation, genomeID);
+ Array.prototype.push.apply(popupData, v);
}
}
- return popupData
-
+ return popupData;
}
-
-// VariantTrack.prototype.contextMenuItemList = function (clickState) {
-//
-// const self = this;
-// const menuItems = [];
-//
-// const featureList = this.clickedFeatures(clickState);
-//
-// if (this.sampleColumns && featureList && featureList.length > 0) {
-//
-// featureList.forEach(function (variant) {
-//
-// if ('str' === variant.type) {
-//
-// menuItems.push({
-// label: 'Sort by allele length',
-// click: function () {
-// sortCallSetsByAlleleLength(self.sampleColumns, variant, self.sortDirection);
-// self.sortDirection = (self.sortDirection === "ASC") ? "DESC" : "ASC";
-// self.trackView.repaintViews();
-// }
-// });
-//
-// }
-//
-// });
-// }
-//
-//
-// function sortCallSetsByAlleleLength(callSets, variant, direction) {
-// var d = (direction === "DESC") ? 1 : -1;
-// Object.keys(callSets).forEach(function (property) {
-// callSets[property].sort(function (a, b) {
-// var aNan = isNaN(variant.calls[a.id].genotype[0]);
-// var bNan = isNaN(variant.calls[b.id].genotype[0]);
-// if (aNan && bNan) {
-// return 0;
-// } else if (aNan) {
-// return 1;
-// } else if (bNan) {
-// return -1;
-// } else {
-// var a0 = getAlleleString(variant.calls[a.id], variant, 0);
-// var a1 = getAlleleString(variant.calls[a.id], variant, 1);
-// var b0 = getAlleleString(variant.calls[b.id], variant, 0);
-// var b1 = getAlleleString(variant.calls[b.id], variant, 1);
-// var result = Math.max(b0.length, b1.length) - Math.max(a0.length, a1.length);
-// if (result === 0) {
-// result = Math.min(b0.length, b1.length) - Math.min(a0.length, a1.length);
-// }
-// return d * result;
-// }
-// });
-// });
-// }
-//
-//
-// return menuItems;
-//
-// };
-
menuItemList() {
-
- const menuItems = []
+ const menuItems = [];
// color-by INFO attribute
if (this.header.INFO) {
@@ -611,237 +516,220 @@ class VariantTrack extends TrackBase {
// For now stick to explicit info fields (well, exactly 1 for starters)
if (this.header.INFO) {
//const stringInfoKeys = Object.keys(this.header.INFO).filter(key => this.header.INFO[key].Type === "String")
- const colorByItems = this._colorByItems
- menuItems.push('
')
- const $e = $('