gramene-search 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +337 -87
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -7447,12 +7447,13 @@ const $047461923b1badda$export$964d88edb00bbcaa = (suggestion)=>{
|
|
|
7447
7447
|
const $64fad37f770d2bfe$var$genomeZone = (0, $gXNCa$tbrowse.createGenomeZone)({
|
|
7448
7448
|
id: 'genome'
|
|
7449
7449
|
});
|
|
7450
|
-
|
|
7450
|
+
// The genome (gene-structure) zone is gated behind the site-config flag
|
|
7451
|
+
// `enable_tbrowse_genome_zone` (defaults to false) — see getTbrowseZones().
|
|
7452
|
+
const $64fad37f770d2bfe$var$TBROWSE_BASE_ZONES = [
|
|
7451
7453
|
(0, $gXNCa$tbrowse.treeZone),
|
|
7452
7454
|
(0, $gXNCa$tbrowse.labelsZone),
|
|
7453
7455
|
(0, $gXNCa$tbrowse.msaZone),
|
|
7454
|
-
(0, $gXNCa$tbrowse.neighborhoodZone)
|
|
7455
|
-
$64fad37f770d2bfe$var$genomeZone
|
|
7456
|
+
(0, $gXNCa$tbrowse.neighborhoodZone)
|
|
7456
7457
|
];
|
|
7457
7458
|
class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$react))).Component {
|
|
7458
7459
|
constructor(props){
|
|
@@ -7485,7 +7486,18 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
|
|
|
7485
7486
|
return slice && slice.homology || {};
|
|
7486
7487
|
}
|
|
7487
7488
|
getViewer() {
|
|
7488
|
-
return this.getHomologySlice().viewer || '
|
|
7489
|
+
return this.getHomologySlice().viewer || 'tbrowse';
|
|
7490
|
+
}
|
|
7491
|
+
// The genome (gene-structure) zone is opt-in per site via
|
|
7492
|
+
// `enable_tbrowse_genome_zone` (defaults to false).
|
|
7493
|
+
isGenomeZoneEnabled() {
|
|
7494
|
+
return !!(this.props.configuration && this.props.configuration.enable_tbrowse_genome_zone);
|
|
7495
|
+
}
|
|
7496
|
+
getTbrowseZones() {
|
|
7497
|
+
return this.isGenomeZoneEnabled() ? [
|
|
7498
|
+
...$64fad37f770d2bfe$var$TBROWSE_BASE_ZONES,
|
|
7499
|
+
$64fad37f770d2bfe$var$genomeZone
|
|
7500
|
+
] : $64fad37f770d2bfe$var$TBROWSE_BASE_ZONES;
|
|
7489
7501
|
}
|
|
7490
7502
|
getHeight() {
|
|
7491
7503
|
const h = this.getHomologySlice().height;
|
|
@@ -7542,7 +7554,7 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
|
|
|
7542
7554
|
// logic — zones default to visible unless their definition opts out
|
|
7543
7555
|
// (e.g. neighborhood and genome opt out so they only appear once
|
|
7544
7556
|
// their async data lands; tbrowse's Layout auto-flips them on then).
|
|
7545
|
-
zones:
|
|
7557
|
+
zones: this.getTbrowseZones().map((z)=>({
|
|
7546
7558
|
id: z.id,
|
|
7547
7559
|
width: z.defaultWidth,
|
|
7548
7560
|
visible: z.defaultVisible ?? true
|
|
@@ -7583,7 +7595,8 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
|
|
|
7583
7595
|
]);
|
|
7584
7596
|
}
|
|
7585
7597
|
this.fetchNeighborhood(treeId);
|
|
7586
|
-
|
|
7598
|
+
// Only pay for gene-structure data when the genome zone is actually enabled.
|
|
7599
|
+
if (this.isGenomeZoneEnabled()) this.fetchGeneStructures(treeId, this._tbrowseData.tree);
|
|
7587
7600
|
}
|
|
7588
7601
|
fetchNeighborhood(treeId) {
|
|
7589
7602
|
if (this._neighborhoodFetchedFor === treeId) return;
|
|
@@ -7754,7 +7767,7 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
|
|
|
7754
7767
|
exonJunctions: this._tbrowseData.exonJunctions,
|
|
7755
7768
|
neighborhood: neighborhood,
|
|
7756
7769
|
geneStructures: geneStructures,
|
|
7757
|
-
zones:
|
|
7770
|
+
zones: this.getTbrowseZones(),
|
|
7758
7771
|
nodeOfInterest: this.gene._id,
|
|
7759
7772
|
viewState: tbrowseVS,
|
|
7760
7773
|
onViewStateChange: (next)=>this.setTbrowseViewState(next),
|
|
@@ -7791,8 +7804,8 @@ class $64fad37f770d2bfe$var$Homology extends (0, ($parcel$interopDefault($gXNCa$
|
|
|
7791
7804
|
margin: '8px 0'
|
|
7792
7805
|
},
|
|
7793
7806
|
children: [
|
|
7794
|
-
btn('
|
|
7795
|
-
btn('
|
|
7807
|
+
btn('tbrowse', 'TBrowse'),
|
|
7808
|
+
btn('treevis', 'TreeVis')
|
|
7796
7809
|
]
|
|
7797
7810
|
});
|
|
7798
7811
|
}
|
|
@@ -16885,6 +16898,14 @@ var $597fe213417ee6ca$export$2e2bcd8739ae039 = (0, $gXNCa$reduxbundlerreact.conn
|
|
|
16885
16898
|
// data.hostData.bins = { genomesByTaxon: { [taxonId]: genome }, maxScore }
|
|
16886
16899
|
// where `genome` is a gramene-bins-client genome (fullGenomeSize,
|
|
16887
16900
|
// _regionsArray, region.bin(i)/binCount()/size/name, bin.results.count).
|
|
16901
|
+
//
|
|
16902
|
+
// Pan/zoom: a single shared horizontal transform { scale, leftFrac } (fraction
|
|
16903
|
+
// space, so it's width-independent and aligns every genome to the same relative
|
|
16904
|
+
// window) lives in the ephemeral binsUI store. The header toggles between two
|
|
16905
|
+
// interaction modes: 'select' (drag selects a region to count/filter genes,
|
|
16906
|
+
// the original gesture) and 'panzoom' (drag pans, wheel zooms toward the
|
|
16907
|
+
// cursor). All hit-testing/coordinates are in genome-fraction [0,1] so
|
|
16908
|
+
// hovers/selections stay anchored to the genome as you pan and zoom.
|
|
16888
16909
|
|
|
16889
16910
|
|
|
16890
16911
|
|
|
@@ -16967,28 +16988,66 @@ function $bfd29d54a0f0e853$var$updateScore(currentScore, baseCount, binScore, bi
|
|
|
16967
16988
|
if (typeof currentScore === 'number') return (currentScore * baseCount + binScore * binBasesUsed) / (binBasesUsed + baseCount);
|
|
16968
16989
|
return binScore;
|
|
16969
16990
|
}
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16991
|
+
const $bfd29d54a0f0e853$var$clamp = (v, lo, hi)=>Math.max(lo, Math.min(hi, v));
|
|
16992
|
+
const $bfd29d54a0f0e853$var$MAX_SCALE = 1000; // zoom far enough to isolate a single bin
|
|
16993
|
+
// Locate the region/bin cursor at a target base offset, so a zoomed draw can
|
|
16994
|
+
// start partway into the genome without iterating skipped pixels. Returns null
|
|
16995
|
+
// past the end of the genome.
|
|
16996
|
+
function $bfd29d54a0f0e853$var$seekCursor(regions, targetBase) {
|
|
16997
|
+
let acc = 0;
|
|
16998
|
+
for(let regionIdx = 0; regionIdx < regions.length; regionIdx++){
|
|
16999
|
+
const region = regions[regionIdx];
|
|
17000
|
+
const n = region.binCount();
|
|
17001
|
+
for(let binIdx = 0; binIdx < n; binIdx++){
|
|
17002
|
+
const bin = region.bin(binIdx);
|
|
17003
|
+
const size = bin.end - bin.start + 1;
|
|
17004
|
+
if (acc + size > targetBase) return {
|
|
17005
|
+
regionIdx: regionIdx,
|
|
17006
|
+
binIdx: binIdx,
|
|
17007
|
+
basesInBinUsedAlready: Math.max(0, targetBase - acc)
|
|
17008
|
+
};
|
|
17009
|
+
acc += size;
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
17012
|
+
return null;
|
|
17013
|
+
}
|
|
17014
|
+
// Draw one genome's distribution into the visible [0, widthPx) strip at
|
|
17015
|
+
// vertical [y, y+height), under the shared { scale, leftFrac } transform. Only
|
|
17016
|
+
// the visible pixels are drawn (the cursor is fast-forwarded to the window's
|
|
17017
|
+
// left edge); consecutive equal-colour columns are batched into one fillRect,
|
|
17018
|
+
// which makes zoomed-in draws (where each bin spans many px) cheap. Ported from
|
|
17019
|
+
// drawGenome() in gramene-search-vis, generalised for pan/zoom.
|
|
17020
|
+
function $bfd29d54a0f0e853$var$drawGenomeRow(ctx, genome, y, widthPx, height, maxScore, scale, leftFrac) {
|
|
16973
17021
|
const regions = genome && genome._regionsArray;
|
|
16974
|
-
|
|
16975
|
-
|
|
17022
|
+
const full = genome && genome.fullGenomeSize;
|
|
17023
|
+
if (!regions || regions.length === 0 || !full) return;
|
|
17024
|
+
const virtualWidth = widthPx * scale; // full genome spans this many px when zoomed
|
|
17025
|
+
const basesPerPx = full / virtualWidth;
|
|
16976
17026
|
if (!(basesPerPx > 0)) return;
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
let regionIdx =
|
|
17027
|
+
const cursor = $bfd29d54a0f0e853$var$seekCursor(regions, leftFrac * full);
|
|
17028
|
+
if (!cursor) return;
|
|
17029
|
+
let { regionIdx: regionIdx, binIdx: binIdx, basesInBinUsedAlready: basesInBinUsedAlready } = cursor;
|
|
16980
17030
|
let region = regions[regionIdx];
|
|
16981
17031
|
let regionUnanchored = region.name === 'UNANCHORED';
|
|
16982
|
-
|
|
17032
|
+
let runColor = null;
|
|
17033
|
+
let runStart = 0;
|
|
17034
|
+
const flush = (endExclusive)=>{
|
|
17035
|
+
if (runColor !== null && endExclusive > runStart) {
|
|
17036
|
+
ctx.fillStyle = runColor;
|
|
17037
|
+
ctx.fillRect(runStart, y, endExclusive - runStart, height);
|
|
17038
|
+
}
|
|
17039
|
+
};
|
|
17040
|
+
let px = 0;
|
|
17041
|
+
for(; px < widthPx; px++){
|
|
16983
17042
|
let baseCount = 0;
|
|
16984
17043
|
let score;
|
|
16985
|
-
let
|
|
17044
|
+
let ended = false;
|
|
16986
17045
|
while(baseCount < basesPerPx){
|
|
16987
17046
|
const basesNeededByThisPixel = basesPerPx - baseCount;
|
|
16988
17047
|
const bin = region.bin(binIdx);
|
|
16989
17048
|
const binSize = bin.end - bin.start + 1;
|
|
16990
17049
|
const binScore = maxScore ? (bin.results ? bin.results.count : 0) / maxScore : 0;
|
|
16991
|
-
basesAvailableInBin = binSize - basesInBinUsedAlready;
|
|
17050
|
+
const basesAvailableInBin = binSize - basesInBinUsedAlready;
|
|
16992
17051
|
let binBasesUsed;
|
|
16993
17052
|
if (basesAvailableInBin <= basesNeededByThisPixel) {
|
|
16994
17053
|
binIdx++;
|
|
@@ -17003,14 +17062,30 @@ function $bfd29d54a0f0e853$var$drawGenomeRow(ctx, genome, x, y, width, height, m
|
|
|
17003
17062
|
if (binIdx === region.binCount()) {
|
|
17004
17063
|
binIdx = 0;
|
|
17005
17064
|
regionIdx++;
|
|
17006
|
-
if (regionIdx === regions.length)
|
|
17065
|
+
if (regionIdx === regions.length) {
|
|
17066
|
+
ended = true;
|
|
17067
|
+
break;
|
|
17068
|
+
}
|
|
17007
17069
|
region = regions[regionIdx];
|
|
17008
17070
|
regionUnanchored = region.name === 'UNANCHORED';
|
|
17009
17071
|
}
|
|
17010
17072
|
}
|
|
17011
|
-
|
|
17012
|
-
|
|
17073
|
+
const idxForColor = regionIdx >= regions.length ? regions.length - 1 : regionIdx;
|
|
17074
|
+
const color = $bfd29d54a0f0e853$var$binColor(idxForColor, score || 0, regionUnanchored);
|
|
17075
|
+
if (runColor === null) {
|
|
17076
|
+
runColor = color;
|
|
17077
|
+
runStart = px;
|
|
17078
|
+
} else if (color !== runColor) {
|
|
17079
|
+
flush(px);
|
|
17080
|
+
runColor = color;
|
|
17081
|
+
runStart = px;
|
|
17082
|
+
}
|
|
17083
|
+
if (ended) {
|
|
17084
|
+
px++;
|
|
17085
|
+
break;
|
|
17086
|
+
}
|
|
17013
17087
|
}
|
|
17088
|
+
flush(px);
|
|
17014
17089
|
}
|
|
17015
17090
|
function $bfd29d54a0f0e853$export$390e10a52782f018(taxDist) {
|
|
17016
17091
|
if (!taxDist || typeof taxDist.leafNodes !== 'function') return null;
|
|
@@ -17030,12 +17105,18 @@ function $bfd29d54a0f0e853$export$390e10a52782f018(taxDist) {
|
|
|
17030
17105
|
}
|
|
17031
17106
|
// ── interaction store (shared between Header and Body via hostData) ──────────
|
|
17032
17107
|
// A tiny pub/sub kept OUT of the controlled tbrowse viewState so per-mousemove
|
|
17033
|
-
// hover/drag updates don't churn the whole tree. Holds the hovered
|
|
17034
|
-
// the in-progress drag,
|
|
17108
|
+
// hover/drag/pan/zoom updates don't churn the whole tree. Holds the hovered
|
|
17109
|
+
// chromosome, the in-progress select-drag, the committed drag-selections, and
|
|
17110
|
+
// the shared horizontal pan/zoom transform.
|
|
17111
|
+
const $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM = {
|
|
17112
|
+
scale: 1,
|
|
17113
|
+
leftFrac: 0
|
|
17114
|
+
};
|
|
17035
17115
|
const $bfd29d54a0f0e853$var$EMPTY_UI = {
|
|
17036
17116
|
hovered: null,
|
|
17037
17117
|
inProgress: null,
|
|
17038
|
-
selections: []
|
|
17118
|
+
selections: [],
|
|
17119
|
+
transform: $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM
|
|
17039
17120
|
};
|
|
17040
17121
|
const $bfd29d54a0f0e853$var$NOOP_SUB = ()=>()=>{};
|
|
17041
17122
|
const $bfd29d54a0f0e853$var$NOOP_GET = ()=>$bfd29d54a0f0e853$var$EMPTY_UI;
|
|
@@ -17063,21 +17144,35 @@ function $bfd29d54a0f0e853$export$f06340802363875a() {
|
|
|
17063
17144
|
};
|
|
17064
17145
|
emit();
|
|
17065
17146
|
},
|
|
17147
|
+
setTransform: (t)=>{
|
|
17148
|
+
state = {
|
|
17149
|
+
...state,
|
|
17150
|
+
transform: t
|
|
17151
|
+
};
|
|
17152
|
+
emit();
|
|
17153
|
+
},
|
|
17154
|
+
resetTransform: ()=>{
|
|
17155
|
+
state = {
|
|
17156
|
+
...state,
|
|
17157
|
+
transform: $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM
|
|
17158
|
+
};
|
|
17159
|
+
emit();
|
|
17160
|
+
},
|
|
17066
17161
|
// Add a selection, merging it with any existing selection on the SAME
|
|
17067
|
-
// genome whose
|
|
17162
|
+
// genome whose fraction range overlaps — so overlapping drags become one
|
|
17068
17163
|
// region and shared bins aren't double-counted. Bins are unioned by their
|
|
17069
17164
|
// global index.
|
|
17070
17165
|
addSelection: (sel)=>{
|
|
17071
17166
|
let merged = sel;
|
|
17072
17167
|
const rest = [];
|
|
17073
|
-
for (const s of state.selections)if (s.taxonId === merged.taxonId && s.
|
|
17168
|
+
for (const s of state.selections)if (s.taxonId === merged.taxonId && s.f0 <= merged.f1 && s.f1 >= merged.f0) {
|
|
17074
17169
|
const byIdx = new Map();
|
|
17075
17170
|
for (const b of s.bins)byIdx.set(b.idx, b.count);
|
|
17076
17171
|
for (const b of merged.bins)byIdx.set(b.idx, b.count);
|
|
17077
17172
|
merged = {
|
|
17078
17173
|
taxonId: merged.taxonId,
|
|
17079
|
-
|
|
17080
|
-
|
|
17174
|
+
f0: Math.min(s.f0, merged.f0),
|
|
17175
|
+
f1: Math.max(s.f1, merged.f1),
|
|
17081
17176
|
bins: [
|
|
17082
17177
|
...byIdx
|
|
17083
17178
|
].map(([idx, count])=>({
|
|
@@ -17095,7 +17190,17 @@ function $bfd29d54a0f0e853$export$f06340802363875a() {
|
|
|
17095
17190
|
};
|
|
17096
17191
|
emit();
|
|
17097
17192
|
},
|
|
17193
|
+
// Clear hover/selections but keep the current zoom/pan transform — clearing
|
|
17194
|
+
// selections shouldn't yank the user back out of their zoom.
|
|
17098
17195
|
clear: ()=>{
|
|
17196
|
+
state = {
|
|
17197
|
+
...$bfd29d54a0f0e853$var$EMPTY_UI,
|
|
17198
|
+
transform: state.transform
|
|
17199
|
+
};
|
|
17200
|
+
emit();
|
|
17201
|
+
},
|
|
17202
|
+
// Full reset (new result set): drop everything including the transform.
|
|
17203
|
+
reset: ()=>{
|
|
17099
17204
|
state = $bfd29d54a0f0e853$var$EMPTY_UI;
|
|
17100
17205
|
emit();
|
|
17101
17206
|
}
|
|
@@ -17115,55 +17220,56 @@ function $bfd29d54a0f0e853$export$861100744513cc3(selections) {
|
|
|
17115
17220
|
...set
|
|
17116
17221
|
];
|
|
17117
17222
|
}
|
|
17118
|
-
// Per-genome
|
|
17223
|
+
// Per-genome layout in genome-fraction space [0,1]: region spans (for
|
|
17119
17224
|
// chromosome hit-testing) and bin spans with gene counts (for summing a
|
|
17120
|
-
// drag-selected range).
|
|
17121
|
-
|
|
17225
|
+
// drag-selected range). Width/zoom-independent — the transform maps fractions
|
|
17226
|
+
// to screen pixels at render time.
|
|
17227
|
+
function $bfd29d54a0f0e853$var$buildGenomeLayout(genome) {
|
|
17122
17228
|
const out = {
|
|
17123
17229
|
regions: []
|
|
17124
17230
|
};
|
|
17125
17231
|
const regions = genome && genome._regionsArray;
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
let px = 0;
|
|
17232
|
+
const full = genome && genome.fullGenomeSize;
|
|
17233
|
+
if (!regions || !full) return out;
|
|
17234
|
+
let base = 0;
|
|
17130
17235
|
for (const region of regions){
|
|
17131
|
-
const
|
|
17236
|
+
const f0 = base / full;
|
|
17132
17237
|
const binsArr = [];
|
|
17133
17238
|
const n = region.binCount();
|
|
17134
17239
|
for(let i = 0; i < n; i++){
|
|
17135
17240
|
const bin = region.bin(i);
|
|
17136
|
-
const
|
|
17241
|
+
const size = bin.end - bin.start + 1;
|
|
17242
|
+
const bf0 = base / full;
|
|
17243
|
+
base += size;
|
|
17137
17244
|
binsArr.push({
|
|
17138
|
-
|
|
17139
|
-
|
|
17245
|
+
f0: bf0,
|
|
17246
|
+
f1: base / full,
|
|
17140
17247
|
count: bin.results && bin.results.count || 0,
|
|
17141
17248
|
idx: bin.idx
|
|
17142
17249
|
});
|
|
17143
|
-
px += bw;
|
|
17144
17250
|
}
|
|
17145
17251
|
out.regions.push({
|
|
17146
17252
|
name: region.name,
|
|
17147
|
-
|
|
17148
|
-
|
|
17253
|
+
f0: f0,
|
|
17254
|
+
f1: base / full,
|
|
17149
17255
|
bins: binsArr
|
|
17150
17256
|
});
|
|
17151
17257
|
}
|
|
17152
17258
|
return out;
|
|
17153
17259
|
}
|
|
17154
|
-
function $bfd29d54a0f0e853$var$
|
|
17155
|
-
for (const r of layout.regions)if (
|
|
17260
|
+
function $bfd29d54a0f0e853$var$regionAtFrac(layout, f) {
|
|
17261
|
+
for (const r of layout.regions)if (f >= r.f0 && f < r.f1) return r;
|
|
17156
17262
|
return null;
|
|
17157
17263
|
}
|
|
17158
|
-
// Non-empty bins overlapping a
|
|
17264
|
+
// Non-empty bins overlapping a fraction range, as {idx, count}. Empty bins are
|
|
17159
17265
|
// excluded by design (the selection / filter only covers bins with genes).
|
|
17160
|
-
function $bfd29d54a0f0e853$var$
|
|
17266
|
+
function $bfd29d54a0f0e853$var$selectedBinsInFracRange(layout, a, b) {
|
|
17161
17267
|
const lo = Math.min(a, b);
|
|
17162
17268
|
const hi = Math.max(a, b);
|
|
17163
17269
|
const bins = [];
|
|
17164
17270
|
for (const r of layout.regions){
|
|
17165
|
-
if (r.
|
|
17166
|
-
for (const bin of r.bins)if (bin.
|
|
17271
|
+
if (r.f1 < lo || r.f0 > hi) continue;
|
|
17272
|
+
for (const bin of r.bins)if (bin.f1 > lo && bin.f0 < hi && bin.count > 0) bins.push({
|
|
17167
17273
|
idx: bin.idx,
|
|
17168
17274
|
count: bin.count
|
|
17169
17275
|
});
|
|
@@ -17177,11 +17283,46 @@ const $bfd29d54a0f0e853$var$HEADER_BTN = {
|
|
|
17177
17283
|
padding: '1px 6px',
|
|
17178
17284
|
cursor: 'pointer'
|
|
17179
17285
|
};
|
|
17286
|
+
function $bfd29d54a0f0e853$var$ModeToggle({ mode: mode, setMode: setMode }) {
|
|
17287
|
+
const seg = (id, label)=>/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("button", {
|
|
17288
|
+
type: "button",
|
|
17289
|
+
onClick: ()=>setMode(id),
|
|
17290
|
+
title: id === 'select' ? 'Drag to select a region' : 'Drag to pan, scroll to zoom',
|
|
17291
|
+
style: {
|
|
17292
|
+
fontSize: 11,
|
|
17293
|
+
lineHeight: 1,
|
|
17294
|
+
padding: '2px 7px',
|
|
17295
|
+
cursor: 'pointer',
|
|
17296
|
+
border: 'none',
|
|
17297
|
+
background: mode === id ? 'var(--tbrowse-accent, #2878dc)' : 'transparent',
|
|
17298
|
+
color: mode === id ? '#fff' : 'var(--tbrowse-text-muted)'
|
|
17299
|
+
},
|
|
17300
|
+
children: label
|
|
17301
|
+
});
|
|
17302
|
+
return /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("div", {
|
|
17303
|
+
style: {
|
|
17304
|
+
display: 'inline-flex',
|
|
17305
|
+
border: '1px solid var(--tbrowse-border-soft)',
|
|
17306
|
+
borderRadius: 4,
|
|
17307
|
+
overflow: 'hidden'
|
|
17308
|
+
},
|
|
17309
|
+
children: [
|
|
17310
|
+
seg('select', 'Select'),
|
|
17311
|
+
seg('panzoom', 'Pan/Zoom')
|
|
17312
|
+
]
|
|
17313
|
+
});
|
|
17314
|
+
}
|
|
17180
17315
|
const $bfd29d54a0f0e853$var$BinsHeader = ({ data: data, zoneState: zoneState, setZoneState: setZoneState })=>{
|
|
17181
17316
|
const store = data.hostData && data.hostData.binsUI;
|
|
17182
17317
|
const snap = (0, $gXNCa$react.useSyncExternalStore)(store ? store.subscribe : $bfd29d54a0f0e853$var$NOOP_SUB, store ? store.getState : $bfd29d54a0f0e853$var$NOOP_GET);
|
|
17183
17318
|
const total = $bfd29d54a0f0e853$export$cf7300886d7d9e1e(snap.selections);
|
|
17184
17319
|
const hovered = snap.hovered;
|
|
17320
|
+
const scale = snap.transform ? snap.transform.scale : 1;
|
|
17321
|
+
const mode = zoneState && zoneState.mode || 'select';
|
|
17322
|
+
const setMode = (m)=>setZoneState((s)=>({
|
|
17323
|
+
...s ?? {},
|
|
17324
|
+
mode: m
|
|
17325
|
+
}));
|
|
17185
17326
|
return /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("div", {
|
|
17186
17327
|
style: {
|
|
17187
17328
|
height: '100%',
|
|
@@ -17199,7 +17340,8 @@ const $bfd29d54a0f0e853$var$BinsHeader = ({ data: data, zoneState: zoneState, se
|
|
|
17199
17340
|
display: 'flex',
|
|
17200
17341
|
alignItems: 'center',
|
|
17201
17342
|
gap: 8,
|
|
17202
|
-
minHeight: 0
|
|
17343
|
+
minHeight: 0,
|
|
17344
|
+
flexWrap: 'wrap'
|
|
17203
17345
|
},
|
|
17204
17346
|
children: [
|
|
17205
17347
|
/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)((0, $gXNCa$tbrowse.EditableZoneName), {
|
|
@@ -17210,6 +17352,32 @@ const $bfd29d54a0f0e853$var$BinsHeader = ({ data: data, zoneState: zoneState, se
|
|
|
17210
17352
|
name: next
|
|
17211
17353
|
}))
|
|
17212
17354
|
}),
|
|
17355
|
+
/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)($bfd29d54a0f0e853$var$ModeToggle, {
|
|
17356
|
+
mode: mode,
|
|
17357
|
+
setMode: setMode
|
|
17358
|
+
}),
|
|
17359
|
+
scale > 1.0001 && /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)((0, $gXNCa$reactjsxruntime.Fragment), {
|
|
17360
|
+
children: [
|
|
17361
|
+
/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("span", {
|
|
17362
|
+
style: {
|
|
17363
|
+
color: 'var(--tbrowse-text-muted)',
|
|
17364
|
+
fontSize: 11,
|
|
17365
|
+
whiteSpace: 'nowrap'
|
|
17366
|
+
},
|
|
17367
|
+
children: [
|
|
17368
|
+
scale.toFixed(scale < 10 ? 1 : 0),
|
|
17369
|
+
"\xd7"
|
|
17370
|
+
]
|
|
17371
|
+
}),
|
|
17372
|
+
/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("button", {
|
|
17373
|
+
type: "button",
|
|
17374
|
+
style: $bfd29d54a0f0e853$var$HEADER_BTN,
|
|
17375
|
+
title: "Reset zoom",
|
|
17376
|
+
onClick: ()=>store && store.resetTransform(),
|
|
17377
|
+
children: "reset zoom"
|
|
17378
|
+
})
|
|
17379
|
+
]
|
|
17380
|
+
}),
|
|
17213
17381
|
snap.selections.length > 0 && /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)((0, $gXNCa$reactjsxruntime.Fragment), {
|
|
17214
17382
|
children: [
|
|
17215
17383
|
/*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("span", {
|
|
@@ -17275,7 +17443,7 @@ function $bfd29d54a0f0e853$var$rowHighlight(isSelected, isExactHover, isInHovere
|
|
|
17275
17443
|
return 'transparent';
|
|
17276
17444
|
}
|
|
17277
17445
|
const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
17278
|
-
const { visibleRows: visibleRows, rowRange: rowRange, width: width, data: data, hoveredNodeId: hoveredNodeId, hoveredSubtreeIds: hoveredSubtreeIds, selectedNodeId: selectedNodeId, onHoverNode: onHoverNode, onSelectNode: onSelectNode } = props;
|
|
17446
|
+
const { visibleRows: visibleRows, rowRange: rowRange, width: width, data: data, zoneState: zoneState, hoveredNodeId: hoveredNodeId, hoveredSubtreeIds: hoveredSubtreeIds, selectedNodeId: selectedNodeId, onHoverNode: onHoverNode, onSelectNode: onSelectNode } = props;
|
|
17279
17447
|
const canvasRef = (0, $gXNCa$react.useRef)(null);
|
|
17280
17448
|
const containerRef = (0, $gXNCa$react.useRef)(null);
|
|
17281
17449
|
const dragRef = (0, $gXNCa$react.useRef)(null);
|
|
@@ -17285,27 +17453,33 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17285
17453
|
const suppressClickRef = (0, $gXNCa$react.useRef)(false);
|
|
17286
17454
|
const store = data.hostData && data.hostData.binsUI;
|
|
17287
17455
|
const snap = (0, $gXNCa$react.useSyncExternalStore)(store ? store.subscribe : $bfd29d54a0f0e853$var$NOOP_SUB, store ? store.getState : $bfd29d54a0f0e853$var$NOOP_GET);
|
|
17456
|
+
const transform = snap.transform || $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM;
|
|
17457
|
+
const mode = zoneState && zoneState.mode || 'select';
|
|
17288
17458
|
const totalHeight = visibleRows.length ? visibleRows[visibleRows.length - 1].y + visibleRows[visibleRows.length - 1].height : 0;
|
|
17289
17459
|
const bins = data.hostData && data.hostData.bins;
|
|
17290
17460
|
const rows = visibleRows.slice(rowRange.startIndex, rowRange.endIndex);
|
|
17291
17461
|
const w = Math.max(1, Math.floor(width));
|
|
17292
|
-
//
|
|
17462
|
+
// Fraction-space layout per visible genome row (regions + bins), for
|
|
17463
|
+
// hit-testing. Independent of width/zoom, so it only rebuilds when the row
|
|
17464
|
+
// set changes.
|
|
17293
17465
|
const layouts = (0, $gXNCa$react.useMemo)(()=>{
|
|
17294
17466
|
const m = {};
|
|
17295
17467
|
if (bins) for (const r of rows){
|
|
17296
17468
|
if (r.kind !== 'leaf') continue;
|
|
17297
17469
|
const g = bins.genomesByTaxon[r.nodeId];
|
|
17298
|
-
if (g) m[r.nodeId] = $bfd29d54a0f0e853$var$buildGenomeLayout(g
|
|
17470
|
+
if (g) m[r.nodeId] = $bfd29d54a0f0e853$var$buildGenomeLayout(g);
|
|
17299
17471
|
}
|
|
17300
17472
|
return m;
|
|
17301
17473
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17302
17474
|
}, [
|
|
17303
17475
|
bins,
|
|
17304
|
-
w,
|
|
17305
17476
|
rowRange.startIndex,
|
|
17306
17477
|
rowRange.endIndex,
|
|
17307
17478
|
visibleRows
|
|
17308
17479
|
]);
|
|
17480
|
+
// Fraction <-> screen-pixel helpers under the current transform.
|
|
17481
|
+
const fracToScreen = (f)=>(f - transform.leftFrac) * transform.scale * w;
|
|
17482
|
+
const screenToFrac = (px)=>transform.leftFrac + px / w / transform.scale;
|
|
17309
17483
|
(0, $gXNCa$react.useEffect)(()=>{
|
|
17310
17484
|
const canvas = canvasRef.current;
|
|
17311
17485
|
if (!canvas || !bins) return;
|
|
@@ -17321,7 +17495,7 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17321
17495
|
const genome = bins.genomesByTaxon[r.nodeId];
|
|
17322
17496
|
if (!genome) continue;
|
|
17323
17497
|
const innerH = Math.max(1, r.height - 2 * $bfd29d54a0f0e853$var$ROW_PAD_Y);
|
|
17324
|
-
$bfd29d54a0f0e853$var$drawGenomeRow(ctx, genome,
|
|
17498
|
+
$bfd29d54a0f0e853$var$drawGenomeRow(ctx, genome, r.y + $bfd29d54a0f0e853$var$ROW_PAD_Y, w, innerH, bins.maxScore, transform.scale, transform.leftFrac);
|
|
17325
17499
|
}
|
|
17326
17500
|
}, [
|
|
17327
17501
|
visibleRows,
|
|
@@ -17329,21 +17503,53 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17329
17503
|
rowRange.endIndex,
|
|
17330
17504
|
w,
|
|
17331
17505
|
totalHeight,
|
|
17332
|
-
bins
|
|
17506
|
+
bins,
|
|
17507
|
+
transform.scale,
|
|
17508
|
+
transform.leftFrac
|
|
17333
17509
|
]);
|
|
17334
17510
|
const pxFromEvent = (e)=>{
|
|
17335
17511
|
const el = containerRef.current;
|
|
17336
17512
|
if (!el) return 0;
|
|
17337
17513
|
const rect = el.getBoundingClientRect();
|
|
17338
|
-
return
|
|
17514
|
+
return $bfd29d54a0f0e853$var$clamp(e.clientX - rect.left, 0, w);
|
|
17339
17515
|
};
|
|
17516
|
+
// Wheel-to-zoom (panzoom mode only), centred on the cursor. Native non-passive
|
|
17517
|
+
// listener so we can preventDefault the page scroll; re-attached when mode/
|
|
17518
|
+
// width change. Transform is read live from the store to avoid stale closures.
|
|
17519
|
+
(0, $gXNCa$react.useEffect)(()=>{
|
|
17520
|
+
const el = containerRef.current;
|
|
17521
|
+
if (!el || !store) return undefined;
|
|
17522
|
+
const onWheel = (e)=>{
|
|
17523
|
+
if (mode !== 'panzoom') return; // let the page scroll normally
|
|
17524
|
+
e.preventDefault();
|
|
17525
|
+
const t = store.getState().transform || $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM;
|
|
17526
|
+
const rect = el.getBoundingClientRect();
|
|
17527
|
+
const cursorPx = $bfd29d54a0f0e853$var$clamp(e.clientX - rect.left, 0, w);
|
|
17528
|
+
const fracAtCursor = t.leftFrac + cursorPx / w / t.scale;
|
|
17529
|
+
const factor = Math.exp(-e.deltaY * 0.0015);
|
|
17530
|
+
const newScale = $bfd29d54a0f0e853$var$clamp(t.scale * factor, 1, $bfd29d54a0f0e853$var$MAX_SCALE);
|
|
17531
|
+
const newLeft = $bfd29d54a0f0e853$var$clamp(fracAtCursor - cursorPx / w / newScale, 0, 1 - 1 / newScale);
|
|
17532
|
+
store.setTransform({
|
|
17533
|
+
scale: newScale,
|
|
17534
|
+
leftFrac: newLeft
|
|
17535
|
+
});
|
|
17536
|
+
};
|
|
17537
|
+
el.addEventListener('wheel', onWheel, {
|
|
17538
|
+
passive: false
|
|
17539
|
+
});
|
|
17540
|
+
return ()=>el.removeEventListener('wheel', onWheel);
|
|
17541
|
+
}, [
|
|
17542
|
+
store,
|
|
17543
|
+
w,
|
|
17544
|
+
mode
|
|
17545
|
+
]);
|
|
17340
17546
|
const genomeName = (taxonId)=>{
|
|
17341
17547
|
const tax = data.taxonomy && data.taxonomy[taxonId];
|
|
17342
17548
|
return tax && (tax.commonName || tax.scientificName) || String(taxonId);
|
|
17343
17549
|
};
|
|
17344
17550
|
const onRowMouseMove = (e, r)=>{
|
|
17345
17551
|
if (!store || dragRef.current || !layouts[r.nodeId]) return;
|
|
17346
|
-
const reg = $bfd29d54a0f0e853$var$
|
|
17552
|
+
const reg = $bfd29d54a0f0e853$var$regionAtFrac(layouts[r.nodeId], screenToFrac(pxFromEvent(e)));
|
|
17347
17553
|
if (!reg) {
|
|
17348
17554
|
store.setHovered(null);
|
|
17349
17555
|
return;
|
|
@@ -17354,33 +17560,60 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17354
17560
|
genomeName: genomeName(r.nodeId),
|
|
17355
17561
|
regionName: reg.name,
|
|
17356
17562
|
geneCount: geneCount,
|
|
17357
|
-
|
|
17358
|
-
|
|
17563
|
+
f0: reg.f0,
|
|
17564
|
+
f1: reg.f1
|
|
17359
17565
|
});
|
|
17360
17566
|
};
|
|
17361
|
-
|
|
17362
|
-
|
|
17567
|
+
// Pan drag (panzoom mode): translate leftFrac by the cursor delta, scaled by
|
|
17568
|
+
// the current zoom. Shared transform → every genome row pans together.
|
|
17569
|
+
const startPan = (e)=>{
|
|
17363
17570
|
e.preventDefault();
|
|
17364
17571
|
const startPx = pxFromEvent(e);
|
|
17572
|
+
const t0 = store.getState().transform || $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM;
|
|
17573
|
+
let moved = false;
|
|
17574
|
+
const onMove = (ev)=>{
|
|
17575
|
+
const dx = pxFromEvent(ev) - startPx;
|
|
17576
|
+
if (Math.abs(dx) > 2) moved = true;
|
|
17577
|
+
const t = store.getState().transform || $bfd29d54a0f0e853$var$DEFAULT_TRANSFORM;
|
|
17578
|
+
const newLeft = $bfd29d54a0f0e853$var$clamp(t0.leftFrac - dx / w / t.scale, 0, 1 - 1 / t.scale);
|
|
17579
|
+
store.setTransform({
|
|
17580
|
+
scale: t.scale,
|
|
17581
|
+
leftFrac: newLeft
|
|
17582
|
+
});
|
|
17583
|
+
};
|
|
17584
|
+
const onUp = ()=>{
|
|
17585
|
+
document.removeEventListener('pointermove', onMove);
|
|
17586
|
+
document.removeEventListener('pointerup', onUp);
|
|
17587
|
+
if (moved) suppressClickRef.current = true;
|
|
17588
|
+
};
|
|
17589
|
+
document.addEventListener('pointermove', onMove);
|
|
17590
|
+
document.addEventListener('pointerup', onUp);
|
|
17591
|
+
};
|
|
17592
|
+
// Select drag (select mode): brush a fraction range and add the non-empty
|
|
17593
|
+
// bins under it as a committed selection.
|
|
17594
|
+
const startSelect = (e, r)=>{
|
|
17595
|
+
if (!layouts[r.nodeId]) return;
|
|
17596
|
+
e.preventDefault();
|
|
17597
|
+
const startFrac = screenToFrac(pxFromEvent(e));
|
|
17365
17598
|
dragRef.current = {
|
|
17366
17599
|
taxonId: r.nodeId,
|
|
17367
|
-
|
|
17600
|
+
startFrac: startFrac,
|
|
17368
17601
|
moved: false
|
|
17369
17602
|
};
|
|
17370
17603
|
store.setInProgress({
|
|
17371
17604
|
taxonId: r.nodeId,
|
|
17372
|
-
|
|
17373
|
-
|
|
17605
|
+
f0: startFrac,
|
|
17606
|
+
f1: startFrac
|
|
17374
17607
|
});
|
|
17375
17608
|
const onMove = (ev)=>{
|
|
17376
17609
|
const d = dragRef.current;
|
|
17377
17610
|
if (!d) return;
|
|
17378
|
-
const cur = pxFromEvent(ev);
|
|
17379
|
-
if (Math.abs(cur - d.
|
|
17611
|
+
const cur = screenToFrac(pxFromEvent(ev));
|
|
17612
|
+
if (Math.abs(cur - d.startFrac) * w * transform.scale > 2) d.moved = true;
|
|
17380
17613
|
store.setInProgress({
|
|
17381
17614
|
taxonId: d.taxonId,
|
|
17382
|
-
|
|
17383
|
-
|
|
17615
|
+
f0: Math.min(d.startFrac, cur),
|
|
17616
|
+
f1: Math.max(d.startFrac, cur)
|
|
17384
17617
|
});
|
|
17385
17618
|
};
|
|
17386
17619
|
const onUp = (ev)=>{
|
|
@@ -17391,17 +17624,17 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17391
17624
|
store.setInProgress(null);
|
|
17392
17625
|
if (d && d.moved) {
|
|
17393
17626
|
suppressClickRef.current = true; // swallow the click that follows a drag
|
|
17394
|
-
const cur = pxFromEvent(ev);
|
|
17395
|
-
const
|
|
17396
|
-
const
|
|
17627
|
+
const cur = screenToFrac(pxFromEvent(ev));
|
|
17628
|
+
const f0 = Math.min(d.startFrac, cur);
|
|
17629
|
+
const f1 = Math.max(d.startFrac, cur);
|
|
17397
17630
|
const lay = layouts[d.taxonId];
|
|
17398
17631
|
if (lay) {
|
|
17399
|
-
const
|
|
17400
|
-
if (
|
|
17632
|
+
const selBins = $bfd29d54a0f0e853$var$selectedBinsInFracRange(lay, f0, f1);
|
|
17633
|
+
if (selBins.length) store.addSelection({
|
|
17401
17634
|
taxonId: d.taxonId,
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
bins:
|
|
17635
|
+
f0: f0,
|
|
17636
|
+
f1: f1,
|
|
17637
|
+
bins: selBins
|
|
17405
17638
|
});
|
|
17406
17639
|
}
|
|
17407
17640
|
}
|
|
@@ -17409,15 +17642,29 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17409
17642
|
document.addEventListener('pointermove', onMove);
|
|
17410
17643
|
document.addEventListener('pointerup', onUp);
|
|
17411
17644
|
};
|
|
17645
|
+
const onRowPointerDown = (e, r)=>{
|
|
17646
|
+
if (!store) return;
|
|
17647
|
+
if (mode === 'panzoom') {
|
|
17648
|
+
startPan(e);
|
|
17649
|
+
return;
|
|
17650
|
+
}
|
|
17651
|
+
startSelect(e, r);
|
|
17652
|
+
};
|
|
17412
17653
|
const rowByTaxon = new Map(rows.map((r)=>[
|
|
17413
17654
|
r.nodeId,
|
|
17414
17655
|
r
|
|
17415
17656
|
]));
|
|
17416
|
-
// Outline rectangles (drawn above the canvas; pointer-events:none).
|
|
17417
|
-
//
|
|
17418
|
-
|
|
17657
|
+
// Outline rectangles (drawn above the canvas; pointer-events:none). Stored in
|
|
17658
|
+
// fraction space and projected to screen px under the transform, clipped to
|
|
17659
|
+
// the visible strip. The y comes from the current row so they track scroll.
|
|
17660
|
+
const outline = (key, taxonId, f0, f1, color, dashed)=>{
|
|
17419
17661
|
const r = rowByTaxon.get(taxonId);
|
|
17420
17662
|
if (!r) return null;
|
|
17663
|
+
let x0 = fracToScreen(f0);
|
|
17664
|
+
let x1 = fracToScreen(f1);
|
|
17665
|
+
if (x1 <= 0 || x0 >= w) return null; // fully outside the visible window
|
|
17666
|
+
x0 = Math.max(0, x0);
|
|
17667
|
+
x1 = Math.min(w, x1);
|
|
17421
17668
|
return /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsx)("div", {
|
|
17422
17669
|
style: {
|
|
17423
17670
|
position: 'absolute',
|
|
@@ -17431,6 +17678,7 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17431
17678
|
}
|
|
17432
17679
|
}, key);
|
|
17433
17680
|
};
|
|
17681
|
+
const rowCursor = mode === 'panzoom' ? 'grab' : 'crosshair';
|
|
17434
17682
|
return /*#__PURE__*/ (0, $gXNCa$reactjsxruntime.jsxs)("div", {
|
|
17435
17683
|
ref: containerRef,
|
|
17436
17684
|
style: {
|
|
@@ -17461,7 +17709,7 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17461
17709
|
right: 0,
|
|
17462
17710
|
height: r.height,
|
|
17463
17711
|
background: $bfd29d54a0f0e853$var$rowHighlight(selectedNodeId === r.nodeId, hoveredNodeId === r.nodeId, !!(hoveredSubtreeIds && hoveredSubtreeIds.has(r.nodeId))),
|
|
17464
|
-
cursor:
|
|
17712
|
+
cursor: rowCursor,
|
|
17465
17713
|
opacity: r.opacity ?? 1
|
|
17466
17714
|
}
|
|
17467
17715
|
}, r.nodeId)),
|
|
@@ -17476,9 +17724,9 @@ const $bfd29d54a0f0e853$var$BinsBody = (props)=>{
|
|
|
17476
17724
|
pointerEvents: 'none'
|
|
17477
17725
|
}
|
|
17478
17726
|
}),
|
|
17479
|
-
snap.hovered && !snap.inProgress && outline('hover', snap.hovered.taxonId, snap.hovered.
|
|
17480
|
-
snap.selections.map((s, i)=>outline(`sel-${i}`, s.taxonId, s.
|
|
17481
|
-
snap.inProgress && outline('drag', snap.inProgress.taxonId, snap.inProgress.
|
|
17727
|
+
snap.hovered && !snap.inProgress && outline('hover', snap.hovered.taxonId, snap.hovered.f0, snap.hovered.f1, 'var(--tbrowse-accent, #2878dc)', false),
|
|
17728
|
+
snap.selections.map((s, i)=>outline(`sel-${i}`, s.taxonId, s.f0, s.f1, '#d62728', false)),
|
|
17729
|
+
snap.inProgress && outline('drag', snap.inProgress.taxonId, snap.inProgress.f0, snap.inProgress.f1, '#d62728', true)
|
|
17482
17730
|
]
|
|
17483
17731
|
});
|
|
17484
17732
|
};
|
|
@@ -17489,7 +17737,9 @@ const $bfd29d54a0f0e853$export$d85d069f2280460c = {
|
|
|
17489
17737
|
Body: $bfd29d54a0f0e853$var$BinsBody,
|
|
17490
17738
|
defaultWidth: 60,
|
|
17491
17739
|
minWidth: 200,
|
|
17492
|
-
defaultZoneState: {
|
|
17740
|
+
defaultZoneState: {
|
|
17741
|
+
mode: 'select'
|
|
17742
|
+
},
|
|
17493
17743
|
isAvailable: (data)=>Boolean(data.hostData && data.hostData.bins && data.hostData.bins.genomesByTaxon && Object.keys(data.hostData.bins.genomesByTaxon).length > 0),
|
|
17494
17744
|
defaultVisible: true
|
|
17495
17745
|
};
|
|
@@ -17724,7 +17974,7 @@ const $15504f5eba8e73bd$var$TaxDistTbrowse = (props)=>{
|
|
|
17724
17974
|
const binsUiRef = (0, $gXNCa$react.useRef)(null);
|
|
17725
17975
|
if (!binsUiRef.current) binsUiRef.current = (0, $bfd29d54a0f0e853$export$f06340802363875a)();
|
|
17726
17976
|
(0, $gXNCa$react.useEffect)(()=>{
|
|
17727
|
-
binsUiRef.current.
|
|
17977
|
+
binsUiRef.current.reset();
|
|
17728
17978
|
}, [
|
|
17729
17979
|
grameneTaxDist
|
|
17730
17980
|
]);
|