Skip to content

Commit

Permalink
Merge pull request #91 from Clinical-Genomics-Lund/add-cytogenetic-id…
Browse files Browse the repository at this point in the history
…eogram

Add cytogenetic ideogram
  • Loading branch information
mhkc authored Oct 18, 2021
2 parents 8eb6785 + e196b7a commit 15d8eb8
Show file tree
Hide file tree
Showing 28 changed files with 21,464 additions and 4,587 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[*.{html,js,py}]
indent_style = space

[*.{js,html}]
indent_size = 2
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# other
*~
\#*
tags
coverage
*.aed

# python
*.pyc
.mypy_cache
Expand All @@ -9,6 +14,8 @@ utils/Homo_sapiens.GRCh38.99.gtf
utils/MANE.GRCh38.v0.8.summary.txt
utils/hg38_annotations/
venv/
*.egg-info
.eggs

# node
node_modules
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ About changelog [here](https://keepachangelog.com/en/1.0.0/)
## [x.x.x]
### Added
- Added seperate error page for when accessing a sample not in the database
- load chromosome-info stores centromere position and cyto band info
- Display viewed chromosome region in cytogenetic ideogram figure
### Changed
### Fixed

## [2.0.1]
### Added
### Changed
- Do not warn when using default configuration
- Renamed cli gens load chrom-sizes to gens load chromosome-info
- Removed gens load chromosome-info dependancy on additional files
### Fixed
- Missing tbi files now returns 404 status code
- Fixed sort order of samples table
Expand Down
21 changes: 17 additions & 4 deletions assets/css/gens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -278,21 +278,33 @@ html, body {
}
}

#interactive-container {
#chromosome-title {
display: grid;
grid-row: 1;
grid-column: 1;
}

#cytogenetic-ideogram {
display: grid;
grid-row: 2;
grid-column: 1;
}

#interactive-container {
display: grid;
grid-row: 3;
grid-column: 1;

#interactive-static {
z-index: 1;
pointer-events: none;
grid-row: 2;
grid-row: 4;
grid-column: 1;
}

#interactive-content {
z-index: 1;
grid-row: 2;
grid-row: 4;
grid-column: 1;
}

Expand Down Expand Up @@ -327,6 +339,7 @@ html, body {
.marker {
background-color: $marker-color;
pointer-events:none;
position: relative;
}

.info-container[data-state=nodata] {
Expand Down Expand Up @@ -480,7 +493,7 @@ html, body {
flex: 1;
}
.spinner {
border-top: 3px solid rgba($black, 0.5);
border-top: 3px solid rgba($menubar-bg-color, 0.5);
border-right: 3px solid transparent;
border-radius: 50%;
width: 30px;
Expand Down
26 changes: 15 additions & 11 deletions assets/js/draw/shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function drawLine ({ ctx, x, y, x2, y2, lineWidth = 1, color = 'black' })
// Draws a box from top left corner with a top and bottom margin
export function drawRect ({
ctx, x, y, width, height, lineWidth, color = null,
fillColor = null, open = false
fillColor = null, open = false, debug = false
}) {
x = Math.floor(x) + 0.5
y = Math.floor(y) + 0.5
Expand All @@ -74,22 +74,26 @@ export function drawRect ({
if (color !== null) ctx.strokeStyle = color
ctx.lineWidth = lineWidth

// define path to draw
const path = new Path2D()

// Draw box without left part, to allow stacking boxes
// horizontally without getting double lines between them.
if (open === true) {
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineTo(x + width, y)
ctx.lineTo(x + width, y + height)
ctx.lineTo(x, y + height)
ctx.stroke()
path.moveTo(x, y)
path.lineTo(x + width, y)
path.lineTo(x + width, y + height)
path.lineTo(x, y + height)
// Draw normal 4-sided box
} else if (fillColor !== null) {
ctx.fillStyle = fillColor
ctx.fillRect(x, y, width, height)
} else {
ctx.strokeRect(x, y, width, height)
path.rect(x, y, width, height)
}
ctx.stroke(path)
if (fillColor !== null) {
ctx.fillStyle = fillColor
ctx.fill(path)
}
return path
}

// Draw an arrow in desired direction
Expand Down
24 changes: 17 additions & 7 deletions assets/js/gens.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import { InteractiveCanvas } from './interactive.js'
import { OverviewCanvas } from './overview.js'
import { CHROMOSOMES, VariantTrack, AnnotationTrack, TranscriptTrack } from './track.js'
import { VariantTrack, AnnotationTrack, TranscriptTrack, CytogeneticIdeogram } from './track.js'
export {
setupDrawEventManager, drawTrack, previousChromosome, nextChromosome,
panTracks, zoomIn, zoomOut, parseRegionDesignation, queryRegionOrGene
} from './navigation.js'

export function initCanvases ({ sampleName, genomeBuild, hgFileDir, uiColors, selectedVariant, annotationFile }) {
export function initCanvases({ sampleName, genomeBuild, hgFileDir, uiColors, selectedVariant, annotationFile }) {
// initialize and return the different canvases
// WEBGL values
const near = 0.1
Expand All @@ -24,17 +24,27 @@ export function initCanvases ({ sampleName, genomeBuild, hgFileDir, uiColors, se
const ac = new AnnotationTrack(ic.x, ic.plotWidth, near, far, genomeBuild, annotationFile)
// Initiate and draw overview canvas
const oc = new OverviewCanvas(ic.x, ic.plotWidth, lineMargin, near, far, sampleName, genomeBuild, hgFileDir)
// Draw cytogenetic ideogram figure
const cg = new CytogeneticIdeogram({
targetId: 'cytogenetic-ideogram',
genomeBuild,
x: ic.x,
y: ic.y,
width: ic.plotWidth,
height: 40
})
return {
ic: ic,
vc: vc,
tc: tc,
ac: ac,
oc: oc
oc: oc,
cg: cg,
}
}

// Make hard link and copy link to clipboard
export function copyPermalink (genomeBuild, region) {
export function copyPermalink(genomeBuild, region) {
// create element and add url to it
const tempElement = document.createElement('input')
const loc = window.location
Expand All @@ -47,19 +57,19 @@ export function copyPermalink (genomeBuild, region) {
}

// Reloads page to printable size
export function loadPrintPage (region) {
export function loadPrintPage(region) {
let location = window.location.href.replace(/region=.*&/, `region=${region}&`)
location = location.includes('?') ? `${location}&print_page=true` : `${location}?print_page=true`
window.location.replace(location)
}

// Show print prompt and reloads page after print
export function printPage () {
export function printPage() {
document.querySelector('.no-print').toggleAttribute('hidden')
window.addEventListener('afterprint', () => {
window.location.replace(window.location.href.replace('&print_page=true', ''))
}, { once: true })
print()
}

export { CHROMOSOMES } from './track.js'
export { CHROMOSOMES, setupGenericEventManager } from './track.js'
63 changes: 44 additions & 19 deletions assets/js/interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export class InteractiveCanvas extends BaseScatterTrack {
this.plotHeight = 180 // Height of one plot
this.x = document.body.clientWidth / 2 - this.plotWidth / 2 // X-position for first plot
this.y = 10 + 2 * lineMargin + this.titleMargin // Y-position for first plot
this.titleYPos = null
this.titleBbox = null
this.canvasHeight = 2 + this.y + 2 * (this.leftRightPadding + this.plotHeight) // Height for whole canvas

// setup objects for tracking the positions of draw and content canvases
Expand Down Expand Up @@ -64,7 +66,7 @@ export class InteractiveCanvas extends BaseScatterTrack {
// Initialize marker div
this.markerElem = document.getElementById('interactive-marker')
this.markerElem.style.height = `${this.plotHeight * 2}px`
this.markerElem.style.top = `${this.y + 81}px`
this.markerElem.style.top = `${this.y + 131}px`

// State values
this.allowDraw = true
Expand All @@ -78,6 +80,17 @@ export class InteractiveCanvas extends BaseScatterTrack {
this.scale = this.calcScale()

// Setup listeners
// update chromosome title event
this.contentCanvas.addEventListener('update-title', event => {
console.log(`interactive got an ${event.type} event`)
const len = event.detail.bands.length
if (len > 0) {
const bandIds = len === 1 ? event.detail.bands[0].id : `${event.detail.bands[0].id}-${event.detail.bands[len-1].id}`
this.drawCanvas.getContext('2d').clearRect(this.titleBbox.x, this.titleBbox.y, this.titleBbox.width, this.titleBbox.height)
this.titleBbox = this.drawTitle(`Chromosome ${event.detail.chrom}; ${bandIds}`)
this.blitChromName({textPosition: this.titleBbox})
}
})
// redraw events
this.contentCanvas.parentElement.addEventListener('draw', event => {
console.log('interactive got draw event')
Expand Down Expand Up @@ -154,12 +167,14 @@ export class InteractiveCanvas extends BaseScatterTrack {
chrom: this.chromosome,
start: start,
end: end,
force: true
exclude: ['cytogenetic-ideogram'],
force: true,
drawTitle: false
})
}
} else if (this.drag) {
// reload window when stop draging
drawTrack({ ...readInputField(), force: true, displayLoading: false })
drawTrack({ ...readInputField(), force: true, displayLoading: false, drawTitle: false })
}
// reset dragging behaviour
this.markingRegion = false
Expand Down Expand Up @@ -204,7 +219,7 @@ export class InteractiveCanvas extends BaseScatterTrack {
}

// Draw values for interactive canvas
async drawInteractiveContent ({ chrom, start, end, displayLoading = true }) {
async drawInteractiveContent ({ chrom, start, end, displayLoading = true, drawTitle = true }) {
console.log('drawing interactive canvas', chrom, start, end)
if (displayLoading) {
this.loadingDiv.style.display = 'block'
Expand Down Expand Up @@ -292,20 +307,18 @@ export class InteractiveCanvas extends BaseScatterTrack {
ctx, data: result.data, color: this.log2.color
})

// Draw chromosome title on the content canvas as a blitting
// work around
const textYPos = result.y_pos - this.titleMargin
const textBbox = drawText({
ctx,
x: document.body.clientWidth / 2,
y: textYPos,
text: 'Chromosome ' + result.chrom,
fontProp: 'bold 15',
align: 'center'
})
// Transfer image to visible canvas
this.blitInteractiveCanvas({ start, end })
this.blitChromName(textBbox)
// Draw chromosome title on the content canvas as a blitting
// work around
this.titleYPos = result.y_pos - this.titleMargin
if ( drawTitle ) {
this.titleBbox !== null && this.blitChromName(
{textPosition: this.titleBbox, clearOnly: true
})
this.titleBbox = this.drawTitle(`Chromosome ${result.chrom}`)
this.blitChromName({textPosition: this.titleBbox})
}

return result
}).then((result) => {
Expand All @@ -324,6 +337,18 @@ export class InteractiveCanvas extends BaseScatterTrack {
})
}

drawTitle(title) {
const ctx = this.drawCanvas.getContext('2d')
return drawText({
ctx,
x: Math.round(document.body.clientWidth / 2),
y: this.titleYPos,
text: title,
fontProp: 'bold 15',
align: 'center'
})
}

calcScale () {
return this.plotWidth / (this.onscreenPosition.end - this.onscreenPosition.start)
}
Expand All @@ -340,7 +365,7 @@ export class InteractiveCanvas extends BaseScatterTrack {
this.markerElem.style.width = '0px'
}

blitChromName (textPosition) {
blitChromName ({textPosition, clearOnly=false}) {
const ctx = this.contentCanvas.getContext('2d')
const padding = 20
// clear area on contentCanvas
Expand All @@ -351,7 +376,7 @@ export class InteractiveCanvas extends BaseScatterTrack {
textPosition.height
)
// transfer from draw canvas
ctx.drawImage(
!clearOnly && ctx.drawImage(
this.drawCanvas, // source
textPosition.x - padding / 2, // sX
textPosition.y, // sY
Expand Down Expand Up @@ -412,7 +437,7 @@ export class InteractiveCanvas extends BaseScatterTrack {
this.blitInteractiveCanvas({ start: region.start, end: region.end, updateCoord: false })
drawTrack({
...region,
exclude: [`${this.contentCanvas.parentElement.id}`],
exclude: [`${this.contentCanvas.parentElement.id}`, 'cytogenetic-ideogram'],
displayLoading: false
})
}
Expand Down
Loading

0 comments on commit 15d8eb8

Please sign in to comment.