Skip to content

Commit

Permalink
Merge pull request #293 from igvteam/juicebox_panel_tabs
Browse files Browse the repository at this point in the history
Juicebox - Tabbed Maps
  • Loading branch information
turner authored Sep 6, 2024
2 parents 050c332 + 8211665 commit 2ba4d28
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 187 deletions.
185 changes: 102 additions & 83 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<!-- Spectrum colorpicker JS -->
<script src="https://cdn.jsdelivr.net/npm/spectrum-colorpicker2@2.0.0/dist/spectrum.min.js"></script>

<!-- Dropbox Chooser API - supports aidenlab.org and netlify.app -->
<!-- Dropbox Chooser API - sw_aiden_lab - supports aidenlab.org and netlify.app -->
<script src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="dmf9qrwim29nbad"></script>

<!-- Datatables JS -->
Expand Down Expand Up @@ -108,7 +108,6 @@

<!-- Spacewalk app entrypoint -->
<script type="module" src="./js/app.js"></script>

</head>
<body>

Expand Down Expand Up @@ -498,94 +497,109 @@

<!-- juicebox panel -->
<div id="spacewalk_juicebox_panel" class="card">
<ul class="list-group list-group-flush">
<!-- drag handle-->
<li class="list-group-item">
<div class="spacewalk_card_drag_container">
<i class="fas fa-square-full"></i>
<div class="dropdown">
<a id="hic-contact-map-dropdown" class="dropdown-toggle" data-bs-toggle="dropdown">
Juicebox File
</a>
<ul class="dropdown-menu">
<!-- Live Contact Frequency Map -->
<li>
<a id="hic-live-contact-frequency-map-button" class="dropdown-item" href="#" role="button">
Load Live Contact Frequency Map ...
</a>
</li>

<!-- Juicebox Archive Map -->
<li>
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#hic-contact-map-modal">
Load Juicebox Archive Maps ...
</a>
</li>

<!-- ENCODE Maps -->
<li>
<button class="dropdown-item" id="hic-encode-hosted-contact-map-presentation-button" type="button" data-bs-toggle="modal" data-bs-target="#hic-encode-hosted-contact-map-modal">
Load ENCODE Maps ...
</button>
</li>

<!-- Local Map File -->
<li>
<label class="dropdown-item btn btn-default btn-file">
<div class="igv-app-dropdown-item-cloud-storage">
<div>
Load Local Map File ...

<div class="card-header">

<ul class="list-group list-group-flush">

<!-- drag handle-->
<li class="list-group-item">
<div class="spacewalk_card_drag_container">
<i class="fas fa-square-full"></i>
<div class="dropdown">
<a id="hic-contact-map-dropdown" class="dropdown-toggle" data-bs-toggle="dropdown">
Juicebox File
</a>
<ul class="dropdown-menu">
<!-- Live Contact Frequency Map -->
<li>
<a id="hic-live-contact-frequency-map-button" class="dropdown-item" href="#" role="button">
Load Live Contact Frequency Map ...
</a>
</li>

<!-- Juicebox Archive Map -->
<li>
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#hic-contact-map-modal">
Load Juicebox Archive Maps ...
</a>
</li>

<!-- ENCODE Maps -->
<li>
<button class="dropdown-item" id="hic-encode-hosted-contact-map-presentation-button" type="button" data-bs-toggle="modal" data-bs-target="#hic-encode-hosted-contact-map-modal">
Load ENCODE Maps ...
</button>
</li>

<!-- Local Map File -->
<li>
<label class="dropdown-item btn btn-default btn-file">
<div class="igv-app-dropdown-item-cloud-storage">
<div>
Load Local Map File ...
</div>
<div>
<input name="contact-map" type="file" style="display: none;">
</div>
</div>
<div>
<input name="contact-map" type="file" style="display: none;">
</label>
</li>

<!-- Dropbox -->
<li>
<div class="dropdown-item">
<div id="hic-contact-map-dropdown-dropbox-button" class="igv-app-dropdown-item-cloud-storage">
<div>Load Dropbox Map File ...</div>
<div>
<img src="img/dropbox-dropdown-menu-item.png" width="18" height="18">
</div>
</div>
</div>
</label>
</li>

<!-- Dropbox -->
<li>
<div class="dropdown-item">
<div id="hic-contact-map-dropdown-dropbox-button" class="igv-app-dropdown-item-cloud-storage">
<div>Load Dropbox Map File ...</div>
<div>
<img src="img/dropbox-dropdown-menu-item.png" width="18" height="18">
</li>

<!-- Google Drive -->
<li>
<div class="dropdown-item">
<div id="hic-contact-map-dropdown-google-drive-button" class="igv-app-dropdown-item-cloud-storage">
<div>Load Google Drive Map File ...</div>
<div><img src="img/googledrive-dropdown-menu-item.png" width="18" height="18"></div>
</div>
</div>
</div>
</li>

<!-- Google Drive -->
<li>
<div class="dropdown-item">
<div id="hic-contact-map-dropdown-google-drive-button" class="igv-app-dropdown-item-cloud-storage">
<div>Load Google Drive Map File ...</div>
<div><img src="img/googledrive-dropdown-menu-item.png" width="18" height="18"></div>
</div>
</div>
</li>

<!-- URL -->
<li>
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#hic-load-url-modal">
Load Map URL ...
</a>
</li>
</ul>
</li>

<!-- URL -->
<li>
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#hic-load-url-modal">
Load Map URL ...
</a>
</li>
</ul>
</div>
<i class="fas fa-times-circle" data-target="spacewalk_ui_manager_ui_controls_juicebox"></i>
</div>
<i class="fas fa-times-circle" data-target="spacewalk_ui_manager_ui_controls_juicebox"></i>
</div>
</li>
</li>

<!-- live contact map threshold widget -->
<li id="hic-live-contact-frequency-map-threshold-widget" class="list-group-item py-1 ps-1">
<div class="input-group input-group-sm">
<div class="input-group-text">Threshold</div>
<input id="spacewalk_contact_frequency_map_adjustment_select_input" type="text" class="form-control text-center">
<button id="spacewalk_contact_frequency_map__button" class="btn btn-secondary" type="button">Enter</button>
</div>
</li>
</ul>
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button id="spacewalk-juicebox-panel-hic-map-tab" class="nav-link active" data-bs-toggle="tab" data-bs-target="" type="button" role="tab">Hi-C Map</button>
</li>
<li class="nav-item" role="presentation">
<button id="spacewalk-juicebox-panel-live-map-tab" class="nav-link" data-bs-toggle="tab" data-bs-target="" type="button" role="tab">Live Map</button>
</li>
</ul>

<!-- live contact map threshold widget -->
<li id="hic-live-contact-frequency-map-threshold-widget" class="list-group-item py-1 ps-1">
<div class="input-group input-group-sm">
<div class="input-group-text">Threshold</div>
<input id="spacewalk_contact_frequency_map_adjustment_select_input" type="text" class="form-control text-center">
<button id="spacewalk_contact_frequency_map__button" class="btn btn-secondary" type="button">Enter</button>
</div>
</li>
</ul>

</div>

<div class="card-body p-0">
<!-- juicebox browser container -->
Expand Down Expand Up @@ -658,7 +672,9 @@

<!-- distance-map panel -->
<div id="spacewalk_distance_map_panel" class="card">

<div class="card-header">

<!-- drag handle -->
<div class="spacewalk_card_drag_container">
<i class="fas fa-square-full"></i>
Expand All @@ -678,10 +694,13 @@
<a class="nav-link" data-bs-toggle="tab" href="#spacewalk_distance_map_canvas_ensemble">Ensemble</a>
</li>
</ul>

</div>

<div id="spacewalk_distance_map_panel_body" class="card-body p-0">

<div id="spacewalk_distance_map_panel_container" class="tab-content">

<div class="spacewalk-spinner-container d-flex align-items-center justify-content-center">
<div id="spacewalk-distance-map-spinner" class="spinner-border text-secondary" style="display:none; width: 5rem; height: 5rem;"></div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ async function createButtonsPanelsModals(container, igvSessionURL, juiceboxSessi

createSpacewalkFileLoaders(spacewalkFileLoadConfig)

const initializeDropbox = () => false
// const initializeDropbox = () => false
const initializeDropbox = () => true

const trackMenuHandler = configList => {

Expand Down Expand Up @@ -280,7 +281,6 @@ async function createButtonsPanelsModals(container, igvSessionURL, juiceboxSessi
await juiceboxPanel.initialize(document.querySelector('#spacewalk_juicebox_root_container'), spacewalkConfig.juiceboxConfig)

liveContactMapService = new LiveContactMapService(distanceThreshold)
liveContactMapService.initialize()

const $dropdownButton = $('#spacewalk-contact-map-dropdown')
const $dropdowns = $dropdownButton.parent()
Expand Down
68 changes: 48 additions & 20 deletions js/juicebox/juiceboxPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ class JuiceboxPanel extends Panel {

let session

// juiceboxClassAdditions()

if (config.browsers) {
session = Object.assign({ queryParametersSupported: false }, config)
} else {
Expand All @@ -67,22 +65,30 @@ class JuiceboxPanel extends Panel {
AlertSingleton.present(`Error initializing Juicebox ${ error.message }`)
}

this.configureTabs()
this.configureMouseHandlers()

hic.EventBus.globalBus.subscribe('MapLoad', event => {
this.browser.eventBus.subscribe('MapLoad', async event => {

// hic-live-contact-frequency-map-threshold-widget
const { dataset } = event.data
const thresholdWidget = document.querySelector('#hic-live-contact-frequency-map-threshold-widget')
thresholdWidget.style.display = undefined === dataset.isLiveContactMapDataSet ? 'none' : 'block'

if (undefined === ensembleManager.locus) {
const [ ab, c ] = config.locus.split('-')
const [ a, b ] = ab.split(':')
this.goto({ chr:a, start: parseInt(b), end: parseInt(c) })
} else {
const { chr, genomicStart, genomicEnd } = ensembleManager.locus
this.goto({ chr, start: genomicStart, end: genomicEnd })
// const { dataset } = event.data
// const thresholdWidget = document.querySelector('#hic-live-contact-frequency-map-threshold-widget')
// thresholdWidget.style.display = dataset === this.browser.liveContactMapDataSet ? 'block' : 'none'
//
// if (undefined === ensembleManager.locus) {
// const [ ab, c ] = config.locus.split('-')
// const [ a, b ] = ab.split(':')
// await this.goto({ chr:a, start: parseInt(b), end: parseInt(c) })
// } else {
// const { chr, genomicStart, genomicEnd } = ensembleManager.locus
// await this.goto({ chr, start: genomicStart, end: genomicEnd })
// }

const activeTabButton = this.container.querySelector('button.nav-link.active')
if ('spacewalk-juicebox-panel-hic-map-tab' === activeTabButton.id) {
this.browser.contactMatrixView.assessPanelTabSelection(false)
} else if ('spacewalk-juicebox-panel-live-map-tab' === activeTabButton.id) {
this.browser.contactMatrixView.assessPanelTabSelection(true)
}

})
Expand Down Expand Up @@ -125,6 +131,32 @@ class JuiceboxPanel extends Panel {
}
}

configureTabs() {

this.browser.contactMatrixView.assessPanelTabSelection(false)

const hicMapTab = document.getElementById('spacewalk-juicebox-panel-hic-map-tab');
const liveMapTab = document.getElementById('spacewalk-juicebox-panel-live-map-tab');

// Assign data-bs-target to point to the respective tab content elements
hicMapTab.setAttribute("data-bs-target", `#${this.browser.id}-contact-map-canvas-container`);
liveMapTab.setAttribute("data-bs-target", `#${this.browser.id}-live-contact-map-canvas-container`);

const tabs = this.container.querySelectorAll('button[data-bs-toggle="tab"]')

for (const tab of tabs) {
tab.addEventListener('show.bs.tab', event => {
if (hicMapTab.id === event.target.id) {
this.browser.contactMatrixView.assessPanelTabSelection(false)
} else if (liveMapTab.id === event.target.id) {
this.browser.contactMatrixView.assessPanelTabSelection(true)
}
console.log(`Juicebox panel: ${ event.target.id } tab selection`)
})
}

}

configureMouseHandlers() {

this.browser.eventBus.subscribe('DidHideCrosshairs', ribbon)
Expand Down Expand Up @@ -184,10 +216,6 @@ class JuiceboxPanel extends Panel {

}

blurb() {
return `${ this.browser.$contactMaplabel.text() }`
}

isContactMapLoaded() {
return (this.browser && this.browser.dataset)
}
Expand All @@ -197,8 +225,8 @@ class JuiceboxPanel extends Panel {
}

async colorPickerHandler(data) {
if (liveContactMapService.liveContactMapDataSet && this.browser.contactMatrixView.doRenderLiveContactMap()) {
console.log(`color picker picked ${ data }`)
if (liveContactMapService.liveContactMapDataSet) {
console.log(`JuiceboxPanel - colorPicker(${ data }). renderWithLiveContactFrequencyData()`)
await this.renderWithLiveContactFrequencyData(liveContactMapService.hicState, liveContactMapService.liveContactMapDataSet, liveContactMapService.contactFrequencies, liveContactMapService.ensembleContactFrequencyArray, ensembleManager.getLiveMapTraceLength())
}
}
Expand Down
21 changes: 15 additions & 6 deletions js/juicebox/liveContactMapDataSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class LiveContactMapDataSet {

this.genome = genome

this.chromosomes = getDatasetChromosomeList(genome.chromosomes)
this.chromosomes = genome.chromosomes

this.averageCount = averageCount

Expand All @@ -33,14 +33,23 @@ class LiveContactMapDataSet {

}

set chromosomes(genomeChromosomeMap) {
const hash = Object.fromEntries(genomeChromosomeMap)
this._chromosomes = Object.values(hash).map(({ index, bpLength, size, name }) => { return { index, name, size, bpLength }})

// reorganize array to be consistent with Juicebox layout
const all = this._chromosomes.pop()
this._chromosomes.unshift(all)

}

get chromosomes() {
return this._chromosomes.slice()
}

isWholeGenome(ignore) {
return false
}
}

function getDatasetChromosomeList(genomeChromosomeMap) {
const hash = Object.fromEntries(genomeChromosomeMap)
return Object.values(hash).map(({ index, bpLength, size, name }) => { return { index, name, size, bpLength }})
}

export default LiveContactMapDataSet
Loading

0 comments on commit 2ba4d28

Please sign in to comment.