jbrowse-plugin-mafviewer 1.0.2 → 1.0.3
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/jbrowse-plugin-mafviewer.umd.development.js +200 -97
- package/dist/jbrowse-plugin-mafviewer.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +1 -1
- package/package.json +1 -1
- package/src/LinearMafDisplay/components/ColorLegend.tsx +25 -28
- package/src/LinearMafDisplay/components/SetRowHeight.tsx +76 -0
- package/src/LinearMafDisplay/components/YScaleBars.tsx +1 -1
- package/src/LinearMafDisplay/configSchema.ts +2 -3
- package/src/LinearMafDisplay/renderSvg.tsx +13 -4
- package/src/LinearMafDisplay/stateModel.ts +50 -12
- package/src/LinearMafRenderer/LinearMafRenderer.ts +98 -43
- package/src/MafTabixAdapter/MafTabixAdapter.ts +19 -17
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jbrowse/core/Plugin'), require('@jbrowse/core/pluggableElementTypes'), require('@jbrowse/core/configuration'), require('@jbrowse/core/data_adapters/BaseAdapter'), require('mobx-state-tree'), require('@jbrowse/core/util'), require('@jbrowse/core/util/rxjs'), require('react'), require('mobx-react'), require('@
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', '@jbrowse/core/Plugin', '@jbrowse/core/pluggableElementTypes', '@jbrowse/core/configuration', '@jbrowse/core/data_adapters/BaseAdapter', 'mobx-state-tree', '@jbrowse/core/util', '@jbrowse/core/util/rxjs', 'react', 'mobx-react', '@
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JBrowsePluginMafViewer = {}, global.JBrowseExports["@jbrowse/core/Plugin"], global.JBrowseExports["@jbrowse/core/pluggableElementTypes"], global.JBrowseExports["@jbrowse/core/configuration"], global.JBrowseExports["@jbrowse/core/data_adapters/BaseAdapter"], global.JBrowseExports["mobx-state-tree"], global.JBrowseExports["@jbrowse/core/util"], global.JBrowseExports["@jbrowse/core/util/rxjs"], global.JBrowseExports.react, global.JBrowseExports["mobx-react"], global.JBrowseExports["@
|
|
5
|
-
})(this, (function (exports, Plugin, pluggableElementTypes, configuration, BaseAdapter, mobxStateTree, util, rxjs, React, mobxReact,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jbrowse/core/Plugin'), require('@jbrowse/core/pluggableElementTypes'), require('@jbrowse/core/configuration'), require('@jbrowse/core/data_adapters/BaseAdapter'), require('mobx-state-tree'), require('@jbrowse/core/util'), require('@jbrowse/core/util/rxjs'), require('react'), require('mobx-react'), require('@mui/material'), require('@jbrowse/core/ui'), require('tss-react/mui')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', '@jbrowse/core/Plugin', '@jbrowse/core/pluggableElementTypes', '@jbrowse/core/configuration', '@jbrowse/core/data_adapters/BaseAdapter', 'mobx-state-tree', '@jbrowse/core/util', '@jbrowse/core/util/rxjs', 'react', 'mobx-react', '@mui/material', '@jbrowse/core/ui', 'tss-react/mui'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JBrowsePluginMafViewer = {}, global.JBrowseExports["@jbrowse/core/Plugin"], global.JBrowseExports["@jbrowse/core/pluggableElementTypes"], global.JBrowseExports["@jbrowse/core/configuration"], global.JBrowseExports["@jbrowse/core/data_adapters/BaseAdapter"], global.JBrowseExports["mobx-state-tree"], global.JBrowseExports["@jbrowse/core/util"], global.JBrowseExports["@jbrowse/core/util/rxjs"], global.JBrowseExports.react, global.JBrowseExports["mobx-react"], global.JBrowseExports["@mui/material"], global.JBrowseExports["@jbrowse/core/ui"], global.JBrowseExports["tss-react/mui"]));
|
|
5
|
+
})(this, (function (exports, Plugin, pluggableElementTypes, configuration, BaseAdapter, mobxStateTree, util, rxjs, React, mobxReact, material, ui, mui) { 'use strict';
|
|
6
6
|
|
|
7
|
-
var version = "1.0.
|
|
7
|
+
var version = "1.0.3";
|
|
8
8
|
|
|
9
9
|
const configSchema$2 = configuration.ConfigurationSchema('BigMafAdapter', {
|
|
10
10
|
/**
|
|
@@ -738,19 +738,42 @@
|
|
|
738
738
|
|
|
739
739
|
function configSchemaF(pluginManager) {
|
|
740
740
|
const LinearGenomePlugin = pluginManager.getPlugin('LinearGenomeViewPlugin');
|
|
741
|
-
|
|
742
|
-
const { linearBasicDisplayConfigSchemaFactory } = LinearGenomePlugin.exports;
|
|
741
|
+
const { baseLinearDisplayConfigSchema } = LinearGenomePlugin.exports;
|
|
743
742
|
return configuration.ConfigurationSchema('LinearMafDisplay', {
|
|
744
743
|
/**
|
|
745
744
|
* #slot
|
|
746
745
|
*/
|
|
747
746
|
renderer: pluginManager.pluggableConfigSchemaType('renderer'),
|
|
748
747
|
}, {
|
|
749
|
-
baseConfiguration:
|
|
748
|
+
baseConfiguration: baseLinearDisplayConfigSchema,
|
|
750
749
|
explicitlyTyped: true,
|
|
751
750
|
});
|
|
752
751
|
}
|
|
753
752
|
|
|
753
|
+
const useStyles$1 = mui.makeStyles()({
|
|
754
|
+
root: {
|
|
755
|
+
width: 500,
|
|
756
|
+
},
|
|
757
|
+
});
|
|
758
|
+
const SetRowHeightDialog = mobxReact.observer(function (props) {
|
|
759
|
+
const { model, handleClose } = props;
|
|
760
|
+
const { classes } = useStyles$1();
|
|
761
|
+
const [rowHeight, setRowHeight] = React.useState(`${model.rowHeight}`);
|
|
762
|
+
const [rowProportion, setRowProportion] = React.useState(`${model.rowProportion}`);
|
|
763
|
+
return (React.createElement(ui.Dialog, { open: true, onClose: handleClose, title: "Filter options" },
|
|
764
|
+
React.createElement(material.DialogContent, { className: classes.root },
|
|
765
|
+
React.createElement(material.Typography, null, "Set row height and the proportion of the row height to use for drawing each row"),
|
|
766
|
+
React.createElement(material.TextField, { value: rowHeight, onChange: event => setRowHeight(event.target.value), placeholder: "Enter row height" }),
|
|
767
|
+
React.createElement(material.TextField, { value: rowProportion, onChange: event => setRowProportion(event.target.value), placeholder: "Enter row proportion" }),
|
|
768
|
+
React.createElement(material.DialogActions, null,
|
|
769
|
+
React.createElement(material.Button, { variant: "contained", color: "primary", type: "submit", autoFocus: true, onClick: () => {
|
|
770
|
+
model.setRowProportion(+rowProportion);
|
|
771
|
+
model.setRowHeight(+rowHeight);
|
|
772
|
+
handleClose();
|
|
773
|
+
} }, "Submit"),
|
|
774
|
+
React.createElement(material.Button, { variant: "contained", color: "secondary", onClick: () => handleClose() }, "Cancel")))));
|
|
775
|
+
});
|
|
776
|
+
|
|
754
777
|
function isStrs(array) {
|
|
755
778
|
return typeof array[0] === 'string';
|
|
756
779
|
}
|
|
@@ -760,10 +783,9 @@
|
|
|
760
783
|
*/
|
|
761
784
|
function stateModelFactory(configSchema, pluginManager) {
|
|
762
785
|
const LinearGenomePlugin = pluginManager.getPlugin('LinearGenomeViewPlugin');
|
|
763
|
-
|
|
764
|
-
const { linearBasicDisplayModelFactory } = LinearGenomePlugin.exports;
|
|
786
|
+
const { BaseLinearDisplay } = LinearGenomePlugin.exports;
|
|
765
787
|
return mobxStateTree.types
|
|
766
|
-
.compose('LinearMafDisplay',
|
|
788
|
+
.compose('LinearMafDisplay', BaseLinearDisplay, mobxStateTree.types.model({
|
|
767
789
|
/**
|
|
768
790
|
* #property
|
|
769
791
|
*/
|
|
@@ -772,9 +794,31 @@
|
|
|
772
794
|
* #property
|
|
773
795
|
*/
|
|
774
796
|
configuration: configuration.ConfigurationReference(configSchema),
|
|
797
|
+
/**
|
|
798
|
+
* #property
|
|
799
|
+
*/
|
|
800
|
+
rowHeight: 15,
|
|
801
|
+
/**
|
|
802
|
+
* #property
|
|
803
|
+
*/
|
|
804
|
+
rowProportion: 0.8,
|
|
775
805
|
}))
|
|
776
806
|
.volatile(() => ({
|
|
777
807
|
prefersOffset: true,
|
|
808
|
+
}))
|
|
809
|
+
.actions(self => ({
|
|
810
|
+
/**
|
|
811
|
+
* #action
|
|
812
|
+
*/
|
|
813
|
+
setRowHeight(n) {
|
|
814
|
+
self.rowHeight = n;
|
|
815
|
+
},
|
|
816
|
+
/**
|
|
817
|
+
* #action
|
|
818
|
+
*/
|
|
819
|
+
setRowProportion(n) {
|
|
820
|
+
self.rowProportion = n;
|
|
821
|
+
},
|
|
778
822
|
}))
|
|
779
823
|
.views(self => ({
|
|
780
824
|
/**
|
|
@@ -789,12 +833,6 @@
|
|
|
789
833
|
return r;
|
|
790
834
|
}
|
|
791
835
|
},
|
|
792
|
-
/**
|
|
793
|
-
* #getter
|
|
794
|
-
*/
|
|
795
|
-
get rowHeight() {
|
|
796
|
-
return 20;
|
|
797
|
-
},
|
|
798
836
|
/**
|
|
799
837
|
* #getter
|
|
800
838
|
*/
|
|
@@ -814,7 +852,7 @@
|
|
|
814
852
|
},
|
|
815
853
|
}))
|
|
816
854
|
.views(self => {
|
|
817
|
-
const { renderProps: superRenderProps } = self;
|
|
855
|
+
const { trackMenuItems: superTrackMenuItems, renderProps: superRenderProps, } = self;
|
|
818
856
|
return {
|
|
819
857
|
/**
|
|
820
858
|
* #method
|
|
@@ -822,10 +860,29 @@
|
|
|
822
860
|
renderProps() {
|
|
823
861
|
return {
|
|
824
862
|
...superRenderProps(),
|
|
863
|
+
config: self.rendererConfig,
|
|
825
864
|
samples: self.samples,
|
|
826
865
|
rowHeight: self.rowHeight,
|
|
866
|
+
rowProportion: self.rowProportion,
|
|
827
867
|
};
|
|
828
868
|
},
|
|
869
|
+
/**
|
|
870
|
+
* #method
|
|
871
|
+
*/
|
|
872
|
+
trackMenuItems() {
|
|
873
|
+
return [
|
|
874
|
+
...superTrackMenuItems(),
|
|
875
|
+
{
|
|
876
|
+
label: 'Set row height',
|
|
877
|
+
onClick: () => {
|
|
878
|
+
util.getSession(self).queueDialog(handleClose => [
|
|
879
|
+
SetRowHeightDialog,
|
|
880
|
+
{ model: self, handleClose },
|
|
881
|
+
]);
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
];
|
|
885
|
+
},
|
|
829
886
|
};
|
|
830
887
|
})
|
|
831
888
|
.actions(self => {
|
|
@@ -836,7 +893,6 @@
|
|
|
836
893
|
*/
|
|
837
894
|
async renderSvg(opts) {
|
|
838
895
|
const { renderSvg } = await Promise.resolve().then(function () { return renderSvg$1; });
|
|
839
|
-
// @ts-expect-error
|
|
840
896
|
return renderSvg(self, opts, superRenderSvg);
|
|
841
897
|
},
|
|
842
898
|
};
|
|
@@ -850,17 +906,14 @@
|
|
|
850
906
|
|
|
851
907
|
const ColorLegend = mobxReact.observer(function ({ model, labelWidth, }) {
|
|
852
908
|
const { samples, rowHeight } = model;
|
|
853
|
-
const svgFontSize = Math.min(rowHeight,
|
|
854
|
-
const canDisplayLabel = rowHeight
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
React.createElement(RectBg, { y: idx * rowHeight + 1, x: extraOffset, width: legendWidth, height: boxHeight, color: sample.color }),
|
|
862
|
-
canDisplayLabel ? (React.createElement("text", { y: idx * rowHeight + 14, x: extraOffset + colorBoxWidth + 2, fontSize: svgFontSize }, sample.label)) : null));
|
|
863
|
-
}))) : null;
|
|
909
|
+
const svgFontSize = Math.min(rowHeight, 10);
|
|
910
|
+
const canDisplayLabel = rowHeight >= 10;
|
|
911
|
+
const boxHeight = Math.min(20, rowHeight);
|
|
912
|
+
return samples ? (React.createElement(React.Fragment, null,
|
|
913
|
+
samples.map((sample, idx) => (React.createElement(RectBg, { key: `${sample.id}-${idx}`, y: idx * rowHeight + 1, x: 0, width: labelWidth + 5, height: boxHeight, color: sample.color }))),
|
|
914
|
+
canDisplayLabel
|
|
915
|
+
? samples.map((sample, idx) => (React.createElement("text", { key: `${sample.id}-${idx}`, y: idx * rowHeight + 14, x: 2, fontSize: svgFontSize }, sample.label)))
|
|
916
|
+
: null)) : null;
|
|
864
917
|
});
|
|
865
918
|
|
|
866
919
|
const Wrapper = mobxReact.observer(function ({ children, model, exportSVG, }) {
|
|
@@ -883,7 +936,7 @@
|
|
|
883
936
|
const { model } = props;
|
|
884
937
|
const { rowHeight, samples } = model;
|
|
885
938
|
const svgFontSize = Math.min(rowHeight, 12);
|
|
886
|
-
const canDisplayLabel = rowHeight
|
|
939
|
+
const canDisplayLabel = rowHeight >= 10;
|
|
887
940
|
const minWidth = 20;
|
|
888
941
|
const labelWidth = Math.max(...(samples
|
|
889
942
|
.map(s => util.measureText(s.label, svgFontSize))
|
|
@@ -925,20 +978,6 @@
|
|
|
925
978
|
explicitlyTyped: true,
|
|
926
979
|
});
|
|
927
980
|
|
|
928
|
-
function getCorrectionFactor(scale) {
|
|
929
|
-
if (scale >= 1) {
|
|
930
|
-
return 0.6;
|
|
931
|
-
}
|
|
932
|
-
else if (scale >= 0.2) {
|
|
933
|
-
return 0.05;
|
|
934
|
-
}
|
|
935
|
-
else if (scale >= 0.02) {
|
|
936
|
-
return 0.03;
|
|
937
|
-
}
|
|
938
|
-
else {
|
|
939
|
-
return 0.02;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
981
|
function getContrastBaseMap(theme) {
|
|
943
982
|
return Object.fromEntries(Object.entries(getColorBaseMap(theme)).map(([key, value]) => [
|
|
944
983
|
key,
|
|
@@ -955,7 +994,7 @@
|
|
|
955
994
|
};
|
|
956
995
|
}
|
|
957
996
|
function makeImageData({ ctx, renderArgs, }) {
|
|
958
|
-
const { regions, bpPerPx, rowHeight, theme: configTheme, samples, } = renderArgs;
|
|
997
|
+
const { regions, bpPerPx, rowHeight, theme: configTheme, samples, rowProportion, } = renderArgs;
|
|
959
998
|
const [region] = regions;
|
|
960
999
|
const features = renderArgs.features;
|
|
961
1000
|
const h = rowHeight;
|
|
@@ -964,7 +1003,9 @@
|
|
|
964
1003
|
const contrastForBase = getContrastBaseMap(theme);
|
|
965
1004
|
const sampleToRowMap = new Map(samples.map((s, i) => [s.id, i]));
|
|
966
1005
|
const scale = 1 / bpPerPx;
|
|
967
|
-
const
|
|
1006
|
+
const f = 0.4;
|
|
1007
|
+
const h2 = h * rowProportion;
|
|
1008
|
+
const offset = h2 / 2;
|
|
968
1009
|
// sample as alignments
|
|
969
1010
|
ctx.font = 'bold 10px Courier New,monospace';
|
|
970
1011
|
for (const feature of features.values()) {
|
|
@@ -974,63 +1015,117 @@
|
|
|
974
1015
|
for (const [sample, val] of Object.entries(vals)) {
|
|
975
1016
|
const origAlignment = val.data;
|
|
976
1017
|
const alignment = origAlignment.toLowerCase();
|
|
977
|
-
// gaps
|
|
978
|
-
ctx.beginPath();
|
|
979
|
-
ctx.fillStyle = 'black';
|
|
980
|
-
const offset0 = (5 / 12) * h;
|
|
981
|
-
const h6 = h / 6;
|
|
982
1018
|
const row = sampleToRowMap.get(sample);
|
|
983
1019
|
if (row === undefined) {
|
|
984
1020
|
throw new Error(`unknown sample encountered: ${sample}`);
|
|
985
1021
|
}
|
|
986
1022
|
const t = h * row;
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1023
|
+
// gaps
|
|
1024
|
+
ctx.beginPath();
|
|
1025
|
+
ctx.fillStyle = 'black';
|
|
1026
|
+
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
1027
|
+
if (seq[i] !== '-') {
|
|
1028
|
+
if (alignment[i] === '-') {
|
|
1029
|
+
const l = leftPx + scale * o;
|
|
1030
|
+
ctx.moveTo(l, t + h2);
|
|
1031
|
+
ctx.lineTo(l + scale + f, t + h2);
|
|
1032
|
+
}
|
|
1033
|
+
o++;
|
|
991
1034
|
}
|
|
992
1035
|
}
|
|
993
|
-
ctx.
|
|
994
|
-
const offset = (1 / 4) * h;
|
|
995
|
-
const h2 = h / 2;
|
|
1036
|
+
ctx.stroke();
|
|
996
1037
|
// matches
|
|
997
1038
|
ctx.beginPath();
|
|
998
1039
|
ctx.fillStyle = 'lightgrey';
|
|
999
|
-
for (let i = 0; i < alignment.length; i++) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1040
|
+
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
1041
|
+
if (seq[i] !== '-') {
|
|
1042
|
+
const c = alignment[i];
|
|
1043
|
+
const l = leftPx + scale * o;
|
|
1044
|
+
if (seq[i] === c && c !== '-') {
|
|
1045
|
+
ctx.rect(l, offset + t, scale + f, h2);
|
|
1046
|
+
}
|
|
1047
|
+
o++;
|
|
1004
1048
|
}
|
|
1005
1049
|
}
|
|
1006
1050
|
ctx.fill();
|
|
1007
1051
|
// mismatches
|
|
1008
|
-
for (let i = 0; i < alignment.length; i++) {
|
|
1052
|
+
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
1009
1053
|
const c = alignment[i];
|
|
1010
|
-
if (seq[i] !==
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1054
|
+
if (seq[i] !== '-') {
|
|
1055
|
+
if (seq[i] !== c && c !== '-') {
|
|
1056
|
+
const l = leftPx + scale * o;
|
|
1057
|
+
ctx.fillStyle =
|
|
1058
|
+
colorForBase[c] ?? 'purple';
|
|
1059
|
+
ctx.fillRect(l, offset + t, scale + f, h2);
|
|
1060
|
+
}
|
|
1061
|
+
o++;
|
|
1015
1062
|
}
|
|
1016
1063
|
}
|
|
1017
1064
|
// font
|
|
1018
1065
|
const charSize = { w: 10 };
|
|
1019
1066
|
if (scale >= charSize.w) {
|
|
1020
|
-
for (let i = 0; i < alignment.length; i++) {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1067
|
+
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
1068
|
+
if (seq[i] !== '-') {
|
|
1069
|
+
const l = leftPx + scale * o;
|
|
1070
|
+
const offset = (scale - charSize.w) / 2 + 1;
|
|
1071
|
+
const c = alignment[i];
|
|
1072
|
+
if (seq[i] !== c && c !== '-') {
|
|
1073
|
+
ctx.fillStyle = contrastForBase[c] ?? 'black';
|
|
1074
|
+
ctx.fillText(origAlignment[i], l + offset, h2 + t + 3);
|
|
1075
|
+
}
|
|
1076
|
+
o++;
|
|
1027
1077
|
}
|
|
1028
1078
|
}
|
|
1029
1079
|
}
|
|
1030
1080
|
}
|
|
1031
1081
|
}
|
|
1082
|
+
// second pass for insertions, has slightly improved look since the
|
|
1083
|
+
// insertions are always 'on top' of the other features
|
|
1084
|
+
for (const feature of features.values()) {
|
|
1085
|
+
const [leftPx] = util.featureSpanPx(feature, region, bpPerPx);
|
|
1086
|
+
const vals = feature.get('alignments');
|
|
1087
|
+
const seq = feature.get('seq').toLowerCase();
|
|
1088
|
+
for (const [sample, val] of Object.entries(vals)) {
|
|
1089
|
+
const origAlignment = val.data;
|
|
1090
|
+
const alignment = origAlignment.toLowerCase();
|
|
1091
|
+
const row = sampleToRowMap.get(sample);
|
|
1092
|
+
if (row === undefined) {
|
|
1093
|
+
throw new Error(`unknown sample encountered: ${sample}`);
|
|
1094
|
+
}
|
|
1095
|
+
const t = h * row;
|
|
1096
|
+
ctx.beginPath();
|
|
1097
|
+
ctx.fillStyle = 'purple';
|
|
1098
|
+
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
1099
|
+
let ins = '';
|
|
1100
|
+
while (seq[i] === '-') {
|
|
1101
|
+
if (alignment[i] !== '-') {
|
|
1102
|
+
ins += alignment[i];
|
|
1103
|
+
}
|
|
1104
|
+
i++;
|
|
1105
|
+
}
|
|
1106
|
+
if (ins.length) {
|
|
1107
|
+
const l = leftPx + scale * o - 2;
|
|
1108
|
+
ctx.rect(l, offset + t, 2, h2);
|
|
1109
|
+
ctx.rect(l - 2, offset + t, 6, 1);
|
|
1110
|
+
ctx.rect(l - 2, offset + t + h2, 6, 1);
|
|
1111
|
+
}
|
|
1112
|
+
o++;
|
|
1113
|
+
}
|
|
1114
|
+
ctx.fill();
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1032
1117
|
}
|
|
1033
1118
|
class LinearMafRenderer extends pluggableElementTypes.FeatureRendererType {
|
|
1119
|
+
getExpandedRegion(region) {
|
|
1120
|
+
const { start, end } = region;
|
|
1121
|
+
const bpExpansion = 1;
|
|
1122
|
+
return {
|
|
1123
|
+
// xref https://github.com/mobxjs/mobx-state-tree/issues/1524 for Omit
|
|
1124
|
+
...region,
|
|
1125
|
+
start: Math.floor(Math.max(start - bpExpansion, 0)),
|
|
1126
|
+
end: Math.ceil(end + bpExpansion),
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1034
1129
|
async render(renderProps) {
|
|
1035
1130
|
const { regions, bpPerPx, samples, rowHeight } = renderProps;
|
|
1036
1131
|
const [region] = regions;
|
|
@@ -1133,6 +1228,10 @@
|
|
|
1133
1228
|
const { adapter } = await this.setup();
|
|
1134
1229
|
return adapter.getRefNames();
|
|
1135
1230
|
}
|
|
1231
|
+
async getHeader() {
|
|
1232
|
+
const { adapter } = await this.setup();
|
|
1233
|
+
return adapter.getHeader();
|
|
1234
|
+
}
|
|
1136
1235
|
getFeatures(query) {
|
|
1137
1236
|
return rxjs.ObservableCreate(async (observer) => {
|
|
1138
1237
|
const { adapter } = await this.setup();
|
|
@@ -1140,31 +1239,29 @@
|
|
|
1140
1239
|
for (const feature of features) {
|
|
1141
1240
|
const data = feature.get('field5').split(',');
|
|
1142
1241
|
const alignments = {};
|
|
1143
|
-
const main = data[0];
|
|
1144
|
-
const aln = main.split(':')[5];
|
|
1145
1242
|
const alns = data.map(elt => elt.split(':')[5]);
|
|
1146
|
-
const
|
|
1243
|
+
// const aln = alns[0]
|
|
1244
|
+
// const alns2 = data.map(() => '')
|
|
1147
1245
|
// remove extraneous data in other alignments
|
|
1148
1246
|
// reason being: cannot represent missing data in main species that are in others)
|
|
1149
|
-
for (let i = 0
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1247
|
+
// for (let i = 0; i < aln.length; i++) {
|
|
1248
|
+
// if (aln[i] !== '-') {
|
|
1249
|
+
// for (let j = 0; j < data.length; j++) {
|
|
1250
|
+
// alns2[j] += alns[j][i]
|
|
1251
|
+
// }
|
|
1252
|
+
// }
|
|
1253
|
+
// }
|
|
1156
1254
|
for (let j = 0; j < data.length; j++) {
|
|
1157
1255
|
const elt = data[j];
|
|
1158
1256
|
const ad = elt.split(':');
|
|
1159
|
-
const org = ad[0].split('.')
|
|
1160
|
-
const chr = ad[0].split('.')[1];
|
|
1257
|
+
const [org, chr] = ad[0].split('.');
|
|
1161
1258
|
alignments[org] = {
|
|
1162
|
-
chr
|
|
1259
|
+
chr,
|
|
1163
1260
|
start: +ad[1],
|
|
1164
1261
|
srcSize: +ad[2],
|
|
1165
1262
|
strand: ad[3] === '-' ? -1 : 1,
|
|
1166
1263
|
unknown: +ad[4],
|
|
1167
|
-
data:
|
|
1264
|
+
data: alns[j],
|
|
1168
1265
|
};
|
|
1169
1266
|
}
|
|
1170
1267
|
observer.next(new util.SimpleFeature({
|
|
@@ -1175,8 +1272,8 @@
|
|
|
1175
1272
|
refName: feature.get('refName'),
|
|
1176
1273
|
name: feature.get('name'),
|
|
1177
1274
|
score: feature.get('score'),
|
|
1178
|
-
alignments
|
|
1179
|
-
seq:
|
|
1275
|
+
alignments,
|
|
1276
|
+
seq: alns[0],
|
|
1180
1277
|
},
|
|
1181
1278
|
}));
|
|
1182
1279
|
}
|
|
@@ -1299,11 +1396,17 @@
|
|
|
1299
1396
|
}
|
|
1300
1397
|
|
|
1301
1398
|
async function renderSvg(self, opts, superRenderSvg) {
|
|
1302
|
-
const {
|
|
1399
|
+
const { height } = self;
|
|
1400
|
+
const { offsetPx, width } = util.getContainingView(self);
|
|
1401
|
+
const clipid = `mafclip-${self.id}`;
|
|
1303
1402
|
return (React.createElement(React.Fragment, null,
|
|
1304
|
-
React.createElement("
|
|
1305
|
-
|
|
1306
|
-
|
|
1403
|
+
React.createElement("defs", null,
|
|
1404
|
+
React.createElement("clipPath", { id: clipid },
|
|
1405
|
+
React.createElement("rect", { x: 0, y: 0, width: width, height: height }))),
|
|
1406
|
+
React.createElement("g", { clipPath: `url(#${clipid})` },
|
|
1407
|
+
React.createElement("g", { id: "snpcov" }, await superRenderSvg(opts)),
|
|
1408
|
+
React.createElement("g", { transform: `translate(${Math.max(-offsetPx, 0)})` },
|
|
1409
|
+
React.createElement(YScaleBars, { model: self, orientation: "left", exportSVG: true })))));
|
|
1307
1410
|
}
|
|
1308
1411
|
|
|
1309
1412
|
var renderSvg$1 = {
|