@apollo-annotation/jbrowse-plugin-apollo 0.3.2 → 0.3.4
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.esm.js +319 -229
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +318 -228
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +318 -228
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -4
- package/src/FeatureDetailsWidget/model.ts +0 -2
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +20 -1
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +232 -117
- package/src/LinearApolloDisplay/stateModel/base.ts +15 -1
- package/src/LinearApolloDisplay/stateModel/layouts.ts +84 -85
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +9 -4
- package/src/LinearApolloDisplay/stateModel/rendering.ts +3 -2
- package/src/OntologyManager/index.ts +22 -0
- package/src/components/FilterFeatures.tsx +2 -2
|
@@ -101,7 +101,7 @@ var ExpandMoreIcon__default = /*#__PURE__*/_interopDefaultLegacy(ExpandMoreIcon)
|
|
|
101
101
|
var ErrorIcon__default = /*#__PURE__*/_interopDefaultLegacy(ErrorIcon);
|
|
102
102
|
var SaveIcon__default = /*#__PURE__*/_interopDefaultLegacy(SaveIcon);
|
|
103
103
|
|
|
104
|
-
var version = "0.3.
|
|
104
|
+
var version = "0.3.4";
|
|
105
105
|
|
|
106
106
|
const ApolloConfigSchema = configuration.ConfigurationSchema('ApolloInternetAccount', {
|
|
107
107
|
baseURL: {
|
|
@@ -1297,6 +1297,7 @@ const OntologyRecordType = mobxStateTree.types
|
|
|
1297
1297
|
})
|
|
1298
1298
|
.volatile((_self) => ({
|
|
1299
1299
|
dataStore: undefined,
|
|
1300
|
+
startedEquivalentTypeRequests: new Set(),
|
|
1300
1301
|
}))
|
|
1301
1302
|
.actions((self) => ({
|
|
1302
1303
|
/** does nothing, just used to access the model to force its lifecycle hooks to run */
|
|
@@ -1320,12 +1321,33 @@ const OntologyRecordType = mobxStateTree.types
|
|
|
1320
1321
|
if (!self.dataStore) {
|
|
1321
1322
|
return;
|
|
1322
1323
|
}
|
|
1324
|
+
if (self.startedEquivalentTypeRequests.has(type)) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
self.startedEquivalentTypeRequests.add(type);
|
|
1323
1328
|
const terms = (yield self.dataStore.getTermsWithLabelOrSynonym(type));
|
|
1324
1329
|
const equivalents = terms
|
|
1325
1330
|
.map((term) => term.lbl)
|
|
1326
1331
|
.filter((term) => term != undefined);
|
|
1327
1332
|
self.setEquivalentTypes(type, equivalents);
|
|
1328
1333
|
}),
|
|
1334
|
+
}))
|
|
1335
|
+
.actions((self) => ({
|
|
1336
|
+
afterCreate() {
|
|
1337
|
+
mobx.autorun((reaction) => {
|
|
1338
|
+
if (!self.dataStore) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
void self.loadEquivalentTypes('gene');
|
|
1342
|
+
void self.loadEquivalentTypes('transcript');
|
|
1343
|
+
void self.loadEquivalentTypes('CDS');
|
|
1344
|
+
void self.loadEquivalentTypes('mRNA');
|
|
1345
|
+
reaction.dispose();
|
|
1346
|
+
});
|
|
1347
|
+
},
|
|
1348
|
+
setEquivalentTypes(type, equivalentTypes) {
|
|
1349
|
+
self.equivalentTypes.set(type, equivalentTypes);
|
|
1350
|
+
},
|
|
1329
1351
|
}))
|
|
1330
1352
|
.views((self) => ({
|
|
1331
1353
|
isTypeOf(queryType, typeOf) {
|
|
@@ -5828,7 +5850,6 @@ const ApolloTranscriptDetailsModel = mobxStateTree.types
|
|
|
5828
5850
|
})),
|
|
5829
5851
|
assembly: mobxStateTree.types.string,
|
|
5830
5852
|
refName: mobxStateTree.types.string,
|
|
5831
|
-
changeManager: mobxStateTree.types.frozen(),
|
|
5832
5853
|
})
|
|
5833
5854
|
.volatile(() => ({
|
|
5834
5855
|
tryReload: undefined,
|
|
@@ -6811,13 +6832,13 @@ const FilterFeatures = mobxReact.observer(function FilterFeatures({ featureTypes
|
|
|
6811
6832
|
React__default["default"].createElement(material.DialogContent, null,
|
|
6812
6833
|
React__default["default"].createElement(material.DialogContentText, null, "Select the feature types you want to display in the apollo track"),
|
|
6813
6834
|
React__default["default"].createElement(material.Grid2, { container: true, spacing: 2 },
|
|
6814
|
-
React__default["default"].createElement(material.Grid2,
|
|
6835
|
+
React__default["default"].createElement(material.Grid2, { size: 8 },
|
|
6815
6836
|
React__default["default"].createElement(OntologyTermAutocomplete, { session: session, ontologyName: "Sequence Ontology", style: { width: '100%' }, value: type, filterTerms: isOntologyClass, renderInput: (params) => (React__default["default"].createElement(material.TextField, { ...params, label: "Feature type", variant: "outlined", fullWidth: true })), onChange: (oldValue, newValue) => {
|
|
6816
6837
|
if (newValue) {
|
|
6817
6838
|
handleChange(newValue);
|
|
6818
6839
|
}
|
|
6819
6840
|
} })),
|
|
6820
|
-
React__default["default"].createElement(material.Grid2,
|
|
6841
|
+
React__default["default"].createElement(material.Grid2, { size: 4 },
|
|
6821
6842
|
React__default["default"].createElement(material.Button, { variant: "contained", onClick: handleAddFeatureType, disabled: !type, style: { marginTop: 9 }, size: "medium" }, "Add"))),
|
|
6822
6843
|
selectedFeatureTypes.length > 0 && (React__default["default"].createElement("div", null,
|
|
6823
6844
|
React__default["default"].createElement("hr", null),
|
|
@@ -6838,6 +6859,7 @@ function baseModelFactory(_pluginManager, configSchema) {
|
|
|
6838
6859
|
table: false,
|
|
6839
6860
|
heightPreConfig: mobxStateTree.types.maybe(mobxStateTree.types.refinement('displayHeight', mobxStateTree.types.number, (n) => n >= minDisplayHeight)),
|
|
6840
6861
|
filteredFeatureTypes: mobxStateTree.types.array(mobxStateTree.types.string),
|
|
6862
|
+
loadingState: false,
|
|
6841
6863
|
})
|
|
6842
6864
|
.views((self) => {
|
|
6843
6865
|
const { configuration, renderProps: superRenderProps } = self;
|
|
@@ -6870,6 +6892,9 @@ function baseModelFactory(_pluginManager, configSchema) {
|
|
|
6870
6892
|
}
|
|
6871
6893
|
return 300;
|
|
6872
6894
|
},
|
|
6895
|
+
get loading() {
|
|
6896
|
+
return self.loadingState;
|
|
6897
|
+
},
|
|
6873
6898
|
}))
|
|
6874
6899
|
.views((self) => ({
|
|
6875
6900
|
get rendererTypeName() {
|
|
@@ -6955,6 +6980,9 @@ function baseModelFactory(_pluginManager, configSchema) {
|
|
|
6955
6980
|
updateFilteredFeatureTypes(types) {
|
|
6956
6981
|
self.filteredFeatureTypes = mobxStateTree.cast(types);
|
|
6957
6982
|
},
|
|
6983
|
+
setLoading(loading) {
|
|
6984
|
+
self.loadingState = loading;
|
|
6985
|
+
},
|
|
6958
6986
|
}))
|
|
6959
6987
|
.views((self) => {
|
|
6960
6988
|
const { filteredFeatureTypes, trackMenuItems: superTrackMenuItems } = self;
|
|
@@ -7025,7 +7053,14 @@ function baseModelFactory(_pluginManager, configSchema) {
|
|
|
7025
7053
|
if (!self.lgv.initialized || self.regionCannotBeRendered()) {
|
|
7026
7054
|
return;
|
|
7027
7055
|
}
|
|
7028
|
-
|
|
7056
|
+
self.setLoading(true);
|
|
7057
|
+
void self.session.apolloDataStore
|
|
7058
|
+
.loadFeatures(self.regions)
|
|
7059
|
+
.then(() => {
|
|
7060
|
+
setTimeout(() => {
|
|
7061
|
+
self.setLoading(false);
|
|
7062
|
+
}, 1000);
|
|
7063
|
+
});
|
|
7029
7064
|
if (self.lgv.bpPerPx <= 3) {
|
|
7030
7065
|
void self.session.apolloDataStore.loadRefSeq(self.regions);
|
|
7031
7066
|
}
|
|
@@ -7454,7 +7489,6 @@ function draw$1(ctx, feature, row, stateModel, displayedRegionIndex) {
|
|
|
7454
7489
|
const displayedRegion = displayedRegions[displayedRegionIndex];
|
|
7455
7490
|
const { refName, reversed } = displayedRegion;
|
|
7456
7491
|
const rowHeight = apolloRowHeight;
|
|
7457
|
-
const exonHeight = Math.round(0.6 * rowHeight);
|
|
7458
7492
|
const cdsHeight = Math.round(0.9 * rowHeight);
|
|
7459
7493
|
const { children, min, strand } = feature;
|
|
7460
7494
|
if (!children) {
|
|
@@ -7488,27 +7522,20 @@ function draw$1(ctx, feature, row, stateModel, displayedRegionIndex) {
|
|
|
7488
7522
|
currentRow += 1;
|
|
7489
7523
|
continue;
|
|
7490
7524
|
}
|
|
7491
|
-
const { children:
|
|
7492
|
-
if (!
|
|
7525
|
+
const { children: transcriptChildren } = transcript;
|
|
7526
|
+
if (!transcriptChildren) {
|
|
7493
7527
|
continue;
|
|
7494
7528
|
}
|
|
7495
|
-
|
|
7496
|
-
|
|
7529
|
+
const cdsCount = getCDSCount(transcript, featureTypeOntology);
|
|
7530
|
+
for (const [, childFeature] of transcriptChildren) {
|
|
7531
|
+
if (!featureTypeOntology.isTypeOf(childFeature.type, 'CDS')) {
|
|
7497
7532
|
continue;
|
|
7498
7533
|
}
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
const widthPx = transcript.length / bpPerPx;
|
|
7505
|
-
const startPx = reversed ? minX - widthPx : minX;
|
|
7506
|
-
const height = Math.round((currentRow + 1 / 2) * rowHeight) + row * rowHeight;
|
|
7507
|
-
ctx.strokeStyle = theme?.palette.text.primary ?? 'black';
|
|
7508
|
-
ctx.beginPath();
|
|
7509
|
-
ctx.moveTo(startPx, height);
|
|
7510
|
-
ctx.lineTo(startPx + widthPx, height);
|
|
7511
|
-
ctx.stroke();
|
|
7534
|
+
drawLine(ctx, stateModel, displayedRegionIndex, row, transcript, currentRow);
|
|
7535
|
+
currentRow += 1;
|
|
7536
|
+
}
|
|
7537
|
+
if (cdsCount === 0) {
|
|
7538
|
+
drawLine(ctx, stateModel, displayedRegionIndex, row, transcript, currentRow);
|
|
7512
7539
|
currentRow += 1;
|
|
7513
7540
|
}
|
|
7514
7541
|
}
|
|
@@ -7522,83 +7549,125 @@ function draw$1(ctx, feature, row, stateModel, displayedRegionIndex) {
|
|
|
7522
7549
|
currentRow += 1;
|
|
7523
7550
|
continue;
|
|
7524
7551
|
}
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
for (const [, exon] of childrenOfTranscript) {
|
|
7531
|
-
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
7552
|
+
const cdsCount = getCDSCount(child, featureTypeOntology);
|
|
7553
|
+
if (cdsCount != 0) {
|
|
7554
|
+
for (const cdsRow of child.cdsLocations) {
|
|
7555
|
+
const { _id, children: transcriptChildren } = child;
|
|
7556
|
+
if (!transcriptChildren) {
|
|
7532
7557
|
continue;
|
|
7533
7558
|
}
|
|
7534
|
-
const
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
const
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
const
|
|
7554
|
-
const
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
ctx.
|
|
7559
|
+
for (const [, exon] of transcriptChildren) {
|
|
7560
|
+
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
7561
|
+
continue;
|
|
7562
|
+
}
|
|
7563
|
+
drawExon(ctx, stateModel, displayedRegionIndex, row, exon, currentRow, strand, forwardFill, backwardFill);
|
|
7564
|
+
}
|
|
7565
|
+
for (const cds of cdsRow) {
|
|
7566
|
+
const cdsWidthPx = (cds.max - cds.min) / bpPerPx;
|
|
7567
|
+
const minX = (lgv.bpToPx({
|
|
7568
|
+
refName,
|
|
7569
|
+
coord: cds.min,
|
|
7570
|
+
regionNumber: displayedRegionIndex,
|
|
7571
|
+
})?.offsetPx ?? 0) - offsetPx;
|
|
7572
|
+
const cdsStartPx = reversed ? minX - cdsWidthPx : minX;
|
|
7573
|
+
ctx.fillStyle = theme?.palette.text.primary ?? 'black';
|
|
7574
|
+
const cdsTop = (row + currentRow) * rowHeight + (rowHeight - cdsHeight) / 2;
|
|
7575
|
+
ctx.fillRect(cdsStartPx, cdsTop, cdsWidthPx, cdsHeight);
|
|
7576
|
+
if (cdsWidthPx > 2) {
|
|
7577
|
+
ctx.clearRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, cdsHeight - 2);
|
|
7578
|
+
const frame = util.getFrame(cds.min, cds.max, child.strand ?? 1, cds.phase);
|
|
7579
|
+
const frameColor = theme?.palette.framesCDS.at(frame)?.main;
|
|
7580
|
+
const cdsColorCode = frameColor ?? 'rgb(171,71,188)';
|
|
7581
|
+
ctx.fillStyle =
|
|
7582
|
+
apolloSelectedFeature && _id === apolloSelectedFeature._id
|
|
7583
|
+
? 'rgb(0,0,0)'
|
|
7584
|
+
: cdsColorCode;
|
|
7585
|
+
ctx.fillStyle = cdsColorCode;
|
|
7586
|
+
ctx.fillRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, cdsHeight - 2);
|
|
7587
|
+
if (forwardFill && backwardFill && strand) {
|
|
7588
|
+
const reversal = reversed ? -1 : 1;
|
|
7589
|
+
const [topFill, bottomFill] = strand * reversal === 1
|
|
7590
|
+
? [forwardFill, backwardFill]
|
|
7591
|
+
: [backwardFill, forwardFill];
|
|
7592
|
+
ctx.fillStyle = topFill;
|
|
7593
|
+
ctx.fillRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, (cdsHeight - 2) / 2);
|
|
7594
|
+
ctx.fillStyle = bottomFill;
|
|
7595
|
+
ctx.fillRect(cdsStartPx + 1, cdsTop + (cdsHeight - 2) / 2, cdsWidthPx - 2, (cdsHeight - 2) / 2);
|
|
7596
|
+
}
|
|
7561
7597
|
}
|
|
7562
7598
|
}
|
|
7599
|
+
currentRow += 1;
|
|
7563
7600
|
}
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
const cdsStartPx = reversed ? minX - cdsWidthPx : minX;
|
|
7572
|
-
ctx.fillStyle = theme?.palette.text.primary ?? 'black';
|
|
7573
|
-
const cdsTop = (row + currentRow) * rowHeight + (rowHeight - cdsHeight) / 2;
|
|
7574
|
-
ctx.fillRect(cdsStartPx, cdsTop, cdsWidthPx, cdsHeight);
|
|
7575
|
-
if (cdsWidthPx > 2) {
|
|
7576
|
-
ctx.clearRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, cdsHeight - 2);
|
|
7577
|
-
const frame = util.getFrame(cds.min, cds.max, child.strand ?? 1, cds.phase);
|
|
7578
|
-
const frameColor = theme?.palette.framesCDS.at(frame)?.main;
|
|
7579
|
-
const cdsColorCode = frameColor ?? 'rgb(171,71,188)';
|
|
7580
|
-
ctx.fillStyle =
|
|
7581
|
-
apolloSelectedFeature && _id === apolloSelectedFeature._id
|
|
7582
|
-
? 'rgb(0,0,0)'
|
|
7583
|
-
: cdsColorCode;
|
|
7584
|
-
ctx.fillStyle = cdsColorCode;
|
|
7585
|
-
ctx.fillRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, cdsHeight - 2);
|
|
7586
|
-
if (forwardFill && backwardFill && strand) {
|
|
7587
|
-
const reversal = reversed ? -1 : 1;
|
|
7588
|
-
const [topFill, bottomFill] = strand * reversal === 1
|
|
7589
|
-
? [forwardFill, backwardFill]
|
|
7590
|
-
: [backwardFill, forwardFill];
|
|
7591
|
-
ctx.fillStyle = topFill;
|
|
7592
|
-
ctx.fillRect(cdsStartPx + 1, cdsTop + 1, cdsWidthPx - 2, (cdsHeight - 2) / 2);
|
|
7593
|
-
ctx.fillStyle = bottomFill;
|
|
7594
|
-
ctx.fillRect(cdsStartPx + 1, cdsTop + (cdsHeight - 2) / 2, cdsWidthPx - 2, (cdsHeight - 2) / 2);
|
|
7595
|
-
}
|
|
7601
|
+
}
|
|
7602
|
+
const { children: transcriptChildren } = child;
|
|
7603
|
+
// Draw exons for non-coding genes
|
|
7604
|
+
if (cdsCount === 0 && transcriptChildren) {
|
|
7605
|
+
for (const [, exon] of transcriptChildren) {
|
|
7606
|
+
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
7607
|
+
continue;
|
|
7596
7608
|
}
|
|
7609
|
+
drawExon(ctx, stateModel, displayedRegionIndex, row, exon, currentRow, strand, forwardFill, backwardFill);
|
|
7597
7610
|
}
|
|
7598
7611
|
currentRow += 1;
|
|
7599
7612
|
}
|
|
7600
7613
|
}
|
|
7601
7614
|
}
|
|
7615
|
+
function drawExon(ctx, stateModel, displayedRegionIndex, row, exon, currentRow, strand, forwardFill, backwardFill) {
|
|
7616
|
+
const { apolloRowHeight, lgv, session, theme } = stateModel;
|
|
7617
|
+
const { bpPerPx, displayedRegions, offsetPx } = lgv;
|
|
7618
|
+
const displayedRegion = displayedRegions[displayedRegionIndex];
|
|
7619
|
+
const { refName, reversed } = displayedRegion;
|
|
7620
|
+
const { apolloSelectedFeature } = session;
|
|
7621
|
+
const minX = (lgv.bpToPx({
|
|
7622
|
+
refName,
|
|
7623
|
+
coord: exon.min,
|
|
7624
|
+
regionNumber: displayedRegionIndex,
|
|
7625
|
+
})?.offsetPx ?? 0) - offsetPx;
|
|
7626
|
+
const widthPx = exon.length / bpPerPx;
|
|
7627
|
+
const startPx = reversed ? minX - widthPx : minX;
|
|
7628
|
+
const top = (row + currentRow) * apolloRowHeight;
|
|
7629
|
+
const exonHeight = Math.round(0.6 * apolloRowHeight);
|
|
7630
|
+
const exonTop = top + (apolloRowHeight - exonHeight) / 2;
|
|
7631
|
+
ctx.fillStyle = theme?.palette.text.primary ?? 'black';
|
|
7632
|
+
ctx.fillRect(startPx, exonTop, widthPx, exonHeight);
|
|
7633
|
+
if (widthPx > 2) {
|
|
7634
|
+
ctx.clearRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2);
|
|
7635
|
+
ctx.fillStyle =
|
|
7636
|
+
apolloSelectedFeature && exon._id === apolloSelectedFeature._id
|
|
7637
|
+
? 'rgb(0,0,0)'
|
|
7638
|
+
: 'rgb(211,211,211)';
|
|
7639
|
+
ctx.fillRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2);
|
|
7640
|
+
if (forwardFill && backwardFill && strand) {
|
|
7641
|
+
const reversal = reversed ? -1 : 1;
|
|
7642
|
+
const [topFill, bottomFill] = strand * reversal === 1
|
|
7643
|
+
? [forwardFill, backwardFill]
|
|
7644
|
+
: [backwardFill, forwardFill];
|
|
7645
|
+
ctx.fillStyle = topFill;
|
|
7646
|
+
ctx.fillRect(startPx + 1, exonTop + 1, widthPx - 2, (exonHeight - 2) / 2);
|
|
7647
|
+
ctx.fillStyle = bottomFill;
|
|
7648
|
+
ctx.fillRect(startPx + 1, exonTop + 1 + (exonHeight - 2) / 2, widthPx - 2, (exonHeight - 2) / 2);
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
}
|
|
7652
|
+
function drawLine(ctx, stateModel, displayedRegionIndex, row, transcript, currentRow) {
|
|
7653
|
+
const { apolloRowHeight, lgv, theme } = stateModel;
|
|
7654
|
+
const { bpPerPx, displayedRegions, offsetPx } = lgv;
|
|
7655
|
+
const displayedRegion = displayedRegions[displayedRegionIndex];
|
|
7656
|
+
const { refName, reversed } = displayedRegion;
|
|
7657
|
+
const minX = (lgv.bpToPx({
|
|
7658
|
+
refName,
|
|
7659
|
+
coord: transcript.min,
|
|
7660
|
+
regionNumber: displayedRegionIndex,
|
|
7661
|
+
})?.offsetPx ?? 0) - offsetPx;
|
|
7662
|
+
const widthPx = transcript.length / bpPerPx;
|
|
7663
|
+
const startPx = reversed ? minX - widthPx : minX;
|
|
7664
|
+
const height = Math.round((currentRow + 1 / 2) * apolloRowHeight) + row * apolloRowHeight;
|
|
7665
|
+
ctx.strokeStyle = theme?.palette.text.primary ?? 'black';
|
|
7666
|
+
ctx.beginPath();
|
|
7667
|
+
ctx.moveTo(startPx, height);
|
|
7668
|
+
ctx.lineTo(startPx + widthPx, height);
|
|
7669
|
+
ctx.stroke();
|
|
7670
|
+
}
|
|
7602
7671
|
function drawDragPreview$1(stateModel, overlayCtx) {
|
|
7603
7672
|
const { apolloDragging, apolloRowHeight, lgv, theme } = stateModel;
|
|
7604
7673
|
const { bpPerPx, displayedRegions, offsetPx } = lgv;
|
|
@@ -7682,6 +7751,22 @@ function getFeatureFromLayout$1(feature, bp, row, featureTypeOntology) {
|
|
|
7682
7751
|
}
|
|
7683
7752
|
return feature;
|
|
7684
7753
|
}
|
|
7754
|
+
function getCDSCount(feature, featureTypeOntology) {
|
|
7755
|
+
const { children, type } = feature;
|
|
7756
|
+
if (!children) {
|
|
7757
|
+
return 0;
|
|
7758
|
+
}
|
|
7759
|
+
const isMrna = featureTypeOntology.isTypeOf(type, 'mRNA');
|
|
7760
|
+
let cdsCount = 0;
|
|
7761
|
+
if (isMrna) {
|
|
7762
|
+
for (const [, child] of children) {
|
|
7763
|
+
if (featureTypeOntology.isTypeOf(child.type, 'CDS')) {
|
|
7764
|
+
cdsCount += 1;
|
|
7765
|
+
}
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7768
|
+
return cdsCount;
|
|
7769
|
+
}
|
|
7685
7770
|
function getRowCount$1(feature, featureTypeOntology, _bpPerPx) {
|
|
7686
7771
|
const { children, type } = feature;
|
|
7687
7772
|
if (!children) {
|
|
@@ -7691,12 +7776,12 @@ function getRowCount$1(feature, featureTypeOntology, _bpPerPx) {
|
|
|
7691
7776
|
let rowCount = 0;
|
|
7692
7777
|
if (isTranscript) {
|
|
7693
7778
|
for (const [, child] of children) {
|
|
7694
|
-
|
|
7695
|
-
if (isCds) {
|
|
7779
|
+
if (featureTypeOntology.isTypeOf(child.type, 'CDS')) {
|
|
7696
7780
|
rowCount += 1;
|
|
7697
7781
|
}
|
|
7698
7782
|
}
|
|
7699
|
-
return
|
|
7783
|
+
// return 1 if there are no CDSs for non coding genes
|
|
7784
|
+
return rowCount === 0 ? 1 : rowCount;
|
|
7700
7785
|
}
|
|
7701
7786
|
for (const [, child] of children) {
|
|
7702
7787
|
rowCount += getRowCount$1(child, featureTypeOntology);
|
|
@@ -7740,6 +7825,9 @@ function featuresForRow$1(feature, featureTypeOntology) {
|
|
|
7740
7825
|
for (const cds of cdss) {
|
|
7741
7826
|
features.push([cds, ...exons, child, feature]);
|
|
7742
7827
|
}
|
|
7828
|
+
if (cdss.length === 0) {
|
|
7829
|
+
features.push([...exons, child, feature]);
|
|
7830
|
+
}
|
|
7743
7831
|
}
|
|
7744
7832
|
return features;
|
|
7745
7833
|
}
|
|
@@ -7987,49 +8075,39 @@ const genericChildGlyph = {
|
|
|
7987
8075
|
};
|
|
7988
8076
|
|
|
7989
8077
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
8078
|
+
function getRowsForFeature(startingRow, rowCount, filledRowLocations) {
|
|
8079
|
+
const rowsForFeature = [];
|
|
8080
|
+
for (let i = startingRow; i < startingRow + rowCount; i++) {
|
|
8081
|
+
const row = filledRowLocations.get(i);
|
|
8082
|
+
if (row) {
|
|
8083
|
+
rowsForFeature.push(row);
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
return rowsForFeature;
|
|
8087
|
+
}
|
|
8088
|
+
function canPlaceFeatureInRows(rowsForFeature, feature) {
|
|
8089
|
+
for (const rowForFeature of rowsForFeature) {
|
|
8090
|
+
for (const [rowStart, rowEnd] of rowForFeature) {
|
|
8091
|
+
if (util.doesIntersect2(feature.min, feature.max, rowStart, rowEnd) ||
|
|
8092
|
+
util.doesIntersect2(rowStart, rowEnd, feature.min, feature.max)) {
|
|
8093
|
+
return false;
|
|
8094
|
+
}
|
|
8095
|
+
}
|
|
8096
|
+
}
|
|
8097
|
+
return true;
|
|
8098
|
+
}
|
|
7990
8099
|
function layoutsModelFactory(pluginManager, configSchema) {
|
|
7991
8100
|
const BaseLinearApolloDisplay = baseModelFactory(pluginManager, configSchema);
|
|
7992
8101
|
return BaseLinearApolloDisplay.named('LinearApolloDisplayLayouts')
|
|
7993
8102
|
.props({
|
|
7994
|
-
|
|
8103
|
+
cleanupBoundary: 200_000,
|
|
7995
8104
|
})
|
|
7996
8105
|
.volatile(() => ({
|
|
7997
8106
|
seenFeatures: mobx.observable.map(),
|
|
7998
8107
|
}))
|
|
7999
8108
|
.views((self) => ({
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
return self.lgv.displayedRegions.map((region) => {
|
|
8003
|
-
const assembly = assemblyManager.get(region.assemblyName);
|
|
8004
|
-
let min;
|
|
8005
|
-
let max;
|
|
8006
|
-
const { end, refName, start } = region;
|
|
8007
|
-
for (const [, feature] of self.seenFeatures) {
|
|
8008
|
-
if (refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
|
|
8009
|
-
!util.doesIntersect2(start, end, feature.min, feature.max) ||
|
|
8010
|
-
feature.length > self.featuresMinMaxLimit ||
|
|
8011
|
-
(self.filteredFeatureTypes.length > 0 &&
|
|
8012
|
-
!self.filteredFeatureTypes.includes(feature.type))) {
|
|
8013
|
-
continue;
|
|
8014
|
-
}
|
|
8015
|
-
if (min === undefined) {
|
|
8016
|
-
({ min } = feature);
|
|
8017
|
-
}
|
|
8018
|
-
if (max === undefined) {
|
|
8019
|
-
({ max } = feature);
|
|
8020
|
-
}
|
|
8021
|
-
if (feature.minWithChildren < min) {
|
|
8022
|
-
({ min } = feature);
|
|
8023
|
-
}
|
|
8024
|
-
if (feature.maxWithChildren > max) {
|
|
8025
|
-
({ max } = feature);
|
|
8026
|
-
}
|
|
8027
|
-
}
|
|
8028
|
-
if (min !== undefined && max !== undefined) {
|
|
8029
|
-
return [min, max];
|
|
8030
|
-
}
|
|
8031
|
-
return;
|
|
8032
|
-
});
|
|
8109
|
+
getAnnotationFeatureById(id) {
|
|
8110
|
+
return self.seenFeatures.get(id);
|
|
8033
8111
|
},
|
|
8034
8112
|
getGlyph(feature) {
|
|
8035
8113
|
if (this.looksLikeGene(feature)) {
|
|
@@ -8059,11 +8137,7 @@ function layoutsModelFactory(pluginManager, configSchema) {
|
|
|
8059
8137
|
if (!grandChildren?.size) {
|
|
8060
8138
|
return false;
|
|
8061
8139
|
}
|
|
8062
|
-
|
|
8063
|
-
const hasExon = [...grandChildren.values()].some((grandchild) => featureTypeOntology.isTypeOf(grandchild.type, 'exon'));
|
|
8064
|
-
if (hasCDS && hasExon) {
|
|
8065
|
-
return true;
|
|
8066
|
-
}
|
|
8140
|
+
return [...grandChildren.values()].some((grandchild) => featureTypeOntology.isTypeOf(grandchild.type, 'exon'));
|
|
8067
8141
|
}
|
|
8068
8142
|
}
|
|
8069
8143
|
return false;
|
|
@@ -8080,15 +8154,11 @@ function layoutsModelFactory(pluginManager, configSchema) {
|
|
|
8080
8154
|
.views((self) => ({
|
|
8081
8155
|
get featureLayouts() {
|
|
8082
8156
|
const { assemblyManager } = self.session;
|
|
8083
|
-
return self.lgv.displayedRegions.map((region
|
|
8157
|
+
return self.lgv.displayedRegions.map((region) => {
|
|
8084
8158
|
const assembly = assemblyManager.get(region.assemblyName);
|
|
8085
8159
|
const featureLayout = new Map();
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
return featureLayout;
|
|
8089
|
-
}
|
|
8090
|
-
const [min, max] = minMax;
|
|
8091
|
-
const rows = [];
|
|
8160
|
+
// Track the occupied coordinates in each row
|
|
8161
|
+
const filledRowLocations = new Map();
|
|
8092
8162
|
const { end, refName, start } = region;
|
|
8093
8163
|
for (const [id, feature] of self.seenFeatures.entries()) {
|
|
8094
8164
|
if (!mobxStateTree.isAlive(feature)) {
|
|
@@ -8111,42 +8181,23 @@ function layoutsModelFactory(pluginManager, configSchema) {
|
|
|
8111
8181
|
let startingRow = 0;
|
|
8112
8182
|
let placed = false;
|
|
8113
8183
|
while (!placed) {
|
|
8114
|
-
let rowsForFeature =
|
|
8184
|
+
let rowsForFeature = getRowsForFeature(startingRow, rowCount, filledRowLocations);
|
|
8115
8185
|
if (rowsForFeature.length < rowCount) {
|
|
8116
8186
|
for (let i = 0; i < rowCount - rowsForFeature.length; i++) {
|
|
8117
|
-
const newRowNumber =
|
|
8118
|
-
|
|
8187
|
+
const newRowNumber = filledRowLocations.size;
|
|
8188
|
+
filledRowLocations.set(newRowNumber, []);
|
|
8119
8189
|
featureLayout.set(newRowNumber, []);
|
|
8120
8190
|
}
|
|
8121
|
-
rowsForFeature =
|
|
8191
|
+
rowsForFeature = getRowsForFeature(startingRow, rowCount, filledRowLocations);
|
|
8122
8192
|
}
|
|
8123
|
-
if (rowsForFeature
|
|
8124
|
-
.map((rowForFeature) => {
|
|
8125
|
-
// zero-length features are allowed in the spec
|
|
8126
|
-
const featureMax = feature.max - feature.min === 0
|
|
8127
|
-
? feature.min + 1
|
|
8128
|
-
: feature.max;
|
|
8129
|
-
let start = feature.min - min, end = featureMax - min;
|
|
8130
|
-
if (feature.min - min < 0) {
|
|
8131
|
-
start = 0;
|
|
8132
|
-
end = featureMax - feature.min;
|
|
8133
|
-
}
|
|
8134
|
-
return rowForFeature.slice(start, end).some(Boolean);
|
|
8135
|
-
})
|
|
8136
|
-
.some(Boolean)) {
|
|
8193
|
+
if (!canPlaceFeatureInRows(rowsForFeature, feature)) {
|
|
8137
8194
|
startingRow += 1;
|
|
8138
8195
|
continue;
|
|
8139
8196
|
}
|
|
8140
8197
|
for (let rowNum = startingRow; rowNum < startingRow + rowCount; rowNum++) {
|
|
8141
|
-
|
|
8142
|
-
let start = feature.min - min, end = feature.max - min;
|
|
8143
|
-
if (feature.min - min < 0) {
|
|
8144
|
-
start = 0;
|
|
8145
|
-
end = feature.max - feature.min;
|
|
8146
|
-
}
|
|
8147
|
-
row.fill(true, start, end);
|
|
8198
|
+
filledRowLocations.get(rowNum)?.push([feature.min, feature.max]);
|
|
8148
8199
|
const layoutRow = featureLayout.get(rowNum);
|
|
8149
|
-
layoutRow?.push([rowNum - startingRow, feature]);
|
|
8200
|
+
layoutRow?.push([rowNum - startingRow, feature._id]);
|
|
8150
8201
|
}
|
|
8151
8202
|
placed = true;
|
|
8152
8203
|
}
|
|
@@ -8159,12 +8210,16 @@ function layoutsModelFactory(pluginManager, configSchema) {
|
|
|
8159
8210
|
const { featureTypeOntology } = self.session.apolloDataStore.ontologyManager;
|
|
8160
8211
|
for (const [idx, layout] of featureLayouts.entries()) {
|
|
8161
8212
|
for (const [layoutRowNum, layoutRow] of layout) {
|
|
8162
|
-
for (const [featureRowNum,
|
|
8213
|
+
for (const [featureRowNum, layoutFeatureId] of layoutRow) {
|
|
8163
8214
|
if (featureRowNum !== 0) {
|
|
8164
8215
|
// Same top-level feature in all feature rows, so only need to
|
|
8165
8216
|
// check the first one
|
|
8166
8217
|
continue;
|
|
8167
8218
|
}
|
|
8219
|
+
const layoutFeature = self.getAnnotationFeatureById(layoutFeatureId);
|
|
8220
|
+
if (!layoutFeature) {
|
|
8221
|
+
continue;
|
|
8222
|
+
}
|
|
8168
8223
|
if (feature._id === layoutFeature._id) {
|
|
8169
8224
|
return {
|
|
8170
8225
|
layoutIndex: idx,
|
|
@@ -8204,6 +8259,23 @@ function layoutsModelFactory(pluginManager, configSchema) {
|
|
|
8204
8259
|
if (!self.lgv.initialized || self.regionCannotBeRendered()) {
|
|
8205
8260
|
return;
|
|
8206
8261
|
}
|
|
8262
|
+
// Clear out features that are no longer in the view and out of the cleanup boundary
|
|
8263
|
+
// cleanup boundary + region boundary + cleanup boundary
|
|
8264
|
+
for (const [id, feature] of self.seenFeatures.entries()) {
|
|
8265
|
+
let shouldKeep = false;
|
|
8266
|
+
for (const region of self.regions) {
|
|
8267
|
+
const extendedStart = region.start - self.cleanupBoundary;
|
|
8268
|
+
const extendedEnd = region.end + self.cleanupBoundary;
|
|
8269
|
+
if (util.doesIntersect2(extendedStart, extendedEnd, feature.min, feature.max)) {
|
|
8270
|
+
shouldKeep = true;
|
|
8271
|
+
break;
|
|
8272
|
+
}
|
|
8273
|
+
}
|
|
8274
|
+
if (!shouldKeep) {
|
|
8275
|
+
self.deleteSeenFeature(id);
|
|
8276
|
+
}
|
|
8277
|
+
}
|
|
8278
|
+
// Add features that are in the current view
|
|
8207
8279
|
for (const region of self.regions) {
|
|
8208
8280
|
const assembly = self.session.apolloDataStore.assemblies.get(region.assemblyName);
|
|
8209
8281
|
const ref = assembly?.getByRefName(region.refName);
|
|
@@ -8477,8 +8549,9 @@ function renderingModelFactory(pluginManager, configSchema) {
|
|
|
8477
8549
|
for (const [idx, featureLayout] of featureLayouts.entries()) {
|
|
8478
8550
|
const displayedRegion = displayedRegions[idx];
|
|
8479
8551
|
for (const [row, featureLayoutRow] of featureLayout.entries()) {
|
|
8480
|
-
for (const [featureRow,
|
|
8481
|
-
|
|
8552
|
+
for (const [featureRow, featureId] of featureLayoutRow) {
|
|
8553
|
+
const feature = self.getAnnotationFeatureById(featureId);
|
|
8554
|
+
if (featureRow > 0 || !feature) {
|
|
8482
8555
|
continue;
|
|
8483
8556
|
}
|
|
8484
8557
|
if (!util.doesIntersect2(displayedRegion.start, displayedRegion.end, feature.min, feature.max)) {
|
|
@@ -8559,11 +8632,18 @@ function mouseEventsModelIntermediateFactory(pluginManager, configSchema) {
|
|
|
8559
8632
|
if (!layoutRow) {
|
|
8560
8633
|
return mousePosition;
|
|
8561
8634
|
}
|
|
8562
|
-
const foundFeature = layoutRow.find((f) =>
|
|
8635
|
+
const foundFeature = layoutRow.find((f) => {
|
|
8636
|
+
const feature = self.getAnnotationFeatureById(f[1]);
|
|
8637
|
+
return feature && bp >= feature.min && bp <= feature.max;
|
|
8638
|
+
});
|
|
8563
8639
|
if (!foundFeature) {
|
|
8564
8640
|
return mousePosition;
|
|
8565
8641
|
}
|
|
8566
|
-
const [featureRow,
|
|
8642
|
+
const [featureRow, topLevelFeatureId] = foundFeature;
|
|
8643
|
+
const topLevelFeature = self.getAnnotationFeatureById(topLevelFeatureId);
|
|
8644
|
+
if (!topLevelFeature) {
|
|
8645
|
+
return mousePosition;
|
|
8646
|
+
}
|
|
8567
8647
|
const glyph = self.getGlyph(topLevelFeature);
|
|
8568
8648
|
const { featureTypeOntology } = self.session.apolloDataStore.ontologyManager;
|
|
8569
8649
|
if (!featureTypeOntology) {
|
|
@@ -8847,11 +8927,18 @@ const useStyles$1 = mui.makeStyles()((theme) => ({
|
|
|
8847
8927
|
color: theme.palette.warning.light,
|
|
8848
8928
|
backgroundColor: theme.palette.warning.contrastText,
|
|
8849
8929
|
},
|
|
8930
|
+
loading: {
|
|
8931
|
+
position: 'absolute',
|
|
8932
|
+
right: theme.spacing(3),
|
|
8933
|
+
zIndex: 10,
|
|
8934
|
+
pointerEvents: 'none',
|
|
8935
|
+
textAlign: 'right',
|
|
8936
|
+
},
|
|
8850
8937
|
}));
|
|
8851
8938
|
const LinearApolloDisplay = mobxReact.observer(function LinearApolloDisplay(props) {
|
|
8852
8939
|
const theme = material.useTheme();
|
|
8853
8940
|
const { model } = props;
|
|
8854
|
-
const { apolloRowHeight, contextMenuItems: getContextMenuItems, cursor, featuresHeight, isShown, onMouseDown, onMouseLeave, onMouseMove, onMouseUp, regionCannotBeRendered, session, setCanvas, setCollaboratorCanvas, setOverlayCanvas, setSeqTrackCanvas, setSeqTrackOverlayCanvas, setTheme, } = model;
|
|
8941
|
+
const { loading, apolloRowHeight, contextMenuItems: getContextMenuItems, cursor, featuresHeight, isShown, onMouseDown, onMouseLeave, onMouseMove, onMouseUp, regionCannotBeRendered, session, setCanvas, setCollaboratorCanvas, setOverlayCanvas, setSeqTrackCanvas, setSeqTrackOverlayCanvas, setTheme, } = model;
|
|
8855
8942
|
const { classes } = useStyles$1();
|
|
8856
8943
|
const lgv = util.getContainingView(model);
|
|
8857
8944
|
React.useEffect(() => {
|
|
@@ -8891,65 +8978,68 @@ const LinearApolloDisplay = mobxReact.observer(function LinearApolloDisplay(prop
|
|
|
8891
8978
|
setContextCoord(coord);
|
|
8892
8979
|
setContextMenuItems(getContextMenuItems(coord));
|
|
8893
8980
|
}
|
|
8894
|
-
} },
|
|
8895
|
-
React__default["default"].createElement(
|
|
8896
|
-
React__default["default"].createElement("
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
assembly.
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
}, TransitionProps: {
|
|
8947
|
-
onExit: () => {
|
|
8981
|
+
} },
|
|
8982
|
+
loading ? (React__default["default"].createElement("div", { className: classes.loading },
|
|
8983
|
+
React__default["default"].createElement(material.CircularProgress, { size: "18px" }))) : null,
|
|
8984
|
+
message ? (React__default["default"].createElement(material.Alert, { severity: "warning", classes: { message: classes.ellipses } },
|
|
8985
|
+
React__default["default"].createElement(material.Tooltip, { title: message },
|
|
8986
|
+
React__default["default"].createElement("div", null, message)))) : (
|
|
8987
|
+
// Promise.resolve() in these 3 callbacks is to avoid infinite rendering loop
|
|
8988
|
+
// https://github.com/mobxjs/mobx/issues/3728#issuecomment-1715400931
|
|
8989
|
+
React__default["default"].createElement(React__default["default"].Fragment, null,
|
|
8990
|
+
React__default["default"].createElement("canvas", { ref: async (node) => {
|
|
8991
|
+
await Promise.resolve();
|
|
8992
|
+
setCollaboratorCanvas(node);
|
|
8993
|
+
}, width: lgv.dynamicBlocks.totalWidthPx, height: featuresHeight, className: classes.canvas, "data-testid": "collaboratorCanvas" }),
|
|
8994
|
+
React__default["default"].createElement("canvas", { ref: async (node) => {
|
|
8995
|
+
await Promise.resolve();
|
|
8996
|
+
setCanvas(node);
|
|
8997
|
+
}, width: lgv.dynamicBlocks.totalWidthPx, height: featuresHeight, className: classes.canvas, "data-testid": "canvas" }),
|
|
8998
|
+
React__default["default"].createElement("canvas", { ref: async (node) => {
|
|
8999
|
+
await Promise.resolve();
|
|
9000
|
+
setOverlayCanvas(node);
|
|
9001
|
+
}, width: lgv.dynamicBlocks.totalWidthPx, height: featuresHeight, onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, className: classes.canvas, style: { cursor: cursor ?? 'default' }, "data-testid": "overlayCanvas" }),
|
|
9002
|
+
lgv.displayedRegions.flatMap((region, idx) => {
|
|
9003
|
+
const assembly = assemblyManager.get(region.assemblyName);
|
|
9004
|
+
return [...session.apolloDataStore.checkResults.values()]
|
|
9005
|
+
.filter((checkResult) => assembly?.isValidRefName(checkResult.refSeq) &&
|
|
9006
|
+
assembly.getCanonicalRefName(checkResult.refSeq) ===
|
|
9007
|
+
region.refName &&
|
|
9008
|
+
util.doesIntersect2(region.start, region.end, checkResult.start, checkResult.end))
|
|
9009
|
+
.map((checkResult) => {
|
|
9010
|
+
const left = (lgv.bpToPx({
|
|
9011
|
+
refName: region.refName,
|
|
9012
|
+
coord: checkResult.start,
|
|
9013
|
+
regionNumber: idx,
|
|
9014
|
+
})?.offsetPx ?? 0) - lgv.offsetPx;
|
|
9015
|
+
const [feature] = checkResult.ids;
|
|
9016
|
+
if (!feature) {
|
|
9017
|
+
return null;
|
|
9018
|
+
}
|
|
9019
|
+
const { topLevelFeature } = feature;
|
|
9020
|
+
const row = parent
|
|
9021
|
+
? model.getFeatureLayoutPosition(topLevelFeature)
|
|
9022
|
+
?.layoutRow ?? 0
|
|
9023
|
+
: 0;
|
|
9024
|
+
const top = row * apolloRowHeight;
|
|
9025
|
+
const height = apolloRowHeight;
|
|
9026
|
+
return (React__default["default"].createElement(material.Tooltip, { key: checkResult._id, title: checkResult.message },
|
|
9027
|
+
React__default["default"].createElement(material.Avatar, { className: classes.avatar, style: { top, left, height, width: height } },
|
|
9028
|
+
React__default["default"].createElement(ErrorIcon__default["default"], null))));
|
|
9029
|
+
});
|
|
9030
|
+
}),
|
|
9031
|
+
React__default["default"].createElement(ui.Menu, { open: contextMenuItems.length > 0, onMenuItemClick: (_, callback) => {
|
|
9032
|
+
callback();
|
|
8948
9033
|
setContextMenuItems([]);
|
|
8949
|
-
},
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
9034
|
+
}, onClose: () => {
|
|
9035
|
+
setContextMenuItems([]);
|
|
9036
|
+
}, TransitionProps: {
|
|
9037
|
+
onExit: () => {
|
|
9038
|
+
setContextMenuItems([]);
|
|
9039
|
+
},
|
|
9040
|
+
}, anchorReference: "anchorPosition", anchorPosition: contextCoord
|
|
9041
|
+
? { top: contextCoord[1], left: contextCoord[0] }
|
|
9042
|
+
: undefined, style: { zIndex: theme.zIndex.tooltip }, menuItems: contextMenuItems }))))));
|
|
8953
9043
|
});
|
|
8954
9044
|
|
|
8955
9045
|
const TrackLines = mobxReact.observer(function TrackLines({ model, }) {
|